I have state structure, something like this at the beginning:
messages:[
{id: 1, name: 'name1'},
{id: 2, name: 'name2'}, ...
]
What I want is to update one message based on its id
key. I am getting from the server another object like this:
{id: 2, name: 'newName2'}
The state is an array: (2) [{…}, {…}]
. I don't know which element with which index will be updated, I know only the id key inside the object.
How I can update object inside the state based on its key value ?
I have state structure, something like this at the beginning:
messages:[
{id: 1, name: 'name1'},
{id: 2, name: 'name2'}, ...
]
What I want is to update one message based on its id
key. I am getting from the server another object like this:
{id: 2, name: 'newName2'}
The state is an array: (2) [{…}, {…}]
. I don't know which element with which index will be updated, I know only the id key inside the object.
How I can update object inside the state based on its key value ?
Share Improve this question edited Apr 20, 2019 at 23:00 halfer 20.4k19 gold badges109 silver badges202 bronze badges asked Feb 15, 2019 at 15:51 gdfgdfggdfgdfg 3,5768 gold badges46 silver badges85 bronze badges 2-
Maybe store them as key value pairs, or reduce your list to an object.
messages.reduce ((m,o) => ({...m,[o.name]:o}),{})['name1']
. You could also usemessages.find(({name})=>name=='name1')
– Moritz Roessler Commented Feb 15, 2019 at 15:57 - Did any of the answers work for you? Consider accepting one of them if that's the case. – Tholle Commented Feb 15, 2019 at 22:13
6 Answers
Reset to default 2You can use findIndex
to get the index of the object you want to update, and replace that with the new object in a new array and set that in your ponent state.
Example
class App extends React.Component {
state = {
messages: [{ id: 1, name: "name1" }, { id: 2, name: "name2" }]
};
updateMessage(newMessage) {
this.setState(prevState => {
const messages = [...prevState.messages];
const index = messages.findIndex(m => m.id === newMessage.id);
messages[index] = newMessage;
return { messages };
});
}
render() {
return (
<div>
{this.state.messages.map(message => (
<div key={message.id}>{message.name}</div>
))}
<button onClick={() => this.updateMessage({ id: 2, name: "newName2" })}>
Update message
</button>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare./ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare./ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
You may be better of storing them as {key:'value'}
pairs, if you need to look them up by a key.
You have a few options.
- If your key is the id, and matches the index, you can access it directly.
- Looping over your array
- Use
[].find
- transform your list to an object and look it up.
- use map
- or findIndex
- ..etc
let id = 1
let message = messages [id -1];
message.foo = 'bar';
let prop = 'name', key = 'name1'
for (const message of messages) if (message[prop] === key) message.foo = 'bar'
const byProp = (prop,key) => ({[prop]:k}) => k == key
const message = messages.find (byProp('name', 'name1'))
const byProp = (arr,prop) => arr.reduce ((obj, itm) => ({...obj, [itm[prop]]:itm}),{})
let message = byProp (messages, 'name')['name1']
This should work
const newMsg = { id: 10, message: 'hi' }
this.setState(({ messages } => {
return {
...messages.filter(x => x.id !== newMsg.id),
newMsg
}
};
Use Array.map
to modify your array
const messages = [
{id: 1, name: 'name1'},
{id: 2, name: 'name2'},
]
const updateById = obj => {
const { id } = obj;
// here we check if new object has the same id as the old one
// we replace old one with new
return messages.map(message => message.id === id ? obj : message)
}
console.log(
updateById({id: 1, name: 'newName'})
)
There are many ways to do this. One among them can be like below.
let x = [{id: 1, a: 1},{id: 2, b: 2}]
let newO = {id: 2, b: 3}
let y =[
...x.map(item => {
if (item.id === newO.id) {
return newO;
} else return item
})
]
console.log(y)
Here is a codesandbox that shows the code below in action.
Assuming you store your state
like this:
state = {
messages: [
{ id: 1, name: 'name1' },
{ id: 2, name: 'name2' },
{ id: 3, name: 'name3' }
]
}
Then, you can look for the message based on the id by using findIndex()
, but you also want to make sure that you update your state immutably. So, you can do the following:
changeMessage = (id, newName) => {
// Search messages for a message with the given id, and return index
// of the matching message in array, or -1 if not found.
const arrayIndex = this.state.messages.findIndex((message) => (message.id === id))
if (arrayIndex === -1) {
console.log('No message found for id ' + id)
return
}
// Copy over the messages from state to an array that
// you can manipulate without affecting this.state.messages
let updatedMessages = [...this.state.messages]
// Update the message located by index
updatedMessages[arrayIndex] = {
id,
name: newName
}
this.setState({
messages: updatedMessages
})
}
}