optice v0.2.0
Readme
Optice
Like redux, but no reducers, no actions
Usage
npm install opticeimport { L, createStore } from 'optice'
const initialState = {
user: {
name: '',
email: '',
},
company: {
name: '',
okato: 0,
}
}
const store = createStore(initialState)
const userLens = L.prop('user')
const companyLens = L.prop('company')
const nameLens = L.prop('name')
const emailLens = L.create(
(state) => state.email,
(email) => (state) => ({ ...state, email }),
)
// same as `L.prop('email')`
const userNameLens = L.compose(userLens, nameLens)
const companyNameLens = L.compose(companyLens, nameLens)
const fetchUser = async () => ({ name: 'Foo Bar', email: 'foo.bar@company.com' })
const loadUser = () => async ({ updateState }) => {
updateState(userLens, await fetchUser())
}In console should be this output:
BEFORE { name: '', email: '' } { name: '', okato: 0 }
UPDATE { name: 'Foo Bar', email: 'foo.bar@company.com' } { name: '', okato: 0 }
UPDATE { name: 'Foo Bar', email: 'foo.bar@company.com' } { name: 'Company', okato: 0 }API
createStore
createStore(initialState): StoreCreate new store object.
Store.execute
store.execute(command: Function, ...args: any[]): resultRun command function with store methods ({ getState, setState, updateState, readState, execute }) and passed arguments.
Immediatly return result of command.
const command = (a, b) => ({ updateState, readState, execute }) => {
// read, update state
// or execute another command
return 1 + a + b
}
store.execute(command, 2, 1) === 4Store.getState
store.getState(): StateJust return current state
Store.readState
store.readState(lens: Lens): ValueRead value from state through lens.
const lens = L.prop('data')
const initialState = {
data: 1
}
const store = createStore(initialState)
const value = store.readState(lens)
console.assert(value === 1)Store.setState
store.setState(newState: State): voidIt notify all subscribers. Replace state, returns nothing.
const initial = { a: 1, b: 2 }
const store = createStore(initial)
store.subscribe(state => {
console.log('updated')
console.assert(state.a === 5)
})
store.setState({ a: 5, b: 10 })Store.subscribe
store.subscribe(listener: Function): FunctionAdd listener to subscribers list, returns unsubscribe function.
const store = createStore({ a: 1 })
const unsubscribe = store.subscribe(state => {
console.log('update', state)
})
store.setState({ a: 2 }) // > update { a: 2 }
unsubscribe()
store.setState({ a: 3 }) // nothingStore.updateState
store.updateState(lens: Lens, valueOrFunc: any | Function): voidIt notify all subscribers. Update piece of state through lens.
If function passed update state with L.over, else use L.write to just set value.
const lens = L.prop('a')
const store = createStore({ a: 1 })
store.updateState(lens, 2)
console.assert(store.getState().a === 2)
store.updateState(lens, value => value + 1)
console.assert(store.getState().a === 3)L.create
L.create(getter: Function, setter: Function): LensCreate new lens.
Getter is just function that received state. Should return piece of state.
Setter is function that received passed value, return function that received state. Should return new version of passed state.
Getter and Setter should be pure functions.
const lens = L.create(
state => state.value,
value => state => ({ ...state, value }),
)L.view
L.view(state: State, lens: Lens): anyRead value from state through lens.
const lens = L.create(
state => state.value,
value => state => ({ ...state, value }),
)
const state = { value: 'foo' }
const value = view(state, lens)
console.assert(value === 'foo')L.write
L.write(state: State, lens: Lens, value: any): StateImmutable update piece of state through lens. Return new version of state.
const state = { foo: { bar: 1 } }
const fooLens = L.prop('foo')
const barLens = L.prop('bar')
const fooBarLens = L.compose(fooLens, barLens)
const newState = L.write(state, fooBarLens, 2)
console.assert(newState.foo.bar === 2)L.over
L.over(state: State, lens: Lens, fn: (value) => value): StateLike L.write but use function to update value. Return new version of state.
const state = { foo: 100 }
const fooLens = L.prop('foo')
const updater = (value) => value + value
const newState = L.over(state, fooLens, updater)
console.assert(L.read(state, fooLens) === 200)L.compose
L.compose(...lenses: Lens[]): LensL.compose can be used only for this lenses
Perform lens composition. Returns one lens.
If passed no lens, returns empty lens L.create(s => s, v => s => s).
If passed one lens, returns its.
const a = L.create(
state => state.a,
value => state => ({ ...state, a: value })
)
const b = L.create(
state => state.b,
value => state => ({ ...state, b: value })
)
const ab = L.compose(a, b)
// same as
const ab2 = L.create(
state => state.a.b,
value => state => ({ ...state, a: { ...state.a, b: value } }),
)L.prop
L.prop(name: string): LensMakes lens to read/write property.
const fooLens = L.prop('foo')
// Same as
const fooLens2 = L.create(
state => state.foo,
value => state => ({ ...state, value: foo })
)