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

luban-store

v0.0.1

Published

Lightweight library to manage the app state with a centralized store

Downloads

12

Readme

luban-store

Lightweight library to manage the app state with a centralized store

安装

使用 luban-store 需要 React 在 16.8.0 版本以上。

$ npm install luban-store --save

简介

luban-store 是基于 React Hooks 实现的轻量级状态管理框架,具有以下特征:

  • 简单、熟悉的 API:不需要额外的学习成本,只需要声明模型,然后 useModel
  • 支持组件 Class 写法:友好的兼容策略可以让老项目享受轻量状态管理的乐趣;
  • 集成异步处理:记录异步操作时的执行状态,简化视图中对于等待或错误的处理逻辑;
  • 良好的 TypeScript 支持:提供完整的 TypeScript 类型定义,在 VS Code 中能获得完整的类型检查和推断。

快速开始

让我们使用 luban-store 开发一个简单的 Todo 应用,包含以下几个步骤:

第一步:定义模型

export const todos = {
  state: {
    dataSource: [],
  },
  actions: {
    async fetch(prevState, actions) {
      await delay(1000);
      const dataSource = [
        { name: 'react' },
        { name: 'vue', done: true},
        { name: 'angular' },
      ];
      return {
        ...prevState,
        dataSource,
      }
    },
    add(prevState, todo) {
      return {
        ...prevState,
        dataSource: [
          ...prevState.dataSource,
          todo,
        ]
      };
    },
  },
};

第二步:创建 Store

import { createStore } from 'luban-store';
import * as models from './models';

export default createStore(models);

第三步:挂载 Store

import React from 'react';
import ReactDOM from 'react-dom';
import store from './store';

const { Provider } = store;

ReactDOM.render(
  <Provider>
    <App />
  </Provider>,
  rootEl
); 

第四步:消费模型

import React, { useEffect } from 'react';
import store from './store';

const { useModel } = store;

function Todos() {
  const [ state, actions ] = useModel('todos');
  const { dataSource } = state;
  const { fetch, add } = actions;

  useEffect(() => {
    fetch();
  }, []);

  function onAdd(event, name) {
    if (event.keyCode === 13) {
      add({ name: event.target.value });
      event.target.value = '';
    }
  }

  return (
    <div>
      <ul>
        {dataSource.map(({ name, done }, index) => (
          <li key={index}>
            <label>
              {done ? <s>{name}</s> : <span>{name}</span>}
            </label>
          </li>
        ))}
      </ul>
      <div>
        <input
          onKeyDown={onAdd}
          placeholder="Press Enter"
        />
      </div>
    </div>
  );
}

API

createStore

createStore(models)

该函数用于创建 Store,将返回一个 Provider 和一些 Hooks。

import { createStore } from 'luban-store';

const store = createStore(models);
const { Provider, useModel, withModel } = store;

入参

models

import { createStore } from 'luban-store'

const counterModel = {
  state: {
    value: 0
  },
};

const models = {
  counter: counterModel
};

createStore(models)

state

state: any:必填

该模型的初始 state。

const model = {
  state: { loading: false },
};

actions

actions: { [string]: (prevState, payload, actions, globalActions) => any }

一个改变该模型 state 的所有函数的对象。这些函数采用模型的上一次 state 和一个 payload 作为形参,并且返回模型的下一个状态。

const counter = {
  state: 0,
  actions: {
    add: (prevState, payload) => prevState + payload,
  }
};

action 可以是异步的:

const counter = {
  actions: {
    async addAsync(prevState, payload) => {
      await delay(1000);
      return prevState + payload;
    },
  }
};

可以在返回前执行另一个 action 或者另一个模型的 actions:

const user = {
  state: {
    foo: [],
  }
  actions: {
    like(prevState, payload, actions, globalActions) => {
      actions.foo(payload); // 调用本模型的 foo
      globalActions.user.foo(payload); // 调用其他模型的 foo
      
      // 做一些操作

      return {
        ...prevState,
      };
    },
    foo(prevState, id) {
      // 做一些操作

      return {
        ...prevState,
      };
    },
  }
};

返回值

Provider

Provider(props: { children, initialStates })

将 Store 挂载到 React 应用,以便组件能够通过 Hooks 使用 Store 并与 Store 进行交互。

import React from 'react';
import ReactDOM from 'react-dom';
import { createStore } from 'luban-store';

const { Provider } = createStore(models);
ReactDOM.render(
  <Provider>
    <App />
  </Provider>,
  rootEl
); 

useModel

useModel(name: string): [ state, actions ]

在组件内使用模型实例。

const counter = {
  state: {
    value: 0
  },
  actions: {
    add: (prevState, payload) => ({...prevState, value: prevState.value + payload}),
  }
};

const { userModel } = createStore({ counter });

function FunctionComponent() {
  const [ state, actions ] = userModel('name');

  state.value; // 0

  actions.add(1); // state.value === 1
}

useModelActions

useModelActions(name: string): actions

useModelActions 提供了一种只使用模型的 actions 但不订阅模型更新的的方式。

function FunctionComponent() {
  const actions = useModelActions('name');
  actions.add(1);
}

useModelActionsState

useModelActionsState(name: string): { [actionName: string]: { isLoading: boolean, error: Error } }

使用 useModelActionsState 来获取模型异步 Action 的执行状态。

function FunctionComponent() {
  const actions = useModelActions('name');
  const actionsState = useModelActionsState('name');

  useEffect(() => {
    actions.fetch();
  }, []);

  actionsState.fetch.isLoading // 异步 Action 是否在执行中
  actionsState.fetch.error // 异步 Action 执行是否有误,注意仅当 isLoading 为 false 时这个值才有意义
}

withModel

withModel(name: string, mapModelToProps?: (model: [state, actions]) => Object = (model) => ({ [name]: model }) ): (React.Component) => React.Component

使用 withModel 来连接模型和 Class Component。

class TodoList extends Component {
  render() {
    const { counter } = this.props;
    const [ state, actions ] = counter;
    const { dataSource } = state;
    
    state.value; // 0

    actions.add(1);
  }
} 

export default withModel('counter')(TodoList);

协议

MIT