Skip to content
/ think-react-store Public template

基于 react hooks 和 context api 实现的类似的 redux 的数据管理库

Notifications You must be signed in to change notification settings

cpagejs/think-react-store

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

21 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

think-react-store

think-react-store 基于 react hooks 和 context api 实现的类似的 redux 的数据管理库。支持数据存储,方法调用,可以在 class 组件和 function 组件中使用,支持同步和异步的方法调用。

GitHub 仓库地址

安装

npm i --save think-react-store

api 介绍

api 作用 适合场景
StoreProvider 全局用的 provider app.js 或者单个模块的根文件
StoreContext 存储用的 Context function 组件和 class 组件均适用
useStoreHook store 钩子函数,包含 state 和 dispatch function 组件
useStateHook 获取 state 用的 hook function 组件
useDispatchHook 进行事件派发的 hook function 组件
connect 添加属性和方法到组件中 function/class 组件

备注:

  • 参数 key 指的是,各个 context 导出时候对应的值,例如 export { default as user } from './user',那么 key 就是 user
  • 如果报语法错误,在检查原因后安装 babel 相关插件,例如 @babel/preset-react;另外建议不用 @babel/preset-env,因为 preset-env 会在运行时将 async/await 等进行转译;如果一定要使用,可以配置 targets 属性,类似这样子
"presets": [
  ["@babel/preset-env", {
    "targets": {
      "chrome": "70"
    },
    useBuiltIns: "usage"
  }],
  "@babel/preset-react"
],

1,创建 context

属性 含义
state state 属性
methods 方法,支持同步和异步两种写法,异步写法需要使用 async
reducers 支持同步方法
effects 支持异步方法,需要使用 async
// 创建 Contexts 目录

// user.js
export default {
  state: {
    id: 123,
    name: "cc",
  },
  reducers: {
    setName(state, payload) {
      return {
        ...state,
        ...payload,
      };
    },
  },
  effects: {
    async setNameAsync(dispatch, state, payload) {
      await new Promise((resolve) => setTimeout(resolve, 1000));
      dispatch({
        type: "setName",
        payload,
      });
    },
  },
};

// index.js 合并 context
export { default as user } from "./user";

2,配置 StoreProvider

import { StoreProvider } from "think-react-store";
import * as store from "./Contexts";

ReactDOM.render(
  <StoreProvider store={store}>
    <App />
  </StoreProvider>,
  mountNode
);

3,使用 connect

备注:使用 connect 绑定的方法,会返回一个 promise 对象

const mapState = ({ user: { id, name } }) => ({
  id,
  name,
});
const mapDispatch = ({ user: { setName, setNameAsync } }) => ({
  setName,
  setNameAsync,
});
export default connect(mapState, mapDispatch)(DemoConnect);

// 使用
const handelClick = () => {
  props
    .setName({
      name: "john",
    })
    .then((res) => {
      console.log(res);
    })
    .catch((err) => {
      console.log(err);
    });
};

4,在 function 组件中使用

import React, { useContext } from "react";
import { StoreContext, useStoreHook } from "think-react-store";

export default function DemoFunc() {
  const { state, dispatch } = useContext(StoreContext);
  const {
    user: { id, name, setName, setNameAsync },
  } = useStoreHook();

  const handleName = () => {
    setName({
      name: "同步修改",
    });
  };

  const handleNameAsync = () => {
    setNameAsync({
      name: "异步修改",
    });
  };

  return (
    <div>
      <h1>function 类型组件</h1>
      <p>
        用户:name--{name} id--{state.user.id}
      </p>
      <p>
        <button onClick={handleName}>修改用户</button>
      </p>
      <p>
        <button onClick={handleNameAsync}>异步修改用户</button>
      </p>
    </div>
  );
}

备注:function 组件中使用 think-react-store ,有多种调用方法。

4.1,获取 state 数据

使用 useStoreHook(推荐使用)

import React, { useContext } from "react";
import { useStoreHook } from 'think-react-store';

const {user:{id, name, setName, setNameAsync}} = useStoreHook()

<div>用户:{name}</div>

使用 useContext + StoreContext

import React, { useContext } from "react";
import { StoreContext } from 'think-react-store';

// state 指的是所有 context 的 state
const {state, dispatch} = useContext(StoreContext)

<div>用户:{state.user.id}</div>

使用 useStateHook,useStateHook 接受一个参数,如果不传则返回所有 state,传递对应的 key 则返回对应的 state

import { useStateHook } from "think-react-store";

// 获取所有的
const states = useStateHook();

// 获取单个的
const userState = useStateHook("user");

4.2,使用 dispatch

使用 useStoreHook(推荐使用),同步和异步的调用方式一样,只需要传递参数即可

import { useStoreHook } from "think-react-store";

const {
  user: { id, name, setName, setNameAsync },
} = useStoreHook();

getUser({
  name: "异步修改",
});

使用 useContext + StoreContext,如果是异步调用参数需要为函数

import React, { useContext } from "react";
import { StoreContext } from "think-react-store";

// state 指的是所有 context 的 state
const { state, dispatch } = useContext(StoreContext);

// 同步
dispatch({
  key: "user",
  type: "setName",
  payload: {
    name: "同步数据",
  },
});

// 异步
dispatch(() => ({
  key: "user",
  type: "setNameAsync",
  payload: {
    name: "异步修改",
  },
}));

使用 useDispatchHook,useDispatchHook 接受一个参数,如果不传那么在使用 dispatch 使用需要携带上。如果是异步调用参数需要为函数

import { useDispatchHook } from "think-react-store";

// 不带参数 key
const dispatchs = useDispatchHook();
dispatchs({
  key: "user",
  type: "setName",
  payload: {
    name: "同步数据",
  },
});

// 参数 key
const dispatchs = useDispatchHook("user");
dispatchs({
  type: "setName",
  payload: {
    name: "同步数据",
  },
});

// 异步
dispatchs(() => ({
  type: "setNameAsync",
  payload: {
    name: "异步修改",
  },
}));

5,在 class 组件中使用

在 class 组件中使用 dispatch 调用异步函数时候,this.context.dispatch 里面的参数是函数;使用 dispatch 调用同步函数时候,this.context.dispatch 里面的参数是函数是 json 对象。

import React from "react";
import { StoreContext } from "think-react-store";

export default class DemoClass extends React.Component {
  static contextType = StoreContext;

  handleAuth = () => {
    this.context.dispatch({
      key: "user",
      type: "setName",
      payload: {
        name: "同步数据",
      },
    });
  };

  handleAuthAsync = () => {
    this.context.dispatch(() => ({
      key: "user",
      type: "setNameAsync",
      payload: {
        name: "异步数据",
      },
    }));
  };

  render() {
    return (
      <div style={{ border: "1px solid #9c9c9c" }}>
        <h1>class 类型组件</h1>
        <p>用户:{this.context.state.user.name}</p>
        <p>
          <button onClick={this.handleAuth}>修改用户</button>
        </p>
        <p>
          <button onClick={this.handleAuthAsync}>异步修改用户</button>
        </p>
      </div>
    );
  }
}

6,中间件

6.1,新增中间件文件

/**
 * 中间件参数
 * @param {Object} store store
 * @param {Object} prevState 更新前的state值
 * @param {Object} nextState 更新后的state值
 * @param {Object} action 派发的action
 */
export default function log(store, prevState, nextState, action) {
  console.log("----日志log-----");
  console.log(`修改前:${JSON.stringify(prevState)}`);
  console.log(`修改后:${JSON.stringify(nextState)}`);
}

6.2,使用中间件

备注:middleware 的类型为数组

<StoreProvider
  store={store}
  middleware={[log]}
></StoreProvider>

7,loading

// 需要引入loading中间件
import loading from "think-react-store/middlewares/loading";

// 配置
<StoreProvider
  store={store}
  middleware={[loading]}
></StoreProvider>;

// 使用
const mapState = ({ user: { id, name }, loading }) => ({
  id,
  name,
  loading,
});

// 一般 loading 只需要异步函数中使用
<p>
  loading-setNameAsync->
  {props.loading.user.setNameAsync ? <span>true</span> : <span>false</span>}
</p>;

8,使用缓存(将 model 的数据缓存到 localStorage 里面)

import cache from "think-react-store/middlewares/cache";

<StoreProvider
  store={store}
  middleware={[cache]}
  cache={["user"]}
></StoreProvider>;

配置 cache 属性,cache 的值为数组,元素是 model 的名称,如果数组为空则不缓存数据。数据被缓存到 localStorage 里面。

ps:如果在使用过程中遇到什么问题/或者有改进的意见,欢迎 👏 在 issues 里面交流!欢迎 🌟!

About

基于 react hooks 和 context api 实现的类似的 redux 的数据管理库

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published