Saral Karki
Saral Karki

Reputation: 5412

React UseEffect not working on page refresh

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

Answers (1)

Shubham Khatri
Shubham Khatri

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

Related Questions