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>
CodePudding user response:
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>
CodePudding user response:
Yes, changes are made to your component, and yes you can see them in the console, but
- App function is just a function and each time it run it will create the array and it will always have the same value (one element).
- React will not update unless state or props has changed for a component.
- even if your App function update, in react an update means React will re-run the same function again (you endup always with one element in the array).
So to solve this issue you can use state, even thow App is still a function, the useState will garenty that if the value of the array change, React will remeber the changes for you, and React also will re-render your component when state changes.
Keep in mind also that you can change the value of the state only using the provided function setBtns
and mutating the btns
will not update your component, and mutation of state is always source of bugs.
const [btns, setBtns] = useState([
<button
onClick={() => setBtns((prev) => [...prev, prev[0]])}
>
Click
</button>
]);