All Projects → yisbug → Iostore

yisbug / Iostore

极简的全局数据管理方案,基于 React Hooks API

Programming Languages

javascript
184084 projects - #8 most used programming language

Projects that are alternatives of or similar to Iostore

Flooks
🍸 A state manager for React Hooks
Stars: ✭ 201 (+103.03%)
Mutual labels:  hooks, state, store
RxReduxK
Micro-framework for Redux implemented in Kotlin
Stars: ✭ 65 (-34.34%)
Mutual labels:  state, store
jedisdb
redis like key-value state management solution for React
Stars: ✭ 13 (-86.87%)
Mutual labels:  hooks, state
atomic-state
A decentralized state management library for React
Stars: ✭ 54 (-45.45%)
Mutual labels:  hooks, state
react-cool-form
😎 📋 React hooks for forms state and validation, less code more performant.
Stars: ✭ 246 (+148.48%)
Mutual labels:  hooks, state
vue
Vue integration for Nano Stores, a tiny state manager with many atomic tree-shakable stores
Stars: ✭ 25 (-74.75%)
Mutual labels:  state, store
eventrix
Open-source, Predictable, Scaling JavaScript library for state managing and centralizing application global state. State manage system for react apps.
Stars: ✭ 35 (-64.65%)
Mutual labels:  hooks, state
vue-reactive-store
A VueX alternative : declarative + reactive + centralized way to structure your data store. Inspired by VueX and Vue.js . Compatible with vue-devtools.
Stars: ✭ 27 (-72.73%)
Mutual labels:  state, store
Reatom
State manager with a focus of all needs
Stars: ✭ 567 (+472.73%)
Mutual labels:  state, store
Pullstate
Simple state stores using immer and React hooks - re-use parts of your state by pulling it anywhere you like!
Stars: ✭ 683 (+589.9%)
Mutual labels:  hooks, state
Tng Hooks
Provides React-inspired 'hooks' like useState(..) for stand-alone functions
Stars: ✭ 954 (+863.64%)
Mutual labels:  hooks, state
useSharedState
useSharedState is a simple hook that can be used to share state between multiple React components.
Stars: ✭ 0 (-100%)
Mutual labels:  hooks, state
deep-state-observer
State library for high performance applications.
Stars: ✭ 25 (-74.75%)
Mutual labels:  state, store
teaful
🍵 Tiny, easy and powerful React state management
Stars: ✭ 638 (+544.44%)
Mutual labels:  state, store
okito
Your best flutter coding friend. All in one; state management, navigation management(with dynamic routing), local storage, localization, dependency injection, cool extensions with best usages and with the support of best utilities!
Stars: ✭ 37 (-62.63%)
Mutual labels:  state, store
knockout-store
State management for Knockout apps.
Stars: ✭ 37 (-62.63%)
Mutual labels:  state, store
Svelte Store Router
Store-based router for Svelte
Stars: ✭ 54 (-45.45%)
Mutual labels:  state, store
mafuba
Simple state container for react apps.
Stars: ✭ 20 (-79.8%)
Mutual labels:  state, store
boutique
Immutable data storage
Stars: ✭ 44 (-55.56%)
Mutual labels:  state, store
Westore
更好的小程序项目架构
Stars: ✭ 3,897 (+3836.36%)
Mutual labels:  state, store

iostore

NPM version build status Test coverage Known Vulnerabilities David deps

背景介绍

由原 react-hooks-model 更名为 iostore

极简的全局数据管理方案,忘掉 reduxstatereduceractionobserver 这些复杂的概念吧。

特性

  • 总计只有 100 多行代码。
  • 只需要学会两个 API 即可使用,非常简单:createStore()useStore()
  • 像普通的 js 对象一样定义 store
  • 像普通的 js 对象一样使用数据和方法。
  • store 定义的方法内部可任意修改数据,可直接返回数据,支持同步、异步方法。
  • 当数据发生变化时,自动触发组件渲染。基于React Hooks API,实现了完整的单向数据流。
  • 集成异步方法的执行状态管理,目前最优雅的loading状态解决方案之一。
  • store 内部方法可以使用this.stores.TodoStore访问其他的 store 示例,实现更复杂的数据交互。

和之前的方案相比:

  • 不再区分 state, reducer, helper,去掉了这些概念,更简单。
  • 定义 store 就像定义一个普通的 js object 一样,只需要传入一个 namespace 用于区分不同的 store
  • 基于 Proxy 重新设计,数据变化,则自动通知组件,重新渲染。

TODO

  • [ ] TypeScript 支持
  • [ ] 支持 Vuejs
  • [ ] 更多的测试用例

如何使用

安装:

npm install iostore
// or
yarn add iostore

API

引入

import { createStore, useStore } from 'iostore';

createStore(params)

定义一个 store。参数:

普通的 js 对象,必须指定一个namespace

// TodoStore.js
import { createStore } from 'iostore';
createStore({
  namespace: 'TodoStore',
  todos: [],
  getTodoCount() {
    return this.todos.length;
  },
  getNs() {
    return this.namespace;
  },
  ...rest, // 其余自定义的数据和方法
});

// UserStore.js
import { createStore } from 'iostore';
createStore({
  namespace: 'UserStore',
  // 访问其他 store 的方法。
  getTodoCount() {
    return this.stores.TodoStore.getTodoCount();
  },
  ...rest, // 其余自定义的数据和方法
});

useStore()

React 函数式组件中引入所需 store。 无参数。 得益于 ES6 中的解构赋值语法,我们从该方法的返回值中,单独声明所需的 store。

框架会在 store 中注入 stores 对象,用来访问其他 store 的数据。 一般来说,只推荐访问其他 store 的计算数据,不要访问其他 store 中可能导致修改数据的方法。 如果需要修改其他 store 的数据,请在逻辑层/组件内处理。

如下:

const Todo = () => {
  const { TodoStore } = useStore();
  // 之后便可以自由的使用 TodoStore 中定义的方法了。
  const ns = TodoStore.getNs();
  return <div>{ns}</div>;
};

关于 loading

在对交互要求较高的场景下,获取异步方法的执行状态是非常必要的。

例如显示一个 loading 页面告诉用户正在加载数据,按钮上显示一个loading样式提示用户该按钮已经被点击。

当你使用iostore时,这一切变得非常简单。

我们可以非常容易的获取到每一个异步方法的loading状态,甚至可以获取到一个store下有没有异步方法正在执行。

  • 获取store中有没有异步方法正在执行:Store.loading,返回 true/false
  • 获取store中某个异步方法的 loading 状态:Store.asyncFunction.loading,返回 true/false

示例如下:

// 定义 store
createStore({
  namespace: 'TodoStore',
  id: 0,
  async inc() {
    await sleep(1000 * 5);
    this.id++;
  },
});

// 获取 loading 状态
const Todo = () => {
  const { TodoStore } = useStore();
  const handleClick = () => TodoStore.inc();
  // TodoStore.loading  store 级别的 loading 状态
  // TodoStore.inc.loading 某个异步方法的 loading 状态
  return (
    <button loading={TodoStore.inc.loading} onClick={handleClick}>
      submit
    </button>
  );
};

完整的 Todo 示例

// TodoStore.js
import store, { createStore, useStore } from 'iostore';
export default createStore({
  namespace: 'TodoStore', // store 命名空间
  id: 0,
  todos: [
    {
      id: 0,
      content: 'first',
      status: 'DOING',
    },
  ],
  addTodo(content) {
    this.id++;
    const todo = {
      id: this.id,
      content,
      status: 'DOING',
    };
    this.todos.push(todo);
  },
  getTodoById(id) {
    return this.todos.filter(item => item.id === id)[0];
  },
  updateTodo(id, status) {
    const todo = this.getTodoById(id);
    if (!todo) return;
    todo.status = status;
  },
  // test async function
  incId: 0,
  async delayIncId() {
    await sleep(1000 * 3);
    this.incId++;
  },
});

// Todos.js
import React, { useRef } from 'react';
import store, { createStore, useStore } from '../src/index';
import todoStore from './TodoStore';

export default () => {
  /**
   * 获取 TodoStore 的几种方式:
   * const { TodoStore } = useStore(); // 更符合 React Hooks 的理念
   * const { TodoStore } = store;
   * const TodoStore = todoStore.useStore();
   */
  const { TodoStore } = useStore();
  const inputEl = useRef(null);
  const handleClick = item => {
    if (item.status === 'DOING') {
      TodoStore.updateTodo(item.id, 'COMPLETED');
    } else if (item.status === 'COMPLETED') {
      TodoStore.updateTodo(item.id, 'DOING');
    }
  };
  const handleAddTodo = () => {
    console.warn('set data within component, should be got console.error : ');
    TodoStore.todos[0].id = 1000;
    const text = inputEl.current.value;
    if (text) {
      TodoStore.addTodo(text);
    }
  };
  console.log('render', 'totos.length:' + TodoStore.todos.length);
  return (
    <div>
      <div data-testid="incid">{TodoStore.incId}</div>
      {!TodoStore.delayIncId.loading ? <div data-testid="incidfinish" /> : ''}

      <div data-testid="incidloading">{TodoStore.delayIncId.loading ? 'loading' : 'completed'}</div>
      <div data-testid="todocount">{TodoStore.todos.length}</div>
      <ul data-testid="todolist">
        {TodoStore.todos.map(item => {
          return (
            <li onClick={() => handleClick(item)} key={item.id}>
              {item.content}
              <span>{item.status}</span>
            </li>
          );
        })}
      </ul>
      <input ref={inputEl} data-testid="todoinput" type="text" />
      <button data-testid="todobtn" onClick={() => handleAddTodo()}>
        add todo
      </button>

      <button data-testid="incbtn" onClick={() => TodoStore.delayIncId()}>
        delay inc id
      </button>
    </div>
  );
};

License

MIT

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].