effector / effector

Business logic with ease ☄️
https://effector.dev
MIT License
4.6k stars 238 forks source link

Question about immutability #1136

Open mkhoussid opened 2 months ago

mkhoussid commented 2 months ago

Suppose the following:

const $store = createStore({});
const onChange = createEvent();

$store.on(onChange, (state, payload) => {
    console.log(state === $store.getState()); // true
    return payload
})

onChange({ isNew: true });

The console.log above prints true. Is it ok to mutate the object in such a case or do I have to make a clone?

i.e, do I do this,

const $store = createStore({ isNew: false });
const onChange = createEvent();

$store.on(onChange, (state, { isNew }) => {
    state.isNew = isNew;

    return state;
})

onChange({ isNew: true });

or this,

const $store = createStore({ isNew: false });
const onChange = createEvent();

$store.on(onChange, (state, { isNew }) => {
    const newStore = { ...state };
    newStore.isNew = isNew;

    return newStore;
})

onChange({ isNew: true });
velialiev commented 2 months ago

@mkhoussid, store subscribers receive updates whenever the store value changes and new store value is not equal to the old one. By default, effector doesn't compare objects by their structure and uses the equality operator for this purpose. If you return an object with the same reference, effector will not be able to know about changes you applied to it, so store subscribers won't receive this updates. You need to either change the object reference or pass your custom updateFilter to the createStore function, which will compare objects by it's structure. updateFilter solution is not a common way, since it changes the core behavior of the store but it's up to you to decide which solution to choose

You can also use Immer for RTK/Mobx-like behavior allowing you to mutate objects