Skip to content

shuvijs/redox

Repository files navigation

redox

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.

Installation

Install with npm:

npm install @shuvi/redox

Install with yarn

yarn add @shuvi/redox

Usage

import { defineModel } from '@shuvi/redox'

const count = defineModel({
  name: 'count',
  state: { count: 0 },
  reducers: {
    increment: (state, payload: number) => {
      return {
        value: state.value + payload,
      }
    },
  },
})

Examples

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>
  )
}

defineModel(options, depends?)

options [object]

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.

depends? [array]

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.

Core Concepts

state

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

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,
      })
    },
  },
})

views

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]
    },
  },
})

React

Plugins

For now, Redox support two plugins. We will suppport more useful plugins in the future.

  • Logger: Prints out the related information for degguging.
  • Persist: Preserves the state of stores in the localStorage.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages