Redox is a decentralized state management solution based on the concept of redux. Stores are created on demand, which prevents from initializing all of the stores at very first time.
- TypeScript friendly
- Easy and efficient.
- Use in Local and Global
- ES modules and tree-shaking support.
Install with npm:
npm install @shuvi/redox
Install with yarn
yarn add @shuvi/redox
import { defineModel } from '@shuvi/redox'
const count = defineModel({
name: 'count',
state: { count: 0 },
reducers: {
increment: (state, payload: number) => {
return {
value: state.value + payload,
}
},
},
})
import { defineModel } from '@shuvi/redox'
const filters = defineModel({
name: 'filters',
state: {
status: 'todo',
search: '',
},
reducers: {
updateStatus: (state, status: 'todo' | 'doing' | 'done') => {
return {
...state,
status,
}
},
updateSearch: (state, search: string) => {
return {
...state,
search,
}
},
},
})
const todo = defineModel(
{
name: 'todo',
state: {
todoList: [],
},
reducers: {
// update list by returning new value
add: (state, todo) => {
return {
...state,
todoList: [...state.todoList, todo],
}
},
// update by modifing state
remove: (state, id) => {
const index = state.todoList.findIndex((todo) => todo.id === id)
if (index >= 0) {
state.todoList.splice(index, 1)
}
},
},
actions: {
// asynchronous function
async fetchTodos() {
const resp = await fetch('https://example.com/todos')
const data = await response.json()
// predefined helper of reducer
this.$set({
todoList: data,
})
},
},
views: {
// value are cached based on state and $deps
filteredTodos() {
const filters = this.$dep.filters
return this.todoList.filter(
(todo) =>
todo.status === filters.status &&
todo.content.includes(filters.content)
)
},
finishedTodos() {
return this.todoList.filter((todo) => todo.status === 'done')
},
},
},
[filters] // defined depends
)
import * as React, { useEffect } from 'react'
import { useModel } from '@shuvi/redox-react'
function App() {
const [state, actions] = useModel(users)
useEffect(() => {
actions.fetchTodos()
}, [])
return (
<div>
{state.filteredTodos.map((todo) => (
<div>[{todo.status}]: {todo.content}</div>
))}
</div>
)
}
Name | Type | Description |
---|---|---|
name? |
string |
optional for useModel, required for useRootModel, useSharedModel and useRootStaticModel. Since name is treated as the key of cache , it should be unique . |
state |
object , string , number , boolean , array , undefined or null |
required . It could be any primitive type except bigint and symbol . |
reducers? |
object |
optional . Define your reducers here, the corresponding actions will be generated automatically . immer support out of the box. |
actions? |
object |
optional . Normally user defined actions have more complex logic than actions of reducers, like fetching data then dispatch actions. |
views? |
object |
optional . Functions in views have cache mechanism. It holds the returned value of functions. Upadte the cache if the state of dependencies has changed. |
optional
. It collects other models that the defined model depends on. Defined model would be aware of the change of state
if it ever happened in any of model dependencies.
The state does not limited to the object
, Redox also supports number
, string
, boolean
and array
as the state. The reason for doing this is because the best practice for Redox is to create the model for every component, using Redox everywhere for your state management.
Actions is where to arrange operations against state. They can be asynchronous.
const count = defineModel({
name: 'user',
state: {
user: null,
},
actions: {
async getUserInfo() {
const response = await fetch(`https://example.com/user/detail`)
const data = await response.json()
this.$set({
user: data,
})
},
},
})
The return value of view function is cached based on the state.
const todo = defineModel({
name: 'todo',
state: {
todos: [
{
status: 'todo',
},
],
},
views: {
finished(index: number) {
return this.todos.filter((todo) => todo.status === 'done')
},
fisrtFinished() {
return this.finished[0]
},
},
})
For now, Redox support two plugins. We will suppport more useful plugins in the future.