UNPKG

react-create-store

Version:

State management just using basic React hooks api within 80 lines of code 在80行代码内仅使用基本的 React hooks API 进行状态管理

258 lines (193 loc) 7.13 kB
# react-create-store > ! There is already [immer](https://www.npmjs.com/package/immer) and [use-immer](https://www.npmjs.com/package/use-immer) included inside > > ! only support ESM State management just using **basic React hooks api** within **80 lines** of code > 中文说明在下方 ## install `npm install react-create-store` or `yarn add react-create-store` ## Basic Usage Imagine you have a class, and split the **data, synchronous methods, and asynchronous methods/listeners** in it into three parts: **initialState, reducer, and useHook** ECCE React's way, hahaha!! > React expects that each time the data you modify is different from the last time > > In a class, what is always modified through "this" is always the object that was initially initialized, which is not convenient to implement reactivity and debugging in the development process, especially confronted with flexible data scenarios. So React hopes to solve this problem by means of a functional state machine, which is functionally equivalent to a class > > We just encapsulate the React api to make it more suitable for "declaring and using together like a class", and we don't modify its internal logic, so it can be achieved within 80 lines of code ### createStore ```Typescript // SomeStore.tsx // It is recommended to use the naming of XxxStore import createStore from "react-create-store" export default createStore( // 1. initialValue - data in class {name: "", password: ""}, // 2. reducer - synchronous methods in class (state, action: // we using partial interface instead of {type,action} Partial<{ changeName: string, changePassword: string }> )=>{ if(action.changeName !== undefined) state.name = action.changeName if(action.changePassword !== undefined) state.password = action.changePassword }, // 3. useHook - asynchronous methods/listeners in class (state, dispatch)=>{ useEffect(()=>{ console.log(state) },[state]) // ! state cannot read and directly modified after return // ! using dispatch to start reducer (just like thunk,vuex or other state management tools) return { changeNameDelay(val:string){ setTimeout(() => { dispatch({changeName: val}) }, 1000); } } } ) ``` Using file default export as an object ```Typescript import SomeStore from "./SomeStore" function Child(){ const [state, dispatch, async] = SomeStore.useReducer() // or just using dispatch/async // const dispatch = SomeStore.useDispatch() // const async = SomeStore.useAsync() return <input value={state.name} onChange={e=>{ dispatch({changeName: e.target.value}) // asynchronous: // async.changeNameDelay(e.target.value) }}/> } function App(){ return <SomeStore.Provider> <Child/> </SomeStore.Provider> } ``` ### BatchProviders Batch declaring providers in JSX the order of the providers parameter array is exactly the order of the context hierarchy ```Typescript function App(){ return <SomeStore.Provider> <OtherStore.Provider> {/* ... */} </OtherStore.Provider> </SomeStore.Provider> } ``` Equals to: ```Typescript import {BatchProviders} from "react-create-store" function App(){ return <BatchProviders providers={[SomeStore.Providers, OtherStore.Providers]}> {/* ... */} </BatchProviders> } ``` There is still complete ts hint in js [Stackblitz preview](https://stackblitz.com/edit/vitejs-vite-y1xsnw?file=src%2FApp.jsx) # 中文说明 > ! 内部已经包含 [immer](https://www.npmjs.com/package/immer) 和 [use-immer](https://www.npmjs.com/package/use-immer) > > ! 仅支持 ESM 在 **80 行** 代码内仅使用**基本的 React hooks API**进行状态管理 ## 安装 `npm install react-create-store` 或者 `yarn add react-create-store` ## 基本使用 想象你有一个 class,将其中的**数据,同步方法,和异步方法/监听器**拆分为三部分:**initialState,reducer 和 useHook** 这就是 React 的风格,哈哈哈!! > React 希望你每次修改的数据都和上一次不同 > > class 当中通过 this 修改的始终是最开始初始化的对象,这不方便实现响应式,以及开发过程中的调试,尤其是面对灵活数据场景,于是 React 希望借由函数式状态机解决这个问题,它在功能上与 class 是等效的 > > 我们仅仅是封装 React api,让它更加适合 ”像 class 一样在一起声明和使用“ 而已,并不修改其内部逻辑,因此可以在 80 行代码内实现 ### createStore ```Typescript // SomeStore.tsx // 推荐使用 XxxStore 命名 import createStore from "react-create-store" export default createStore( // 1. initialValue - class中的数据 {name: "", password: ""}, // 2. reducer - class中的同步方法 (state, action: // we using partial interface instead of {type,action} Partial<{ changeName: string, changePassword: string }> )=>{ if(action.changeName !== undefined) state.name = action.changeName if(action.changePassword !== undefined) state.password = action.changePassword }, // 3. useHook - class中的异步方法和监听器 (state, dispatch)=>{ useEffect(()=>{ console.log(state) },[state]) // ! return 之后,state 不可以被读取和直接修改 // ! 使用 dispatch 启动 reducer 修改 (就像 thunk,vuex 和其他状态管理工具一样) return { changeNameDelay(val:string){ setTimeout(() => { dispatch({changeName: val}) }, 1000); } } } ) ``` 使用文件默认导出作为对象 ```Typescript import SomeStore from "./SomeStore" function Child(){ const [state, dispatch, async] = SomeStore.useReducer() // 或者只使用 dispatch/async // const dispatch = SomeStore.useDispatch() // const async = SomeStore.useAsync() return <input value={state.name} onChange={e=>{ dispatch({changeName: e.target.value}) // 异步: // async.changeNameDelay(e.target.value) }}/> } function App(){ return <SomeStore.Provider> <Child/> </SomeStore.Provider> } ``` ### BatchProviders 在 JSX 中批量声明上下文 参数数组的顺序,正好是上下文层级的顺序 ```Typescript function App(){ return <SomeStore.Provider> <OtherStore.Provider> {/* ... */} </OtherStore.Provider> </SomeStore.Provider> } ``` 等于: ```Typescript import {BatchProviders} from "react-create-store" function App(){ return <BatchProviders providers={[SomeStore.Providers, OtherStore.Providers]}> {/* ... */} </BatchProviders> } ``` 在 js 中仍有完整的 ts 提示 [Stackblitz 演示](https://stackblitz.com/edit/vitejs-vite-y1xsnw?file=src%2FApp.jsx)