Aidenhsy
Aidenhsy

Reputation: 1641

React-Redux useSelector has trouble passing data

I am using React with Redux. The Redux devtool console shows that data exists in the state (redux devtools console), but the webpage displays an error saying that the object is undefined (error).

This is my code for my screen:

import React, { useEffect } from "react";

import { useSelector, useDispatch } from "react-redux";
import { listProductDetails } from "../redux/actions/productActions";

const ProductScreen = ({ match }) => {
  const dispatch = useDispatch();
  const productDetails = useSelector((state) => state.productDetails);
  const { loading, error, product } = productDetails;
  useEffect(() => {
    dispatch(listProductDetails(match.params.id));
  }, [dispatch, match]);
  return <div>{product.name}</div>;
};

export default ProductScreen;

This is the code for my redux reducer:

import {
  PRODUCT_DETAILS_FAIL,
  PRODUCT_DETAILS_REQUEST,
  PRODUCT_DETAILS_SUCCESS,
} from "../constants";

export const productDetailsReducer = (state = { product: {} }, action) => {
  switch (action.type) {
    case PRODUCT_DETAILS_REQUEST:
      return { loading: true };
    case PRODUCT_DETAILS_SUCCESS:
      return { loading: false, product: action.payload };
    case PRODUCT_DETAILS_FAIL:
      return { loading: false, error: action.payload };
    default:
      return state;
  }
};

This is the code for my action:

import axios from "axios";
import {
      PRODUCT_DETAILS_FAIL,
      PRODUCT_DETAILS_REQUEST,
      PRODUCT_DETAILS_SUCCESS,
    } from "../constants";
export const listProductDetails = (id) => async (dispatch) => {
  try {
    dispatch({
      type: PRODUCT_DETAILS_REQUEST,
    });
    const { data } = await axios.get(`/api/products/${id}`);
    dispatch({
      type: PRODUCT_DETAILS_SUCCESS,
      payload: data,
    });
  } catch (error) {
    dispatch({
      type: PRODUCT_DETAILS_FAIL,
      payload:
        error.response && error.response.data.message
          ? error.response.data.message
          : error.message,
    });
  }
};

I really cannot find the issue here, any help would be greatly appreciated!

Upvotes: 0

Views: 501

Answers (1)

michael
michael

Reputation: 4173

I think the problem is when you dispatch PRODUCT_DETAILS_REQUEST action, reducer will override the state value with { loading: true }, and so product will be undefined instead of empty object {}.

So you should return merged object with the previous state in the reducer. e.g. return { ...state, loading: true };

Hope it could help you.

export const productDetailsReducer = (state = { product: {} }, action) => {
  switch (action.type) {
    case PRODUCT_DETAILS_REQUEST:
      return { ...state, loading: true };
    case PRODUCT_DETAILS_SUCCESS:
      return { ...state, loading: false, product: action.payload };
    case PRODUCT_DETAILS_FAIL:
      return { ...state, loading: false, error: action.payload };
    default:
      return state;
  }
};

Upvotes: 1

Related Questions