-
I'm trying to create an atom that is derived from another atom. When the source atom changes, the derived atom should also update. In the meantime, the atom can also be overridden. But when the source atom changes again, the override should be lost. You could have a source atom that is fetched from the network. That should be the source for the derived atom. But, the user can overwrite the derived atom, until the next fetch happens, in which case the network value should have priority (and the overridden value is lost). For example, you might get weather data from the network, and if it's raining, you want to automatically turn on the windshield wipers. However, the user can also manually override the windshield wiper setting, so turn them off, for example. But the next time the weather data is fetched from the network, the wipers should turn back on automatically. const weatherData = atomWithRefresh(() => fetch('/weather'));
const windshieldWipersOn = ((get) => {
return get(weatherData).isRaining;
}, (get, set, update) => {
set(windshieldWipersOn, update);
}); The problem I'm facing is that if an atom has a read function (as opposed to a hardcoded read value), it cannot be written to ( I tried working around that by having an internal value atom and an action atom: const weatherData = atomWithRefresh(() => fetch('/weather'), ...);
const isRaining = ((get) => get(weatherData).isRaining);
const windshieldWipersOverride = atom(undefined);
const windshieldWipersOn = ((get) => {
return get(windshieldWipersOverride) ?? get(isRaining);
}, (get, set, update) => {
set(windshieldWipersOverride, update);
}); But of course now the Any pointers are much appreciated. |
Beta Was this translation helpful? Give feedback.
Replies: 5 comments 7 replies
-
Is https://jotai.org/docs/recipes/atom-creators#atomwithrefreshanddefault related? Maybe not. I think what you describe is not truly declarative. For such impure cases, often the escape hatch is |
Beta Was this translation helpful? Give feedback.
-
Hmm I might be on to something...might just be a brain fart const atomWithAutoReset = (getter: any) => {
let overwrittenValue: any = undefined;
const counter = atom(0);
return atom(
(get) => {
const originalValue = getter(get);
get(counter); // subscribe to auto-reload
const overwritten = overwrittenValue;
overwrittenValue = undefined;
return overwritten ?? originalValue;
},
(get, set, args) => {
overwrittenValue = args;
set(counter, (count) => count + 1);
}
);
}; ( This "caches" the overwritten value in a regular JS variable, because that can be read from and written to from anywhere. Then it increments the counter to let re-run the read function so that any subscribers of this atom know the value changed. Since the overwritten value is set, it returns that, but also clears the overwritten value, so that next time the read function runs, it takes the value from the parent instead of the overwritten one. @dai-shi does my code make sense? Is it a good idea? 😄 Edit: Had a wrong value assignment in the code |
Beta Was this translation helpful? Give feedback.
-
It's not declarative if you can't determine which one should be the result, the source atom or the overridden atom. |
Beta Was this translation helpful? Give feedback.
-
I would say that it's a good recipe. I like when docs showing you problems and approach to solve it. |
Beta Was this translation helpful? Give feedback.
-
its great, l like it |
Beta Was this translation helpful? Give feedback.
Hm, I think you can keep "what you are overriding".
In this case, we don't need timestamps.