1

i wonder how using useEffect like componentWillReceiveProps.

i'm using redux in my react app.

So i have a some redux state when it state updated i wan't to execute some function in my component. When i use class components i did it like that:

componentWillReceiveProps(nextProps) {
   if (nextProps.Reducer.complete !== this.props.Reducer.complete) {
     someFunc();
   }
}

Now i'm using just functional components and hooks.

now my component is like that: I'm trying to do it with this way but not working. Any idea where i mistaken ?

function Component(props) {
  const Reducer = useSelector(state => state.Reducer);

  const someFunc = () => {
     .....
  }

  useEffect(() => {
    someFunc();
  }, [Reducer.complete]);

}

export default Component;
user3348410
  • 2,733
  • 10
  • 51
  • 85

3 Answers3

2

Since someFunc is a dependency of the effect and you create someFunc every time you render Component the effect will either be called every time because you correctly added the dependency or behave unexpectedly because you didn't add it or you have set up your development environment with eslint and exhaustive deps and your dev environment will warn you that your effect has missing dependencies.

To prevent someFunc to be re created on every render you can use useCallback:

function Component(props) {
  const Reducer = useSelector(state => state.Reducer);

  const someFunc = useCallback(() => {
    //  .....
  }, []);

  useEffect(() => {
    someFunc(Reducer.complete); //should use the dep
  }, [Reducer.complete, someFunc]);
}

If in the body of someFunc you use props or values created in Component then passing [] as dependencies will not work, you can use exhaustive deps to help you with this.

Here is a working example of effect reacting to changing value:

const {
  useCallback,
  useState,
  useEffect,
} = React;

function Component() {
  const [complete, setComplete] = React.useState(false);
  const [message, setMessage] = React.useState(
    `complete is ${complete}`
  );

  const completeChanged = useCallback(complete => {
    console.log(
      'running effect, setting message:',
      complete
    );
    setMessage(`complete is ${complete}`);
  }, []);
  const toggleComplete = useCallback(
    () => setComplete(c => !c),
    []
  );
  useEffect(() => {
    completeChanged(complete); //should use the dep
  }, [complete, completeChanged, setMessage]);
  console.log('rendering:', complete);
  return (
    <div>
      <button onClick={toggleComplete}>
        toggle complete
      </button>
      {message}
    </div>
  );
}


//render app
ReactDOM.render(
  <Component />,
  document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
HMR
  • 37,593
  • 24
  • 91
  • 160
0

The react hook equivalent to the old componentWillReceive props can be done using the useEffect hook, just specifying the prop that we want to listen for changes in the dependency array. Try this:

useEffect( () => {
     someFunc()
}, [props.something, someFunc])
aturan23
  • 4,798
  • 4
  • 28
  • 52
  • You are missing dependency `someFunc` but since it's created in `Component` it'll run the effect on every render if you don't create `someFunc` with `useCallback` – HMR Mar 12 '20 at 07:50
0

Ok, so I assume that Reducer now is an object and have a complete key. Try to create conditional inside your useEffect.

useEffect(() => {
  if (Reducer.complete) {
    runThisFunction()
  }
}, [Reducer.complete, runThisFuntion])
danu
  • 55
  • 6
  • In OP's code he defines `someFunc` in `Component` so adding that in the dependencies without `useCallback` will have the effect run on every render, even if complete didn't change. – HMR Mar 12 '20 at 07:49
  • should we always wrap a function with `useCallback`? @HMR – danu Mar 12 '20 at 08:21
  • In this case it makes sense because you only want to run the effect when complete changes, not when the function changes and the function changes every render. It is better to use it as well when you pass a function to be used as an event handler (like onClick), it will prevent React to needlessly re render DOM elements. You can read the comments in [this answer](https://stackoverflow.com/a/60595693/1641941) for a more detailed explanation of what will happen if you do `prop={new=>reference}` or `prop={{new:'reference'}}` – HMR Mar 12 '20 at 08:42