Reputation: 377
Codesandbox to the problem: https://codesandbox.io/s/serverless-thunder-6gj04?file=/src/store.js
I have the following store:
class PersonStore {
persons = [];
constructor() {
makeAutoObservable(this, {}, { autoBind: true });
}
*fetchPersons() {
const response = yield fetch(
"https://random-data-api.com/api/users/random_user?size=5"
);
this.persons = yield response.json();
}
}
export default new PersonStore();
Now, I want to update persons inside the person-list.
When I update a single field on on items inside the array like this it works as expected and the UI updates:
update(id) {
let updated = this.persons.find((p) => p.id === id);
// This works...
updated.first_name = "FOO";
}
However, in the future I would like to pass more complex, updated data into this function. So my idea was to basically assign a totally new object with the updated values in the list.
Unfortunately, this does not work as I expected it:
update(id) {
let updated = this.persons.find((p) => p.id === id);
// This does not work...
const dummy_person = { first_name: 'foo', last_name: 'bar', id: 99 }
updated = dummy_person
}
My first guess was that this does not work because the objects inside the array are not "normal objects" but observables. So I created a model for the persons:
class Person {
id = null;
first_name = "";
last_name = "";
constructor() {
makeAutoObservable(this);
this.first_name = "FOO";
this.last_name = "BAR";
}
}
...but this does still not work...
update(id) {
let updated = this.persons.find((p) => p.id === id);
// This does not work...
const dummy_person = new Person()
updated = person
}
How can I "replace" an object inside the array here with an object containing the updated data?
Upvotes: 1
Views: 12716
Reputation: 18476
As @Tholle said in the comment, you are only updating local variable, not actual object.
In simpler words this is what's happening inside your update
function:
let updated = this.persons.find((p) => p.id === id);
- you create local variable updated
and assign some object (person) to it
const dummy_person = { first_name: 'foo', last_name: 'bar', id: 99 }
- you create dummy object and assign it to local dummy_person
constant
updated = dummy_person
- here you assign dummy_person
value to updated
variable. Basically you only reassign value of updated
variable, you are not changing the person-object, but only changing to what value updated
variable points.
Sometimes people explain it with boxes, like imagine that updated
is a box and at first you put person
inside of it and then changed you mind and put dummy_person
inside, but actual person
wasn't changed.
So what can you do?
As @Tholle said, you can use splice
to change persons
array, it will basically throw away old person and insert new one.
Or if you actually want to update old person you could use Object.assign(updated, dummy_person)
Or you could use map
(although it will reassign whole array, might be unnecessary sometimes):
update(id) {
const dummy_person = { first_name: 'foo', last_name: 'bar', id: 99 };
this.persons = this.persons.map(person => person.id === id ? dummy_person : person);
}
There is a lot what you can do, depends on what you what. The main thing is understand how reactivity works!
More about this topic in the docs: https://mobx.js.org/understanding-reactivity.html
Upvotes: 4