ReactJS. All parts of the hook have different value of the same state

Viewed 33

Here is a program. By pushing Add Button you can add a button. Pushing the Show current number of buttons you can show current number of buttons.
But it appears every button has its own idea about how many buttons we currently have. Every button somehow “remembers” the number_of_buttons we had when it was “born”, and does not see the current value of this state.
I want state property number_of_buttons to be the same for every element in the hook. How to do this?

import React, { useState, useEffect } from 'react';
import ReactDOM from "react-dom";

var just_key = 50;

class App extends React.Component {               
    render() {
        return (
                <SomeCrazyButtons/>
        );
    }
}

function SomeCrazyButtons() {
    const [number_of_buttons, setButtonsNumber] = useState(1);
    const [some_html, setSomeHtml] = useState([]);

    function addClickNumber() {
        setButtonsNumber(number_of_buttons + 1);
    }

    function showCurrentNumberOfButtons() { 
        console.log("Current number of buttons is " + number_of_buttons);
    }

    useEffect(() => { 
        just_key++;
        console.log("We have " + number_of_buttons + " buttons");
        var new_button = [
            <button key = {just_key + "b"} onClick = {showCurrentNumberOfButtons}>Show current number of buttons</button>
        ];
        var new_buttons = some_html.concat(new_button);
        setSomeHtml(new_buttons);
      }, [number_of_buttons]);

    return (
        <div>
            {some_html}
            <button onClick = {addClickNumber}>Add button</button>
        </div>
    )  
}

ReactDOM.render(
    <App />,
    document.getElementById('root')
);

1 Answers

Don't store components in state. As you've discovered, it's an easy way to end up rendering stale components, because you forgot to update your stored components to match your new state. Instead, just store the minimal data needed to define the state (in this case, the number of buttons), and create the components when you render.

function SomeCrazyButtons() {
  const [number_of_buttons, setButtonsNumber] = useState(1);

  function addClickNumber() {
    setButtonsNumber(number_of_buttons + 1);
  }

  function showCurrentNumberOfButtons() { 
    console.log("Current number of buttons is " + number_of_buttons);
  }

  const buttons = [];
  for (let i = 0; i < number_of_buttons; i++) {
    buttons.push((
      <button key={i + 'b'} onClick={showCurrentNumberOfButtons}>
        Show current number of buttons
      </button>
    );
  }

  return (
    <div>
      {buttons}
      <button onClick={addClickNumber}>Add button</button>
    </div>
  );
}
Related