@acato/rx-state
v1.0.8
Published
Easy statemanagement without config, Contexts, etc.
Downloads
15
Readme
rx-state
Statemanagement without the hassle. No React Context, no reducers/actions/etc, no config, no store, just state.
Table of contents
Features
- Use state local and/or global
- Zoom in on state slices
- Set and get state outside React
- Subscribe to state changes (in and outside React)
- Use selectors
- Derived state
Installing
Using yarn:
yarn add @acato/rx-state
Using npm:
npm i @acato/rx-state
Examples
The state created with createRxState
can be used anywhere in your app. What I mean
by that is that createRxState
returns a hook which can be used anywhere inside a
React component, without having to use providers, contexts, etc. Besides that, it
returns three more functions: setState/setPartialState/setSharedState,
getState/getPartialState/getSharedState and subscribe (names are up to you). These
three functions can be used inside as well as outside of React.
To get or set state you will need to use a path, like 'todos.items'.
Create state:
const [setRxState, useRxState, getRxState, subscribe] = createRxState({
cart: { items: ['prod #1'] },
todos: { items: ['todo #1'] }
})
export { setRxState, useRxState, getRxState, subscribe }
Getting state
Get state without callback (hook):
const MyTodos = ({...rest}) => {
const todos = useRxState('todos.items')
...
return todos.map(...)
}
Get state with callback (hook):
const MyTodos = ({...rest}) => {
const todos = useRxState(items=> items.map(itm=> itm.toUpperCase()), 'todos.items')
...
return todos.map(...)
}
Get state with multiple 'selectors':
const MyComponent = ({...rest}) => {
const [todos, cartTotal] = useRxState((...data)=> [data[0].map(...), data[1].items.reduce(...)], ['todos.items', 'cart'])
...
return ...
}
Derived state:
const getFullName = user => `${user.firstName} ${user.lastName}`
const MyComponent = ({...rest}) => {
const userFullName = useRxState(getFullName, 'user')
...
return ...
}
Setting state
Set state:
const setTodos = setRxState('todos.items')
const MyTodoForm = ({...rest}) => {
...
return <button onClick={e=> setTodos(todos=> [...todos, 'new todo'])}>Add a todo</button>
}
Get state (js):
const doSomethingInteresting = () => {
const todos = getRxState('todos.items')
// doSomethingWithTodos(todos)
}
Subscribe to state changes
Subscribing to state changes can be useful when you want, for example, store some state in the browser's storage. Or maybe you want to execute some other logic whenever (a part of) state changes.
// Subscribe to a specific state slice:
const unsubscribe = subscribe((value) => {}, 'auth.token')
// or:
const unsubscribe = subscribe((value) => {}, 'auth')
// Subscribe to every state change:
const unsubscribe = subscribe((value) => {})
Bonus tips:
- The state can be used locally, shared or both.
- You can create your own little scoped api for managing a state-slice, like:
const setCart = setRxState('cart.items')
const cartApi = {
addItem: item=> setCart(items=> [...items, item]),
removeItem: item=> setCart(items => items.filter(...)),
etc...
}
API
The state module is built on top of rxjs and ramda. It allows consumers to get notified automatically whenever the subscribed state (top-level prop or nested props) changes.
Create (shared) state:
createRxState(initialValue) where initialValue ideally is an object literal.
const [setRxState, useRxState, getRxState, subscribe] = createRxState({
myslice: {
nested: {}
},
anotherSlice: 'yeah!'
})
It returns 4 functions:
- a set function for setting state (can be used outside React) with an optional default/initial value.
const setNestedState = setRxState('myslice.nested', 'my init value')
setNestedState((currentValue) => ({ ...currentValue, newKey: 'something' }))
setNestedState({ newKey: 'something' })
- a hook function for consuming (shared) state.
// most simple:
const myState = useRxState('myslice.nested')
// with setState callback
const myState = useRxState(value => ..., 'myslice.nested')
// multiple selectors, with callback
const myState = useRxState((...values) => ..., ['myslice.nested', 'otherslice.items'])
- a get function for getting state, outside of React.
const doSomething = (...args) => {
const nestedState = getRxState('myslice.nested')
...
}
- a subscribe function for subscribing to state changes, in or outside of React. It returns an unsubscribe function. The subscribe function is most useful used outside of React, because there already is a hook function which subscribes to state. You can subscribe to specific state slices or the whole state tree.
// Or to subscribe to specific state changes.
const unsubscribe = subscribe((value) => {}, 'auth')
// Or to subscribe to all state changes.
const unsubscribe = subscribe((value) => {})
// Unsubscribe:
unsubscribe()