I want to update state like [1, 2, 3] but what I'm wrong here and how to fix it.
codesanbox: https://codesandbox.io/s/infallible-mendeleev-6641iw?file=/src/App.js:0-642
import "./styles.css";
import { useEffect, useState } from "react";
export default function App() {
const [value, setValue] = useState([]);
useEffect(() => {
run();
}, []);
const run = () => {
for (let i = 0; i < 10; i ) {
let copy = i;
switch (copy) {
case 1:
setValue([...value, copy]);
break;
case 2:
setValue([...value, copy]);
break;
case 3:
setValue([...value, copy]);
}
}
};
return (
<div className="App">
{value.map((item, index) => {
return <h2>{value[index]}</h2>;
})}
</div>
);
}
CodePudding user response:
The problem is that every time you do setValue([...value, copy])
, you're overwriting the previous time you did it. value
is unchanging in that loop.
Instead, build the new array and then set it in state. And any time you're building new state based on existing state, it's generally best to use the callback form of the state setter (to ensure that you're not starting with a stale version of value
).
Example:
const run = () => {
setValue((oldValue) => {
const newValue = [...oldValue];
for (let i = 0; i < 10; i ) {
let copy = i; // ** There's no need for this, just use `i`
switch (copy) {
case 1:
newValue.push(copy); // It's not clear to me why...
break;
case 2:
newValue.push(copy); // ...every case does the same..
break;
case 3:
newValue.push(copy); // ...thing, but I replicated it
break;
}
}
return newValue;
});
};
Old version showing the problem:
const { useEffect, useState } = React;
/*export default*/ function App() {
const [value, setValue] = useState([]);
useEffect(() => {
run();
}, []);
const run = () => {
for (let i = 0; i < 10; i ) {
let copy = i;
switch (copy) {
case 1:
setValue([...value, copy]);
break;
case 2:
setValue([...value, copy]);
break;
case 3:
setValue([...value, copy]);
}
}
};
return (
<div className="App">
{value.map((item, index) => {
return <h2>{value[index]}</h2>;
})}
</div>
);
}
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<App />);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.development.js"></script>
New version showing the solution:
const { useEffect, useState } = React;
/*export default*/ function App() {
const [value, setValue] = useState([]);
useEffect(() => {
run();
}, []);
const run = () => {
setValue((oldValue) => {
const newValue = [...oldValue];
for (let i = 0; i < 10; i ) {
let copy = i; // ** There's no need for this, just use `i`
switch (copy) {
case 1:
newValue.push(copy); // It's not clear to me why...
break;
case 2:
newValue.push(copy); // ...every case does the same..
break;
case 3:
newValue.push(copy); // ...thing, but I replicated it
break;
}
}
return newValue;
});
};
return (
<div className="App">
{value.map((item, index) => {
return <h2>{value[index]}</h2>;
})}
</div>
);
}
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<App />);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.development.js"></script>
Side note: You need key
props on those h2
elements in the map
callback.
CodePudding user response:
Oh, I know how to make state become [1, 2, 3]
just use the previous value in every setState();
for (let i = 0; i < 10; i ) {
let copy = i;
switch (copy) {
case 1:
setValue((value) => [...value, copy]);
break;
case 2:
setValue((value) => [...value, copy]);
break;
case 3:
setValue((value) => [...value, copy]);
}
}
};