Skip to content

Instantly share code, notes, and snippets.

@sgb-io
Created January 25, 2021 15:53
Show Gist options
  • Select an option

  • Save sgb-io/758b48e1f8eee0b423abdaa0fa42d4f5 to your computer and use it in GitHub Desktop.

Select an option

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).
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