Skip to content

Instantly share code, notes, and snippets.

@myobie
Last active July 2, 2020 11:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save myobie/cc50f828cc074072410bb22d92d7ec58 to your computer and use it in GitHub Desktop.
Save myobie/cc50f828cc074072410bb22d92d7ec58 to your computer and use it in GitHub Desktop.
Make a little state object which can be updated through Immer's produce
import produce, { Draft, Immutable } from 'immer'
type Updater<S> = (state: Draft<S>) => void | S
type UpdateCallback<S> = (state: Immutable<S>) => void
type State<T> = {
current: Immutable<T>;
update: (updater: Updater<T>) => void;
onUpdate: (cb: UpdateCallback<T>) => void;
}
export default function<T> (initialState: T): State<T> {
let currentState: Immutable<T> = produce(initialState, draft => draft) as Immutable<T>
const callbacks: UpdateCallback<T>[] = []
return {
get current () {
return currentState
},
update (updater: Updater<T>) {
currentState = produce(currentState, updater) as Immutable<T>
callbacks.forEach(cb => {
cb(currentState)
})
},
onUpdate (cb: UpdateCallback<T>) {
callbacks.push(cb)
}
}
}
import createState from './create-state'
describe('createState', function () {
it('can be created', async function () {
const state = createState(5)
expect(state.current).to.equal(5)
})
it('can be partially updated', async function () {
const state = createState({
name: 'Alice',
age: 24
})
state.update(draft => {
draft.age += 1
})
expect(state.current.name).to.equal('Alice')
expect(state.current.age).to.equal(25)
})
it('can notify when updated', async function () {
const state = createState(1)
const values: number[] = []
state.onUpdate(newState => {
values.push(newState)
})
state.update(draft => ++draft)
state.update(draft => ++draft)
expect(values).to.eql([2, 3])
})
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment