4

So I have a question regarding useEffect dependenices

This is from the react docs:

useEffect(() => {
  document.title = `You clicked ${count} times`;
}, [count]); // Only re-run the effect if count changes

What does this mean exactly, does React keep track of the count variable and its value, and reacts when the value changes, or does React keep track of the first element in the array and its value.

What do I mean by this? Let me explain more. So if we have something like this [name] as dependencies. At the moment of evaluation, the array might result with ['Bob'] or ['Steve']. Clearly this is a change and the useEffect will rerender the component. But how does it check it?

Does it keep track of name or does it keep track of dependencyArray[0]. If we take a look in the previous example, both of these would result to true, name and the first element both changed their values from 'Bob' to 'Steve'. But how does it actually work?

Currently in my code I am using something like this [employees[selectedEmployee].name], where selectedEmployee is something clickable on the UI and it becomes 'Bob' or 'Steve'

ex:

const employees = {
   Bob: {
      name: 'Bob'
   },
   Steve: {
      name: 'Steve'
   }
}

This means that in the end, when evaluated, the dependency array will still result with ['Bob'] --> ['Steve'], and if React is evaluating the dependencyArray[0] then that has clearly changed and component should rerender, but If it keeps track of the reference, then I am changing the reference altogether and it may cause problems.

So what's the correct approach? Can I use dynamic properties like employees[selectedEmployee].name as a dependency?

1 Answer 1

2

count is a value, not a reference.

It's just good old Javascript, nothing fancy:

const myArray = [ count ]; // new array containing the value of variable 'count'
const myFunction = () => {
  document.title = `You clicked ${count} times`;
}

useEffect(
  myFunction,
  myArray
);

// Means actually:
// "Run this function if any value in the array
// is different to what it was last time this useEffect() was called"

does React keep track of the ... value, or ... the reference ?

React doesn't really 'keep track' of any of them. It only checks the difference to a previous call, and forgets about everything else.

Can I use dynamic properties as a dependency?

Yes, you can (because they are not as 'dynamic' as you think).

So what's the correct approach?

Better think less of any react-magic going on, but

  • understand that the component is a function, and believe React calls it when necessary and
  • think about the variables (properties and state) used inside it, from a plain Javascript perspective.

Then your 'dynamic properties' become 'constant variables during one function call'. No matter which variables change dynamically and how, it will always be one value last time and one value now.

Explaination:

The important 'trick' here is, that the component is just a javascript function, that is called like 'whenever anything might have changed', and consequently useEffect() is also called (as useEffect() is just a function call inside the component).
Only the callback function passed to useEffect is not always called.

useEffect does not render the component, useEffect is called when the component is called, and then just calls the function given to it, or not, depending on if any value in the dependencies array is different to what it was last time useEffect() was called.

React might rerender the component if in the function given to useEffect there are any changes made to the state or something (anything that makes React to think it has to rerender), but that's as a result of this state change, where ever it came from, not because of the useEffect call.

Example:

const MyComponent = (props) => {

  // I'm assigning many const here to show we are dealing with local constants.
  // Usually you would use this form (using array destructuring):
  // const [ selectedEmployee, setSelectedEmployee ] = useState( someInitialValue );

  const myStateValueAndSetter = useState( 'Bob' );
  const selectedEmployee    = myStateValueAndSetter[0];
  const setSelectedEmployee = myStateValueAndSetter[1];

  const employees = {
    Bob: { name: 'Bob' },
    Steve: { name: 'Steve' }
  };

  const currentName = employees[ selectedEmployee ].name;

  useEffect(() => {
    document.title = 'current name: ' + currentName;
  }, [ currentName ]);

  return <MyClickableComponent onClick={( newValue ) => {
    setSelectedEmployee( newValue )
  }}>;
};
  • click on MyClickableComponent calls the current setSelectedEmployee( newValue ) function.
    (The constant selectedEmployee is not changed!)
  • MyComponent() is called again.
    (This is a new function call. All the constants are gone! Only React stores some state in the background.)
  • useState() is called, the result is stored in a new constant selectedEmployee.
  • useEffect() is called, and decides if its callback should be called, depending on the previous and the current value of selectedEmployee.
    If the callback is not called and nothing else is changed, you might not notice that anything has happened at all.
  • <MyClickableComponent ... /> is rendered.
Sign up to request clarification or add additional context in comments.

2 Comments

So just to clarify First point: If we have 2 users, whose both names are 'Bob', And if we pass, user.name as a dependency, Does that mean that when we swap between users in the UI, because their name is the same, the useEffect won't call its callback? Second point Does the useEffect get activated when the dependency array switches from [1,2] to [2,1]? Is this considered a change, since all the previous elements are still here, only their positions are swapped? Third point Should I use objects inside in the dependency array, or should there only be primitive values?
First point: correct, user.name with both 'Bob' will not call the useEffect callback. But e.g. user instead of user.name will. Second point: good question! I think yes, but that should never happen, because the Idea of useEffect relies on the order unchanged, I believe. Third point: Both ok, to use objects and primitives. Generally, all objects used in the callback, should be put in the dependencies, but there is too much to say for a comment.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.