Like redux, but no reducers
, no actions
npm install optice
import { 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 }
createStore(initialState): Store
Create new store object.
store.execute(command: Function, ...args: any[]): result
Run command function with store methods ({ 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) === 4
store.getState(): State
Just return current state
store.readState(lens: Lens): Value
Read 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(newState: State): void
It 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(listener: Function): Function
Add 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 }) // nothing
store.updateState(lens: Lens, valueOrFunc: any | Function): void
It 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(getter: Function, setter: Function): Lens
Create 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(state: State, lens: Lens): any
Read 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(state: State, lens: Lens, value: any): State
Immutable 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(state: State, lens: Lens, fn: (value) => value): State
Like 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.view(state, fooLens) === 200)
L.compose(...lenses: Lens[]): Lens
L.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(name: string): Lens
Makes lens to read/write property.
const fooLens = L.prop('foo')
// Same as
const fooLens2 = L.create(
state => state.foo,
value => state => ({ ...state, value: foo })
)