-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Summary: Pull Request resolved: #380 Introduce the concept of effects for Recoil Atoms based on [this proposal](https://fb.quip.com/bauvAeBEX5Ee). This is a similar concept of using React `useEffect()` for side-effects on components, only for atoms. It can be challenging to use `useEffect()` with Recoil atoms because the Recoil hierarchy is orthogonal to the React component hierarchy, and we have to worry about lifetime and singleton patterns. Recoil Atom Effects are an array of callbacks which will be called the first time the atom is used with a `<RecoilRoot>`, so they are always part of a React context. Atom Effects can be used for: * Synchronization with browser URI history * Persistence to local storage * Bi-directional synchronization with remote asynchronous state * Maintaining state history * other side-effects such as "set on get" * &c. # Proposed Atom Effects ``` type AtomOptions<T> = { key: string, default: T | RecoilValue<T> | Promise<T>, ... effects: $ReadOnlyArray<AtomEffect<T>>, }; // Effect is called the first time node is used with a <RecoilRoot> type AtomEffect<T> = ({ node: RecoilState<T>, trigger: 'get' | 'set', // Can call either synchronously to initialize value or async to change it later setSelf: (T | DefaultValue | (T => T | DefaultValue)) => void, resetSelf: () => void, getSnapshot: () => Snapshot, // Subscribe to events // Called when React batch ends, but before global RecoilTransactionObserver onSet: ((newValue: T | DefaultValue, oldValue: T | DefaultValue) => void) => void, }) => void | () => void; // Return optional cleanup handler ``` ### Current Diff This diff introduces a subset of the atom effect functionality: ``` // Effect is called the first time node is used with a <RecoilRoot> type AtomEffect<T> = ({ node: RecoilState<T>, trigger: 'get' | 'set', setSelf: (T | DefaultValue | (T => T | DefaultValue)) => void, resetSelf: () => void, getSnapshot: () => Snapshot, }) => void; ``` ### Example Usage Example use of an atom as a local cache of state that can be bi-directionally synchronized with remote async storage. ``` const myAtom = atom({ key: 'MyAtom', default: undefined, effects: [({node, setSelf, onSet}) => { const storage = getStorage(node.key); // set a value for synchronous init that overrides default setSelf(storage.get(value)); // Subscribe to storage updates storage.subscribe(value => setSelf(value)); // Subscribe local changes to update storage onSet(value => value === undefined ? storage.reset() : storage.set(value) ); // Subscribe to cleanup onCleanup(() => storage.unsubscribe()); }], }); ``` Reviewed By: csantos42 Differential Revision: D21919545 fbshipit-source-id: b500602d7ca91972d28790ee3f895517fdc52320
- Loading branch information
1 parent
765a56d
commit fb029cf
Showing
8 changed files
with
500 additions
and
107 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.