React: React Hook cannot call a function in the useEffect and function component to setState operation?

Created on 12 Jun 2019  ·  2Comments  ·  Source: facebook/react

Save question #15865

I have a function that needs to be called when componentDidMount and handleClick.

On the class component, there is no problem, but I converted to a React Hook function, inside the useEffect, mocking componentDidMount and calling this function. Outside the element, by clicking on the event, we also need to call this function to trigger the new calculation.

function App() {
  const [elePositionArr, setElePositionArr] = useState([
    { left: 0, top: 0 },
    { left: 0, top: 0 },
    { left: 0, top: 0 }
  ]);
  const stageRef = useRef(null);
  const Stage = useRef({ w: 0, h: 0 });
  const currentIndex = useRef(0);

  useEffect(() => {
    // Record the size of the stage when componentDidMount, Important!!!
    const stageW = stageRef.current.scrollWidth;
    const stageH = stageRef.current.scrollHeight;

    Stage.current = { w: stageW, h: stageH };

    const index = Math.floor(Math.random() * 3);
    currentIndex.current = index;
    // Randomly set the position of the element
    setCenterPosition(index);
  }, []);

  // Centering a block element
  function setCenterPosition(index) {
    let cacheEle = elePositionArr;
    // calc center postion
    const centerOfLeft = Stage.current.w / 2 - 25;
    const centerOfTop = Stage.current.h / 2 - 25;

    cacheEle = cacheEle.map((item, i) => {
      const randomWNum = Math.floor(Math.random() * Stage.current.w) - 50;
      const randomHNum = Math.floor(Math.random() * Stage.current.h) - 50;
      const randomLeft = randomWNum <= 50 ? 50 : randomWNum;
      const randomTop = randomHNum <= 50 ? 50 : randomHNum;
      let newItem;

      if (index === i) {
        newItem = { left: centerOfLeft, top: centerOfTop };
      } else {
        newItem = { left: randomLeft, top: randomTop };
      }

      return newItem;
    });

    setElePositionArr(cacheEle);
  }

  // click nav li, then setElePositionArr
  function handleClickLi(index) {
    if (currentIndex.current !== index) {
      setCenterPosition(index);
      currentIndex.current = index;
    }
  }

  return (
    <div className="container">
      <div className="stage" ref={stageRef}>
        {elePositionArr.map((item, index) => (
          <div className="ele" key={index} style={item}>
            {index}
          </div>
        ))}
      </div>
      <ul className="nav">
        {elePositionArr.map((item, index) => (
          <li
            className={currentIndex.current === index ? "active-li" : ""}
            onClick={() => {
              handleClickLi(index);
            }}
            key={"li" + index}
          >
            {index}
          </li>
        ))}
      </ul>
    </div>
  );
}

So, React Hook will prompt:

React Hook useEffect has a missing dependency: 'setCenterPosition'.
Either include it or remove the dependency array. (react-hooks/exhaustive-deps)

I didn't find a suitable answer in the 8. Hooks FAQ. Can someone help me?

codesandbox
https://codesandbox.io/s/trusting-kowalevski-oet4b

Most helpful comment

not sure what answer you are looking for here. But, general problem is you are trying to make this act like a class component instead of embracing how the hooks work. For instance setCenterPosition is defined twice because it's called again in handleClickLi. But you don't need to do that. Instead write your useEffect so it runs when you need it to: _in response to the changing index_. Then you don't need the function you can put all the logic in useEffect.

In the general you don't want to think in terms of "How do i map useEffect to component lifecycles", instead structure them to run when the things they depend on change.

Here is one example of how you might do that: https://codesandbox.io/s/magical-wildflower-d8gp0

All 2 comments

not sure what answer you are looking for here. But, general problem is you are trying to make this act like a class component instead of embracing how the hooks work. For instance setCenterPosition is defined twice because it's called again in handleClickLi. But you don't need to do that. Instead write your useEffect so it runs when you need it to: _in response to the changing index_. Then you don't need the function you can put all the logic in useEffect.

In the general you don't want to think in terms of "How do i map useEffect to component lifecycles", instead structure them to run when the things they depend on change.

Here is one example of how you might do that: https://codesandbox.io/s/magical-wildflower-d8gp0

@jquense Thank you very much for providing a solution,my problem may be a hook conversion based on the form of class, so the understanding of useEffect is not deep enough, as you said, instead structure them to run when the things they depend on change.

Was this page helpful?
0 / 5 - 0 ratings