react-elf

Manage your project states like redux with react hooks

Usage no npm install needed!

<script type="module">
  import reactElf from 'https://cdn.skypack.dev/react-elf';
</script>

README

react-elf 状态管理器使用说明

该状态管理器是对react-hooks 的一种封装, 能让你像使用hooks一样的方式,来管理你项目的状态。实现同react-redux相同的功能;

特点: 1. 简单

1. 数据注册(Store Register)

  • Router节点之前注册 Store 这样可以保证Store中的数据可以用于任何位置
import ReactDom from 'react-dom';
import Store from 'react-elf';
import reducer from './reducer.js';
// 注册方式: 只需要传入一个属性 reducers: Array<ReducerPiece>
// interface ReducerPiece {
//     reducer: Reducer<ReducerState<any>, Action>,
//     name: StatePieceName,
//     init: any,
//     initializer?: (arg: any) => ReducerStateWithoutAction<ReducerWithoutAction<any>>
//   }

const App = () => {
    return (
        <>
            <Store reducers={[reducer]} />
            <Router />
        </>
    );
};

ReactDom.render(<App />, document.getElementById('root'));

2. 创建reducer

  • reducers 只是一个存放reducer的数组;这里描述如何创建一个reducer:
// './reducer.js'
// TS类型描述:
/**
export interface Action {
    type: string;
    payload?: any;
    error?: boolean;
    meta?: any;
}
*/
function reducer(state, action) {
    switch (action.type) {
        case 'increase':
            return { ...state, count: action.payload };

        default:
            return state;
    }
}


const init = {
    name: 'example',
    count: 0
};

/**
export interface ReducerPiece {
    reducer: Reducer<ReducerState<any>, Action>;
    name: StatePieceName;
    init: any;
    initializer?: (arg: any) => ReducerStateWithoutAction<ReducerWithoutAction<any>>;
}
*/
export default {
    reducer,
    name: 'example',
    init
};

3. 订阅数据,当数据修改时更新当前组件 (useElf 数据订阅)

import {useElf} from 'react-elf'

// TS ElfDispatch:
// type ElfDispatch = (x: string | Action, payload?: any) => void;

const Decreace = ({ children }) => {
    const [{ count }, dispatch] = useElf('example');

    function onIncrease() {
        // 更新状态的方式:传递两个参数,第一个参数是action的类型Type, 第二个参数是携带的数据;
        dispatch('increase', count - 1);
        
        // 一般用于不需要传递 payload 的情况下,更新状态的方式:传递一个action对象 [关于action的标准可以参考: https://github.com/redux-utilities/flux-standard-action]
        // dispatch({type: 'increase', payload: count - 1 });
    }

    return (
        <button style={{margin: 20}} onClick={onIncrease}>
            {children}
        </button>
    );
}

4. 如果只想订阅某个数据片段中的一部分值

// 你可以像这样使用:
import {useElfSubscribe} from 'react-elf';

// TS useElfSubscribe 描述:
// declare function useElfSubscribe(name: StatePieceName, subscribableFields: any | any[]): [any[], ElfDispatch];

const Count = () => {
    const [[count]] = useElfSubscribe('example', 'count');

    return <div>{count}</div>;
}


// 如果需要订阅多个字段,可以像下面这样传递一个数组;
// Note: useElfSubscribe 只会按顺序,返回订阅的数据,在当前数据切片中的其它数据并不会反回;
// 支持使用"name-path"
// const [[count, name, id], dispatch] = useElfSubscribe('example', ['count', 'name', 'arr[0].data.id']);
注意:这里有些需要注意的问题,如果你订阅的数据是引用型变量,请确保在更新状态的时候该引用型变量的改变;(这个问题是由于在判定状态值是否改变使用的是浅比较[Object.is])
一般建议订阅引用型变量内部的基本类型的值;例如: `useElfSubscribe('example', ['pagination.size', 'pagination.current']) 等
如果不方便按照此种方法订阅值的更新,建议使用 useElf 订阅数据;

5. 如果,只想获取某个数据片段,并不想订阅数据更新(当订阅的数据变更时并不会通知当前组件更新)

// 你可以像这样使用:
import {getElfState} from 'react-elf';

const NoSubscribeData = () => {
    const {count} = getElfState('example');

    return (
        <div>
            <span>这里的数据并不会动态更新:</span>
            <span>{count}</span>
        </div>
    );
}

6. 如果,只想获取某个数据片段的分发器(更新某个数据片段的[dispatch])不需要数据,也不需要订阅数据更新

import {getElfDispatch} from 'react-elf';

const Increace = ({ children }) => {
    const dispatch = getElfDispatch('example');

    function onIncrease() {
        const state = getElfState('example');
        dispatch('increase', state.count + 1)
    }

    return (
        <button onClick={onIncrease}>
            {children}
        </button>
    );
}