npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

react-elf

v0.1.3

Published

Manage your project states like redux with react hooks

Downloads

5

Readme

react-elf

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

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

特点: 使用简单;体积小;支持Immutable数据; 支持订阅指定数据字段

1. 数据注册(Store Register)

  • Router节点之前注册 Store 这样可以保证Store中的数据可以用于任何位置
import ReactDom from 'react-dom';
import Store from 'react-elf';
import reducer from './reducer.js';
/**
interface StoreProps {
    reducers: Array<ReducerPiece>,
    
    // getValueFromState:[v0.1.3 支持] 自定义从state中获取指定字段的值(适用于从复杂对象中获取值:如Immutable对象中取值)
    // 该方法为可选:
    // 1、在Store 属性中指定的getValueFromState 方法是用于所有状态切片的取值
    // 2、在reducer指定的getValueFromState 方法会覆盖Store中指定的取值方法;
    getValueFromState?: GetValueFromState
}

// 注册方式:传入一个属性 reducers: Array<ReducerPiece>
/**
interface ReducerPiece {
    reducer: Reducer<ReducerState<any>, Action>,
    name: StatePieceName,
    init: any,
    
    // 该方法会覆盖Store 中指定的getValueFromState, 可以只针对于一个数据片段指定取值方法;
    getValueFromState?: GetValueFromState, // 0.1.3 版本支持
    initializer?: (arg: any) => ReducerStateWithoutAction<ReducerWithoutAction<any>>
}

// 返回当前State 中指定字段的值
type GetValueFromState = (state: any, field: any) => any;
*/

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

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

2. 创建reducer

  • reducers 只是一个存放reducer的数组;这里描述如何创建一个reducer:
// './reducer.js'

/**
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: 'D',
    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'

/**
// 分发器定义
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>
    );
}

Immutable 数据使用示例

// usage::
const TestMapData: FC = () => {
    const [[value], dispatch] = useElfSubscribe('example-m', [['complexData', 'value']]);

    return (
        <div>
            <span>订阅的Map 数据:{value}</span>
            <button onClick={() => dispatch('updateComplexValue', Math.random())}>更新Map 数据</button>
        </div>
    );
};

// reducer data::
const MapState: Map<string, any> = Map({
    key: 'Foo',
    value: 99
});

const Init: Record.Factory<StateType> = Record({
    name: 'record-state demo',
    count: 0,
    complexData: MapState
}, 'DEMO_STATE');


// 示例 Immutable 数据:
function getValueFromState(state, field) {
    return state.getIn(Array.isArray(field) ? field : [field]);
}

const reducers: Array<ReducerPiece> = [
    {
        reducer,
        name: 'example-m',
        init: new Init(),
        getValueFromState(state, field) {
            return state.getIn(Array.isArray(field) ? field : [field]);
        }
    },
];