Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use useEffect hook properly with array dependency. I passed state from redux store and still my component renders infinitely

I am using useEffect hook and getting a list of users data with fetch call using function getStoreUsers which dispatches an action on response and stores shopUsers(which is an array) inside the redux store.

In array dependency, I am writing [shopUsers]. I don't know why it is causing infinite rendering.

Here is how I am using useEffect hook:

useEffect(() => {
    const { getStoreUsers, shopUsers } = props;
    setLoading(true);
    getStoreUsers().then(() => {
      setLoading(false);
    }).catch(() => {
      setLoading(false);
    });
  }, [shopUsers]);

I want to re-render component only when data inside shopUsers array changes.

If I write shopUsers.length inside array dependency. It stops to re-render.

But, let's suppose I have have a page which opens up when the user clicks on a userList and updates user data on next page. After the update I want the user to go back to the same component which is not unmounted previously. So, In this case array length remains the same, but data inside in of array index is updated. So shopUsers.length won't work in that case.

like image 339
shubham choudhary Avatar asked Apr 18 '19 08:04

shubham choudhary


1 Answers

You can make a custom hook to do what you want:

In this example, we replace the last element in the array, and see the output in the console.

import React, { useState, useEffect, useRef } from "react";
import ReactDOM from "react-dom";
import { isEqual } from "lodash";

const usePrevious = value => {
  const ref = useRef();
  useEffect(() => {
    ref.current = value;
  });
  return ref.current;
};

const App = () => {
  const [arr, setArr] = useState([2, 4, 5]);
  const prevArr = usePrevious(arr);

  useEffect(() => {
    if (!isEqual(arr, prevArr)) {
      console.log(`array changed from ${prevArr} to ${arr}`);
    } 
  }, [prevArr]);

  const change = () => {
    const temp = [...arr];
    temp.pop();
    temp.push(6);
    setArr(temp);
  };

  return (
      <button onClick={change}>change last array element</button>
  )
};

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Live example here.

like image 92
Colin Ricardo Avatar answered Sep 21 '22 18:09

Colin Ricardo