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
Is It Safe to Expose Firebase APIkey to the Public
Web-Scraping JavaScript Page With Python
Sorting Object Property by Values
Add a Property to a JavaScript Object Using a Variable as the Name
How to Sort an Array of Integers Correctly
How to Create a File in Memory For User to Download, But Not Through Server
How to Calculate Number of Days Between Two Dates
What Is the 'New' Keyword in JavaScript
Why Is Extending Native Objects a Bad Practice
What Is the !! (Not Not) Operator in JavaScript
Add a Property to a JavaScript Object Using a Variable as the Name
Setting "Checked" For a Checkbox With Jquery
Short Circuit Array.Foreach Like Calling Break