README
基于 hooks, context, immer 的 Redux 实现
Feature
- 简易: 简化了 redux 的使用方式, 仅有 action 及 state 的概念, 且遵循 redux 单向数据流, 数据驱动页面的设计思维;
- 轻量: 仅用 react 自带的 hook 及 context 实现, 源码仅有 20 行, 数据变更使用 immer 库;
- 高性能: 为了更颗粒的控制组件更新, 使用 immer 进行数据的设定, 虽然是不可变数据, 但是使用过程中是无感知的;
安装
$ yarn add @nuage/react-context-immer
编译
此库未编译, 也不愿意编译后发布, 使用请配置 webpack 的 babel:
@nuage/* 系列的库都都不会进行编译发布: 为了在不使用 Typescript 的前提下更好地利用 Javascript 的提示
// Process application JS with Babel.
// The preset includes JSX, Flow, TypeScript, and some ESnext features.
{
test: /\.(js|mjs|jsx|ts|tsx)$/,
// 此处添加 @nuage 的正则, 使得 @nuage/* 的库会被 babel 编译
include: [/@nuage/, paths.appSrc],
loader: require.resolve('babel-loader'),
...
}
基础使用
import createContextRedux from '@nuage/react-context';
const { store, Provider } = createContextRedux();
function actionOfChangeAge() {
// 发起一个 dispatch, 修改全局 state, 从而更新 注册了 context 的组件
store.dispatch(state => {
// state 是一个 immutable 对象, 请直接修改 state 的值, 而不是重构 state
state.age += 1;
});
}
function Sub() {
const { state } = React.useContext(store);
return <div>age: {state.age}</div>;
}
function App() {
return (
<Provider defaultState={{ age: 0 }}>
<Sub />
<button type="button" onClick={actionOfChangeAge}>
change age
</button>
</Provider>
);
}
异步更新
异步更新不需要引入任何新 API\中间键, 只需要在 action 中执行任何异步行为, 在异步结束之后进行更新
// action.js
import { store } from './createContext.js';
async function actionOfFetchUser() {
const info = await fetch(...);
// 在请求之后更新数据
store.dispatch(state => {
state.age += 1;
});
}
工程化
我们需要将 action 分离到公共区域, 组件只需要发起 action, 获得新的数据即可
1. 创建 store 及 Provider
// createContext.js
import createContextRedux from '@nuage/react-context';
const { store, Provider } = createContextRedux();
export { store, Provide };
2. 在项目顶部声明 Provide
// App.js
import { Provide } from './createContext.js';
import Changer from './Changer';
import Shower from './Shower';
function App() {
return (
<Provider defaultState={{ name: 'dog' }}>
<div>app</div>
<Changer />
<Shower />
</Provider>
);
}
3. 声明修改 state 的 action
// action.js
import { store } from './createContext.js';
export function actionOfChangeAge() {
store.dispatch(state => {
state.age = 500;
});
}
4. 实现两个组件, 跨组件更新
// Changer.js
import { actionOfChangeAge } from './action.js';
function Changer() {
return <button onClick={actionOfChangeAge}>click this change age</button>;
}
// Shower.js
import { store } from './createContext.js';
function Shower() {
// 注册 store
const { state } = React.useContext(store);
const { age } = state;
// 使用 userCallback 管理控制, 只有 age 修改时, 才会进行重绘
return React.useCallback(<div>age: {age}</div>, [age]);
}