0

Hey all given a basic react component that has componentWillReceiveProps. I want to convert this to use react hooks. Now I've looked at this question here and whilst the answer is straightforward I feel as though I'm miss-understanding something. For example:

export class Example extends React.Component {
  constructor(props) {
    super(props);
  }

  componentWillReceiveProps(nextProps) {
    console.log('HELLO WORLD') // Note this isn't called on initial render
    if (nextProps.match.params.id != this.props.match.params.id) {
      console.log('testing....')
    }
  }

  render() {
    return (
      <div>Cool</div>
    );
  }
}

I know that from the above example that we won't get into the if statement unless the nextProps hasn't changed. Now converting the above to function component is like this:

export const Example = ({ ...props }) => {
  useEffect(() => {
    console.log('TESTING')
  }, [props.match.params.id])

  return (
    <div>Cool</div>
  )
}

I've also prepared a short recording gif of what I'm seeing. https://recordit.co/hPuwGey6WM

green1919
  • 289
  • 2
  • 13
  • 1
    To add dependencies, you'll need to use arrays. `useEffect(function(0 {}, [props.match.params.id]);` That being said, I think it will always run on the first render – SerShubham Apr 23 '20 at 14:13
  • @SerShubham - sorry you're right even with the array syntax I'm seeing the same thing. You'll see this in the recording. – green1919 Apr 23 '20 at 14:14
  • `useEffect` always runs on first mount – Jagrati Apr 23 '20 at 14:15
  • right.. so how do I _correctly_ simulate the behaviour of: `componentWillReceiveProps`. Because this doesn't run on first mount. – green1919 Apr 23 '20 at 14:16
  • @Jagrati - i know that if you don't want an effect to run on first mount you have to pass in an empty array to useEffect. But that would mean I would not be observing any properties. – green1919 Apr 23 '20 at 14:17
  • Basically this is what I think I'm looking for: https://stackoverflow.com/questions/53351517/react-hooks-skip-first-run-in-useeffect – green1919 Apr 23 '20 at 14:18

2 Answers2

1

useEffect always runs after first render. If you don't want to run useEffect on first render , you can use it in combination with useRef

const Example = ({ ...props }) => {
  const initialRender = useRef(true)
  useEffect(() => {
    if (initialRender.current) {
      initialRender.current = false;
    } else {
      // write code here
      console.log("TESTING");
    }
  }, [props.match.params.id]);

  return <div>Cool</div>;
};
Jagrati
  • 11,474
  • 9
  • 35
  • 56
1

Unfortunately, useEffect is designed to run on the first render and everytime it's dependencies change.

To avoid running on the first render, you will have to write your own little custom hook.

const useComponentWillReceiveProps = (callback, dependencies) => {
  const [firstRender, setFirstRender] = useState(true);

  useEffect(() => {
     if(firstRender) {
        setFirstRender(false);
        return;
     }
     callback();
  }, dependencies);
}

Alternatively, you could also use refs to avoid the initial re-render like:

const useComponentWillReceiveProps = (callback, dependencies) => {
   const firstRender = useRef(true);

  useEffect(() => {
     if(firstRender.current) {
        firstRender.current = false;
        return;
     }
     callback();
  }, dependencies);
}
SerShubham
  • 873
  • 4
  • 10