skip to Main Content

I’m confused about when react does decide to re-render.

function App() {
  const [position, setPosition] = useState({x: 0, y: 0});

  console.log(position);

  const handleMove = (e) => {
    const newPos = {x: e.clientX, y: e.clientY};
    setPosition(newPos);
    position.x = e.clientX;
    position.y = e.clientY;
    setPosition(position);
  };

  return (
    <div onPointerMove={e => {
      handleMove(e);
    }}>
      <h1>{position.x}</h1>
      <h1>{position.y}</h1>
    </div>
  );
}

The code above is from my React component function.

In this code, you can see that I’m mutating the object used as state. Although it’s a method forbidden by React, I wrote this code for experimental purposes.

After mutating the original object and then calling the setState function, re-rendering does not occur. To force a re-render, I created and assigned newPos, and then reassigned the original position object.

Upon logging, I noticed that my component function is continuously called, and the position’s x and y values are consistently updated. I also confirmed that in the returned JSX object, position.x and position.y values are changing.

However, the actual webpage doesn’t reflect these changes. What could be the reason? Is the re-rendering rejected during the process of comparing the existing DOM with the newly created DOM after the JSX is returned? But the values in the JSX have clearly changed.

Is there anyone who can provide a clear answer to this?

2

Answers


  1. I am not exactly sure what problem you are facing.I tried to replicate the issue.
    This works fine and x and y are updated on on page when I move the cursor.

    function Test() {
      const [position, setPosition] = useState({ x: 0, y: 0 });
    
      function handlePointer(e) {
        const newPos = {
          x: e.clientX,
          y: e.clientY,
        };
        setPosition(newPos);
      }
      console.log(position);
      return (
        <div onPointerMove={(e) => handlePointer(e)}>
          <p>
            X: {position.x}, Y: {position.y}
          </p>
        </div>
      );
    }
    

    you already have a similar implementation which should work fine. Need more clarification if this is not working?

    const newPos = {x: e.clientX, y: e.clientY};
    setPosition(newPos);
    

    Also, I am not clear on the purpose of the below code. This should not be required.

    position.x = e.clientX;
    position.y = e.clientY;
    setPosition(position);
    

    Edit: Updated the example with exact use case

    Login or Signup to reply.
  2. Objects in Javascript are a reference type. When you assign an object to a variable name, the value being assigned is a pointer, not a value. Quoting the MDN example:

    // Two variables, two distinct objects with the same properties
    const fruit = { name: "apple" };
    const fruitbear = { name: "apple" };
    
    fruit == fruitbear; // return false
    fruit === fruitbear; // return false
    

    The objects that fruit and fruitbear point to have the same value, but a comparison between the two variables show they are different because they point different memory locations. If you change a property of fruit, fruitbear will not change.

    // Two variables, a single object
    const fruit = { name: "apple" };
    const fruitbear = fruit; // Assign fruit object reference to fruitbear
    
    // Here fruit and fruitbear are pointing to same object
    fruit == fruitbear; // return true
    fruit === fruitbear; // return true
    
    fruit.name = "grape";
    console.log(fruitbear); // { name: "grape" }; not { name: "apple" }
    

    This example shows that the value of fruitbear is a reference to the same object referenced by fruit, so changing properties of fruit will also change properties of fruitbear. This is why setPosition(position) will not trigger a re-render; the value of position is a pointer and that pointer does not change when properties of the object being referenced change. It would change if you created a new object and assign that to position before running setPosition.

    This will always be the case when you use reference types like Object and Array with state. The usual recommendation for react is to make state updates immutable, which is what you did with newPos. As has been pointed out already the component will rerender if you setPosition(newPos), but it will not rerender if you include the setPosition(position).

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search