Correct Modification of State Arrays in React.Js

Correct modification of state arrays in React.js

The React docs says:

Treat this.state as if it were immutable.

Your push will mutate the state directly and that could potentially lead to error prone code, even if you are "resetting" the state again afterwards. For example, it could lead to that some lifecycle methods like componentDidUpdate won’t trigger.

The recommended approach in later React versions is to use an updater function when modifying states to prevent race conditions:

this.setState(prevState => ({
arrayvar: [...prevState.arrayvar, newelement]
}))

The memory "waste" is not an issue compared to the errors you might face using non-standard state modifications.

Alternative syntax for earlier React versions

You can use concat to get a clean syntax since it returns a new array:

this.setState({ 
arrayvar: this.state.arrayvar.concat([newelement])
})

In ES6 you can use the Spread Operator:

this.setState({
arrayvar: [...this.state.arrayvar, newelement]
})

How to edit an item in a state array?

My suggestion is to get used to use immutable operations, so you don't modify internal state object.

As pointed in the react docs:

Never mutate this.state directly, as calling setState() afterwards may
replace the mutation you made. Treat this.state as if it were
immutable.

In this case, you can [1] use slice() to get a new copy of the Array, [2] manipulate the copy, and, then, [3] setState with the new Array. It's a good practice.

Something like that:

const newIds = this.state.ids.slice() //copy the array
newIds[1] = 'B' //execute the manipulations
this.setState({ids: newIds}) //set the new state

how to set state array using react hooks

To insert new element at the end of the list

const addMessage = (newMessage) => setMessages(oldMessages => [...oldMessages, newMessage])

To insert new element at the begining of the list

const addMessage = (newMessage) => setMessages(oldMessages => [newMessage, ...oldMessages])

Correct way to push into state array

Array push returns length

this.state.myArray.push('new value') returns the length of the extended array, instead of the array itself.Array.prototype.push().

I guess you expect the returned value to be the array.

Immutability

It seems it's rather the behaviour of React:

NEVER mutate this.state directly, as calling setState() afterwards may
replace the mutation you made. Treat this.state as if it were
immutable.React.Component.

I guess, you would do it like this (not familiar with React):

var joined = this.state.myArray.concat('new value');
this.setState({ myArray: joined })

How to modify array within object in react component state

You need to return a new array for setActiveStates being particularly careful not to mutate the nested object that you are updating. A long hand approach is to findIndex() of the item you want to update, then use this index to spread slice()s of the array before and after the item in question, and also retrieve and clone the item itself and any nested object properties to return a copy.

const newMessages = [{ content: 'new1', received: true, date: '10:21 AM' }, { content: 'new2', received: true, date: '10:22 AM' }];
const itemId = 1;

setActiveChats(prevState => {
const index = prevState.findIndex(({ id }) => id = itemId);
const item = prevState[index];
return [
...prevState.slice(0, index),
{ ...item, messages: [...item.messages, ...newMessages] },
...prevState.slice(index + 1)
];
});

Sort & render an array of objects using a select in ReactJS

Lots of issues as pointed by David. You need to use state to manage the users & update state whenever sort direction is changed in the select. It's pretty straight forward. Working sample -

const {useState} = React;

function App() {
const [users, setUsers] = useState([
{ id: 1, name: "One" },
{ id: 2, name: "Two" },
{ id: 3, name: "Three" }
]);
function onSelectionChange(e) {
const sortDirection = e.target.value;
const copyArray = [...users]; // create a new array & not mutate state

copyArray.sort((a, b) => {
return sortDirection === "0" ? a.id - b.id : b.id - a.id;
});
setUsers(copyArray); //re-render
}

return (
<div className="App">
<select defaultValue={0} onChange={onSelectionChange}>
<option value={0}>Ascending</option>
<option value={1}>Descending</option>
</select>
{users.map((user) => (
<div key={user.id}>
{user.id} - {user.name}
</div>
))}
</div>
);
}

ReactDOM.render(
<App/>,
document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="react">

Updating state array based on another array

const array3=Array1.map(function (item) {
if (Array2.includes(item.title)) {
item.checked = true;
}
return item;
})
setArray1(array3)

You may try this inside useEffect function.



Related Topics



Leave a reply



Submit