I have created a React application to test out the useState hook.
This the variable of concern:
let [blocks, setBlocks] = useState([
{text: "Hello", id: 1},
{text: "This is google", id: 2},
{text: "Wassup", id: 3},
{text: "Last One", id: 4}
]);
I've displayed this using the map function as follows:
return (
<div className="App">
{blocks.map((block) => (
<div className='block-element'>{block.text}</div>
))}
<button onClick={clickFunc}>ClickToChange</button>
</div>
);
As far as I've understood, to make any change in the webpage we have to pass the new-data into setBlocks() and wherever "blocks" was used will be updated.
I tried the following clickFunc() to do so:
const clickFunc = ()=>{
blocks[1].text = "Go Home";
setBlocks(blocks);
console.log(blocks);
}
I expected the output (onclicking the button) to be:
Hello
Go Home
Wassup
Last One
But nothing changed.
Surprisingly when I used the following (similar looking) clickFunc():
const clickFunc = ()=>{
blocks = [
{ text: "Hello", id: 1 },
{ text: "Go Home", id: 2 },
{ text: "Wassup", id: 3 },
{ text: "Last One", id: 4 }
];
setBlocks(blocks);
console.log(blocks);
}
And it worked perfectly as expected. On click output:
Hello
Go Home
Wassup
Last One
CodePudding user response:
NEVER mutate state directly.
The following code block is mutation and wrong. Javascript is kind of like some other programming languages where only the reference of the object is stored in the memory. So when you mutate the object instead of creating a new one, you are not really changing the content of the object in memory, because it still has the same value(reference) as before.
const blocks = [{text: 'one'}];
blocks[0].text = 'two';
You should create a new object and assign it to state using React setState
callback:
setBlocks(blocks => {
clonedBlocks = [ ...blocks];
clonedBlocks[1]= { ...blocks[1], text: "Go Home" };
return clonedBlocks;
});
Or any other way that does not mutate the state directly.
CodePudding user response:
React state is immutable
if you mutate the state react will not know that state is changed
first you need to copy the state using Spread syntax and change it
const clickFunc = () => {
setBlocks(prevBlocks => {
const shallowCopy = [...prevBlocks]
shallowCopy[1].text = "Go Home";
return shallowCopy
});
}