A redux helper for react & hooks & typescript developers.


Keywords
react, react-redux, immer, hook, store
License
MIT
Install
npm install imdux@0.1.0

Documentation

imdux logo

Imdux

🌈 A redux helper for react & hooks & typescript developers.

CI Status Coverage Status Version Download Mini size MIT License

特点

  • 🚀简单高效:完全去除了redux冗余低效的样板代码,提供一把全自动的生产力工具。
  • 🍧 类型安全:面向typescript用户,100%类型安全,同时摒弃interface类型预定义,改用infer,实现了state和dispatch类型推导,极大地减少了类型定义代码。
  • ✈️目前未来:拥抱react hooks,便于typescript的类型检查和代码复用。
  • 🍸最佳实践:Imdux的目的不仅仅是提供一个库,更希望的是提供一个解决方案,探索一种react hooks的最佳实践。

开始

首先,创建一个react项目:

npx create-react-app imdux-demo

安装imdux,imdux依赖于 immer,redux,react-redux :

npm install imdux immer redux react-redux --save

src目录下创建文件store.js,输入代码:

import { createAction, createStore } from "imdux";

const initialState = {
  value: 0
};

const reducers = {
  increase(draft, payload) {
    draft.value += payload;
  },
  decrease(draft, payload) {
    draft.value -= payload;
  }
};

const counter = createAction({ initialState, reducers });
export const store = createStore({ counter }, { devtool: true });
export const { Dispatch } = store;

打开src/App.js,输入代码:

import React from "react";
import { useSelector } from "react-redux";

import { Dispatch } from "./store";

export default function App() {
  const value = useSelector(store => store.counter.value);
  return (
    <div>
      <h1>{value}</h1>
      <button onClick={() => Dispatch.counter.increase(1)}>increase</button>
      <button onClick={() => Dispatch.counter.decrease(1)}>decrease</button>
    </div>
  );
}

打开src/index.js,注入redux的store:

import React from "react";
import ReactDOM from "react-dom";
import { Provider } from "react-redux";

import App from "./App";
import { store } from "./store";

const rootElement = document.getElementById("root");
ReactDOM.render(
  <Provider store={store.redux}>
    <App />
  </Provider>,
  rootElement
);

enjoy it~ 很简单,对不对?

打开redux的devtool,通过点击increasedecreasebutton,我们可以看到状态变更的历史记录:

redux_devtool

通过观察可以发现,counter.increase中的counter等于 createStore({ counter })中的counter,而counter.increase中的increase等于reducers中的increase,也就是说,imdux会自动帮你创建redux中的action.type,你再也不需要定义字符串、写switch...case、那一套东西了。

对于typescript用户,你需要在store.ts中带上类型:

import { createAction, createStore } from "imdux";

type State = typeof initialState; // 获得类型
type Reducers = typeof reducers;  // 获得类型

const initialState = {
  value: 0
};

const reducers = {
  increase(draft: State, payload: number) { // draft的类型为State
    draft.value += payload;
  },
  decrease(draft: State, payload: number) { // draft的类型为State
    draft.value -= payload;
  }
};

const counter = createAction<State, Reducers>({ initialState, reducers }); // 注入类型
export const store = createStore({ counter }, { devtool: true });
export const { Dispatch } = store;

这样你就可以很轻松地获得typescript的类型检查和代码提示:

type

你可以在浏览器中打开这个例子: javascript typescript

Imdux API

createAction

imdux中的action由两部组成:initialStatereducers

通常react项目可以切割为很多小的页面或者模块。当一个页面或者模块的state需要全局管理时,你就可以为这个页面或者模块创建一个Action,并为这个Action起一个名字。例如,你有一个名称为homeActionhome.usename需要全局管理:

const initialState = { usernmae: "" }
const reducers = {
  setUsername(draft, payload) {
    draft.usernmae = payload;
  },
};
const home = createAction({ initialState, reducers });

一个Action就创建好了。

对于typescript用户,你需要增加类型信息并注入:

type State = typeof initialState; // 获得类型
type Reducers = typeof reducers;  // 获得类型

const home = createAction<State, Reducers>({ initialState, reducers }); // 注入类型

同时,给每一个reducer函数带上类型信息,以便在reducer内获得类型提示,这也是Dispatch函数参数类型检查的关键所在:

const reducers = {
  setUsername(draft:State, payload:string) {
    draft.usernmae = payload;
  },
};

createStore

创建好名称为homeAction后,你需要使用createStore把这个action初始化,同时将DispatchQuery导出:

export const store = createStore({ home }, { devtool: true });
export const { Dispatch, Query } = store;

接下来,你就可以使用Dispatch触发一个状态变化,更新页面:

Dispatch.home.setUsername("jack");

你可以使用Query,同步地获取当前状态:

console.log(Query.home.usernmae) // jack

异步请求

// TODO

最佳实践

// TODO

License

MIT