PrevProps giving same value as props

Viewed 38

I have a scene component that I map to array of objects in editor.

And am passing the scene object as props to every scene, and i wanted to get the previous scene when i press a button.

But when I compare them in the console they are the same.

I used useRef and useEffect hooks to get prevProps

code for editor:

const scene = {
    jsonObj: null,
  };
  const [scenes, setScenes] = useState([scene]);
  useEffect(() => {
    
  }, []);
const switchScene = (scene, prevScene) => {
    const JsonObj = canvas.setJsonObj();
    console.log(JsonObj);
    const index = scenes.indexOf(scene);
    canvas.resetEditor();
    const prevIndex = scenes.indexOf(prevScene);
    console.log(prevIndex, index);
    let cpScenes = [...scenes];
    cpScenes[prevIndex].jsonObj = JSON.stringify(JsonObj);
    setScenes(cpScenes);

    cpScenes = [...scenes];
    cpScenes[index].jsonObj = JsonObj;
    setScenes(cpScenes);

    canvas.loadJson(scene.JsonObj);

    console.log(scene);
    console.log(prevScene);
  };

return(
<div>
          {scenes.map((scene, i) => (
            <Scene
              key={i * Math.floor(Math.random() * 100)}
              addText="Scene"
              onDelete={removeScene}
              scene={scene}
              switchScene={(scene, prevScene) => {
                setUpdate(Math.floor(Math.random() * 100));
                switchScene(scene, prevScene);
              }}
            />
          ))}
);

code for scene:

import React, { useEffect, useRef, useState } from "react";
import _uniqueId from "lodash/uniqueId";

function Scene(props) {
  const id = useState(_uniqueId("sceneCmpn-"));
  const prevScene = useRef(props.scene);

  useEffect(() => {
    prevScene.current = props.scene;
  }, [props.Scene]);
  return (
    <div key={id}>
      <button
        id={id}
        onClick={() => {
          props.switchScene(props.scene, prevScene.current);
        }}
      >
        Scene
      </button>
      <button
        onClick={() => props.onDelete(props.scene)}
        className="btn btn-danger m-2"
      >
        remove scene
      </button>
    </div>
  );
}

export default Scene;

1 Answers

I think the way the usePrevious hook works is by returning a stale value - the useEffect is only called after the value is updated inside the hook (I think).

I think the problem with having onClick as the following:

onClick={() => {
  props.switchScene(props.scene, prevScene.current);
}}

Is that the useEffect will updated the prevScene before the click is actually handled (so it will return the same value for props.scene, prevScene.current).

Instead of integrating that functionality inside your component, I think you could get it to work by using the hook separately.

I tried your initial approach with a simple example with a counter:

function Switcher(value) {
  const ref = useRef();
  useEffect(() => {
    ref.current = value;
  }, [value]); 

  const onClick = () => {
    console.log(value, ref.current);
  };

  return <button onClick={onClick}> LOG </button>;
}

export default Switcher;

In this case, clicking the button didn't work as expected, it showerd the same value for value and previousValue:

enter image description here

However this could be fixed by separating out the hook:

function Switcher(value) {
  const prevValue = usePrev(value);

  const onClick = () => {
    console.log(value, prevValue);
  };

  return <button onClick={onClick}> LOG </button>;
}

export default Switcher;

Here is the console output:

enter image description here

You can find the sandbox here

Related