0

I created a minimalistic app using the npx create-react-app approach. I created a functional component and tried if an old setValue method of a useState hook updates the value maintained by the hook.

Therefore, I created an array listOfSetValueMethods that contains all setValue methods. In the myButtonClick() method I used the first setValue method to update the value of the hook: it does not work: react does not re-render anything: listOfSetValueMethods[0](scopeId+1);. If I use ANY other setValue method, it does work:

var myCounter=0;
var listOfSetValueMethods=[];

function MyComponent() {
  const [currentScopeId,setValue]=useState(-1);
  listOfSetValueMethods.push(setValue);

  let scopeId=myCounter++;
  console.log("scopeId: " + scopeId);

  function myButtonClick(){
    if(listOfSetValueMethods.length>0){
      listOfSetValueMethods[0](scopeId+1); //does not work
      //works: listOfSetValueMethods[1](scopeId+1); 
      console.log("setted value to:" + (scopeId+1) + ", current value in scope:" + currentScopeId);
    }else{
      setValue(scopeId);
    }
  }

  return (
    <div>
      <b onClick={()=>{myButtonClick()}}> id: {currentScopeId}</b> <br />
    </div>
  );
} 

What is the difference between calling listOfSetValueMethods[0](scopeId+1) and listOfSetValueMethods[X](scopeId+1) whereby X>0?

Output from console:

scopeId: 0
App.js:13 scopeId: 1
App.js:19 setted value to:2, current value in scope:-1
App.js:13 scopeId: 2
App.js:13 scopeId: 3
App.js:19 setted value to:2, current value in scope:-1
App.js:13 scopeId: 4

so the current scope id remains at -1! App.js:13 scopeId: 5

user3579222
  • 1,103
  • 11
  • 28
  • What are you trying to do? If you want a counter you can do `onClick={myButtonClick}` and define myButtonClick as `const myButtonClick=()=>setValue(value=>value+1)` – HMR May 14 '20 at 18:49
  • 1
    This post will help you understand the closure issues with your code when you run the state updater function: https://stackoverflow.com/questions/54069253/usestate-set-method-not-reflecting-change-immediately – Shubham Khatri May 14 '20 at 18:53

1 Answers1

0

I have no idea what you are trying to do and why you are making it so difficult. You keep pushing setValue to listOfSetValueMethods on every render but setValue never changes so there is no point.

You are logging a stale closure so maybe that's what you mean with "not working".

Here is your code working and showing that setValue is the same every render:

var myCounter = 0;
var listOfSetValueMethods = [];

function App() {
  const [currentScopeId, setValue] = React.useState(-1);
  listOfSetValueMethods.push(setValue);

  let scopeId = myCounter++;
  console.log('scopeId: ' + scopeId);

  function myButtonClick() {
    //this works just fine
    listOfSetValueMethods[0](scopeId + 1);
    console.log(
      'setted value to:' +
        (scopeId + 1) +
        ', current value in scope:' +
        currentScopeId //this logs a stale closure
    );
  }

  return (
    <div>
      are all items in listOfSetValueMethods the same:
      {listOfSetValueMethods.every(
        (item) => item === setValue
      )+""}
      <button onClick={() => {myButtonClick()}}>
        id: {currentScopeId}
      </button>
    </div>
  );
}
ReactDOM.render(<App />, 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>

So instead of having these myCounter and listOfSetValueMethods that would break if you render multiple instances of that component you could just do:

function myButtonClick() {
  setValue(value=>value+1)
}
HMR
  • 37,593
  • 24
  • 91
  • 160
  • 1
    Hmmm: in strict mode it does NOT work ReactDOM.render( , document.getElementById('root') ); Do you know why - I do not get any relevant warning? – user3579222 May 14 '20 at 19:32
  • 1
    @user3579222 Looks like in strictmode the setValue changes (you can see `are all items in listOfSetValueMethods the same:false` StrictMode is only during development and I never use it because it gives buggy console.logs as well and runs hooks multiple times when it should not. It will work if you just not use myCounter and listOfSetValueMethods and just define myButtonClick as follows: `function myButtonClick() { setValue(value=>value+1) }` – HMR May 14 '20 at 19:39