Skip to content
Advertisement

Replicate element in React

Hello thanks for the help, with the following code in react I want to replicate the click button every time I click on it. Currently nothing happens, but if the console shows that the array grows. Here the sandbox:

https://codesandbox.io/s/charming-glitter-0ntxmj?file=/src/App.js

const { useEffect, useState } = React;

function App() {
  const btn = [
    <button
      onClick={() => {
        btn.push(btn[0]);
        console.log(btn);
      }}
    >
      Click
    </button>
  ];

  /*  useEffect(()=>{
btn
  },[btn])*/

  return (
    <div className="App">
      <div>
        {btn.map((e) => {
          return e;
        })}
      </div>
    </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>

Advertisement

Answer

Updating a local variable in a function component doesn’t work that way. It behaves just like a normal function, btn only exists during the execution of App().

In order to persist values across renders you need to use state. However, updates to state and props are the only things that cause rerenders in the first place, so App is probably only being rendered one time at the beginning.

If you convert this directly to use state, you will run into the anti-pattern of storing components in state. To avoid that, we should modify the logic to only store some generic items in the state array so that our rendering logic can us it to determine how many buttons to render.

Consider the following option:

const { useState } = React;

function App() {
  const [btns, setBtns] = useState(['value'])
  
  function handleAdd() {
    setBtns((prev) => ([...btns, 'value']));
  }

  return (
    <div className="App">
      <div>
        {btns.map((e) => (
          <button
            onClick={handleAdd}
          >
            Click
          </button>
        ))}
      </div>
    </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>

You can simplify even more by only storing the count of buttons in your state:

const { useState } = React;

function App() {
  const [btnCount, setBtnCount] = useState(1)
  
  function handleAdd() {
    setBtnCount(btnCount + 1);
  }

  return (
    <div className="App">
      <div>
        {Array.from({ length: btnCount}).map((e) => (
          <button
            onClick={handleAdd}
          >
            Click
          </button>
        ))}
      </div>
    </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>
User contributions licensed under: CC BY-SA
8 People found this is helpful
Advertisement