Created
January 25, 2021 15:53
-
-
Save sgb-io/758b48e1f8eee0b423abdaa0fa42d4f5 to your computer and use it in GitHub Desktop.
Example Recoil Atom effect that syncs Atom states to the URL (search params).
This file contains hidden or 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
| import type { AtomEffect } from 'recoil' | |
| import qs from 'query-string' | |
| import { atomDefaults } from './defaults' | |
| const getStateFromUrl = () => { | |
| return qs.parse(window.location.search, { | |
| parseBooleans: true, | |
| parseNumbers: true, | |
| }) | |
| } | |
| // NOTE: This currently assumes that keys within each atom do not conflict | |
| const sendStateToUrl = (newState: Record<string, any>) => { | |
| const existingState = getStateFromUrl() | |
| const updatedState = { | |
| ...existingState, | |
| ...newState, | |
| } | |
| window.history.replaceState( | |
| updatedState, | |
| window.document.title, | |
| `?${qs.stringify(updatedState)}` | |
| ) | |
| } | |
| let urlState: Record<string, any> = {} | |
| // Note: this currently assumes that no keys will clash between atoms | |
| export const persistInputToUrl: AtomEffect<any> = ({ | |
| node, | |
| setSelf, | |
| onSet, | |
| trigger, | |
| }): void => { | |
| // On initial load, apply any existing URL state to the Atom | |
| if (trigger === 'get') { | |
| const existingState = getStateFromUrl() | |
| // Apply relevant existing URL state to this atom | |
| const startingState = Object.keys(atomDefaults[node.key]).reduce< | |
| Record<string, any> | |
| >((derivedState, stateKey) => { | |
| if (existingState[stateKey]) { | |
| derivedState[stateKey] = existingState[stateKey] | |
| } else { | |
| derivedState[stateKey] = atomDefaults[node.key][stateKey] | |
| } | |
| return derivedState | |
| }, {}) | |
| // Now that we have a full starting state, apply it | |
| setSelf(startingState) | |
| // Also re-write to the URL which ensures defaults that needed to be applied are reflected there, too | |
| sendStateToUrl(startingState) | |
| } | |
| // When changes are made to the Atom, send all properties into the URL | |
| onSet((newVal) => { | |
| urlState = { | |
| ...urlState, | |
| ...newVal, | |
| } | |
| sendStateToUrl(urlState) | |
| }) | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment