Reputation: 5412
I am using a useEffect to fetch information from my backend api. I am using Redux and I dispatch action on useeffect. At first, It works but after page reloads all information become null and i get this error TypeError: Cannot read property 'mainImage' of null. In redux dev tools, it doesnot even call the action and my redux store state it is null. What could be possible error? My other components are working fine , even after reloading page and I am using same method in other components also. I have even checked if my response data are loading or not. I even console.log('HI') in useeffect and it doesnot show
Here is my that component
const ProductDetailScreen = ({match,history}) => {
const dispatch = useDispatch();
const {loading,product,error}= useSelector(state=> state.singleProduct)
useEffect(()=>{
dispatch(getProductDetails(match.params.id))
},[dispatch,match])
return (
<div className='my-5 p-3'>
<Button variant="outline-dark" onClick={()=> history.push('/')}>
<i className="fas fa-arrow-left"></i> Go Back
</Button>
{loading ? <Loader/> : error? <AlertMessage>{error}</AlertMessage>:
(
<>
<Row className='my-4'>
<Col md={4}>
<Image style={{width:'90%',height:'auto'}} alt='' fluid src={product.mainImage}/>
</Col>
<Col md={4}>
<ListGroup variant='flush'>
<ListGroup.Item>
<h3>{product.name}</h3>
</ListGroup.Item>
<ListGroup.Item>
<Rating value={product.ratings} text={`${product.numReviews} reviews`}/>
</ListGroup.Item>
<ListGroup.Item>
Quantity: {product.quantity}
</ListGroup.Item>
<ListGroup.Item>
Buyers: {product.sale}
</ListGroup.Item>
<ListGroup.Item>
<h5>Choose Version :</h5>
<ListGroup horizontal>
<Row>
{product.version.map(pro=>(
<Col key={pro._id} className='my-2 d-flex align-items-stretch' md={6}>
<ListGroup.Item>
<Form.Check defaultChecked type="radio" inline name="group1" aria-label="radio 1" />
<h6>Version: {pro.version}</h6>
<h6>Price: ${pro.price} </h6>
</ListGroup.Item>
</Col>
))}
</Row>
</ListGroup>
</ListGroup.Item>
</ListGroup>
</Col>
</Row>
</>
export default ProductDetailScreen
My reducer
export const getProductFromID = (state={product:null},action)=>{
switch(action.type){
default:
return state
case GET_PRODUCT_REQUEST:
return {loading:true}
case GET_PRODUCT_SUCCESS:
return{loading:false, product:action.payload}
case GET_PRODUCT_FAIL:
return {loading:false,error:action.payload}
}
}
My store
const rootReducer= combineReducers({
productsReducer: getProductsReducer,
topProducts: getTopProductReducer,
categories: getCategoriesReducer,
productCategories : getProductFromCategories,
singleProduct: getProductFromID
})
const initialState ={};
const middleWare = [thunk];
const store = createStore(rootReducer,initialState, composeWithDevTools(applyMiddleware(...middleWare)))
export default store
My action creator
export const getProductDetails = (id) => async (dispatch) => {
try {
dispatch({
type: GET_PRODUCT_REQUEST
})
const res = await axios.get(`/api/products/${id}`)
dispatch({
type: GET_PRODUCT_SUCCESS,
payload: res.data
})
} catch (error) {
dispatch({
type: GET_PRODUCT_FAIL,
payload: error.response && error.response.data.message ? error.response.data.message : error.message
})
}
}
There is nothing wrong in my backend api , It works correctly in postman
Upvotes: 0
Views: 1265
Reputation: 281950
When you reload your page, your redux state is reset and hence during the first render, your product value is null and you are trying to access mainImage
from product which breaks the flow of the page.
To solve this, set the initial state in your reducer to have loading as true
export const getProductFromID = (state={product:null, loading: true},action)=>{
switch(action.type){
default:
return state
case GET_PRODUCT_REQUEST:
return {loading:true}
case GET_PRODUCT_SUCCESS:
return{loading:false, product:action.payload}
case GET_PRODUCT_FAIL:
return {loading:false,error:action.payload}
}
}
Upvotes: 0