Whateverneveranywhere
Whateverneveranywhere

Reputation: 33

React useReducer empties initialState

i'm trying to use some data fetched by axios inside initialState so I can use it with useReducer later on. but as soon as I pass it as the initialState of my second argument it returns an empty array with no objects. please help... :(

 const [prods, setProds] = useState([]);
  const getProds = () => {
    axios.get(`API`).then((res) => {
      const data = res.data;
      setProds(data.products);
    });
  };


  const result = prods.map(function (el) {
    const quantity = Object.assign({}, el);
    quantity.count = 0;
    return quantity;
  });
  
  const initialState = {
    products: [result],
  };
  useEffect(() => {
    getProds();
  }, []);

console.log(initialState);

  const [countState, dispatch] = useReducer(counterReducer, initialState);

  console.log(countState);

and the result from the first and second log looks like :

useReducer empties initialState

the result from API call after adding the count to each looks something like this :

enter image description here

and here's the code for my reducer, I checked it many times but seems fine :

export const counterReducer = (state, action) => {
  switch (action.type) {
    case "increment":
      return {
        ...state,
        products: state.products.map((product) =>
          product.id === action.id
            ? { ...product, count: product.count + 1 }
            : product
        ),
      };

    case "decrement":
      return {
        ...state,
        products: state.products.map((product) =>
          product.id === action.id
            ? {
                ...product,
                count: product.count !== 1 ? product.count - 1 : 1,
              }
            : product
        ),
      };
    default:
      return state;
  }
};

Upvotes: 3

Views: 1962

Answers (1)

ThatAnnoyingDude
ThatAnnoyingDude

Reputation: 562

useReducer consumes initialState only on first render(before axios finished), on all the subsequent rerenders it will just return the state from the memory cell. What you want to do is to call useReducer at the top

const [countState, dispatch] = useReducer(counterReducer, {products: []});

and then call dispatch in your getProds

const getProds = () => {
    axios.get(`API`).then((res) => {
      const data = res.data;
      setProds(data.products);
      dispatch({ type: "PRODUCTS_FETCHED", payload: data.products});
    });
  };

And also add according case in your reducer to set the state.

export const counterReducer = (state, action) => {
  switch (action.type) {
    case "increment":
      return {
        ...state,
        products: state.products.map((product) =>
          product.id === action.id
            ? { ...product, count: product.count + 1 }
            : product
        ),
      };

    case "decrement":
      return {
        ...state,
        products: state.products.map((product) =>
          product.id === action.id
            ? {
                ...product,
                count: product.count !== 1 ? product.count - 1 : 1,
              }
            : product
        ),
      };
    case "PRODUCTS_FETCHED":
      return {
        ...state,
        products: action.payload
      };
    default:
      return state;
  }
};

Upvotes: 5

Related Questions