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