facebookexperimental / Recoil

Recoil is an experimental state management library for React apps. It provides several capabilities that are difficult to achieve with React alone, while being compatible with the newest features of React.
https://recoiljs.org/
MIT License
19.5k stars 1.18k forks source link

Atom state seems to be locked as read-only when using objects on Expo 49 #2281

Open mphill opened 10 months ago

mphill commented 10 months ago

Simple reproduction repo:

https://github.com/mphill/recoil-readonly

I recently upgraded to Expo 49 which is based on the following:

  "react": "18.2.0",
  "react-native": "0.72.4",

I noticed my recoil states that contain objects cannot be modified, only primitives seem to work as expected. Everything was working as expected in Expo 48.

Normally when updating the objects I would do something like this:

const copy = [...original];

copy[0].options[0].enabled = true; // indexes are hard coded for this example;

setConfig(copy);

Now the property will remain false, it can not be changed.

The only way I could work around this was to make a clone method:

function clone<T>(value: T): T {
    return JSON.parse(JSON.stringify(value)) as T;
}

const copy = clone(original);

copy[0].options[0].enabled = true; // indexes are hard coded for this example;

setConfig(copy);

// Now it works as expected

You can see this in the reproduction repo:

// Doesn't work
            <Button
                title="Enable AC (spread operator)"
                onPress={() => {
                    const newCars = [...cars];
                    newCars[0].options[0].selected = true;
                    setCars(newCars);
                }}
            />

// Works
            <Button
                title="Enable AC (dirty clone)"
                onPress={() => {
                    const newCars = clone(cars);
                    newCars[0].options[0].selected = true;
                    setCars(newCars);
                }}
            />