使用70行代码配合hooks重新实现react-redux

栏目: IOS · Android · 发布时间: 7年前

内容简介:react-hooks 是 react 官方新的编写推荐,我们很容易在官方的 useReducer 钩子上进行一层很简单的封装以达到和以往 react-redux \ redux-thunk \ redux-logger 类似的功能,并且大幅度简化了声明。react-hooks 的更多信息请阅读reactjs.org/hooks;这70行代码就是全部, 客官可以先阅读,或许后续的说明文档也就不需要阅读了。

react-hooks 是 react 官方新的编写推荐,我们很容易在官方的 useReducer 钩子上进行一层很简单的封装以达到和以往 react-redux \ redux-thunk \ redux-logger 类似的功能,并且大幅度简化了声明。

react-hooks 的更多信息请阅读reactjs.org/hooks;

先看看源码

这70行代码就是全部, 客官可以先阅读,或许后续的说明文档也就不需要阅读了。

  • 简易的实现了 react-redux, redux-thunk 和 redux-logger
  • 默认使用 reducer-in-action 的风格, 也可声明传统的 reducer 风格
import React from 'react';

function devLog(lastState, nextState, action, isDev) {
  if (isDev) {
    console.log(
      `%c|------- redux: ${action.type} -------|`,
      `background: rgb(70, 70, 70); color: rgb(240, 235, 200); width:100%;`,
    );
    console.log('|--last:', lastState);
    console.log('|--next:', nextState);
  }
}

function reducerInAction(state, action) {
  if (typeof action.reducer === 'function') {
    return action.reducer(state);
  }
  return state;
}

export default function createStore(params) {
  const { isDev, reducer, initialState, actions, middleware } = {
    isDev: false,
    reducer: reducerInAction,
    initialState: {},
    actions: {},
    middleware: params.isDev ? [devLog] : undefined,
    ...params,
  };
  const AppContext = React.createContext();
  const store = {
    useContext: function() {
      return React.useContext(AppContext);
    },
    actions,
    dispatch: undefined,
    state: initialState,
    initialState,
  };
  let realReducer;
  if (middleware) {
    realReducer = function(lastState, action) {
      let nextState = reducer(lastState, action);
      for (let i = 0; i < middleware.length; i++) {
        const newState = middleware[i](lastState, nextState, action, isDev);
        if (newState) {
          nextState = newState;
        }
      }
      return nextState;
    };
  } else {
    realReducer = reducer;
  }

  const Provider = props => {
    const [state, dispatch] = React.useReducer(realReducer, initialState);
    if (!store.dispatch) {
      store.dispatch = async function(action) {
        if (typeof action === 'function') {
          await action(dispatch, store.state);
        } else {
          dispatch(action);
        }
      };
    }
    store.state = state;
    return <AppContext.Provider {...props} value={state} />;
  };
  return { Provider, store };
}
复制代码

reducer-in-action 风格

reducer-in-action是一个reducer函数,这 6 行代码就是 reducer-in-action 的全部:

function reducerInAction(state, action) {
  if (typeof action.reducer === 'function') {
    return action.reducer(state);
  }
  return state;
}
复制代码

它把 reducer 给简化了,放置到了每一个 action 中进行 reducer 的处理。我们再也不需要写一堆 switch,再也不需要时刻关注 action 的 type 是否和 redcer 中的 type 一致。

reducer-in-action 配合 thunk 风格,可以非常简单的编写 redux,随着项目的复杂,我们只需要编写 action,会使得项目结构更清晰。

使用

安装, 您甚至可以将上面那70行代码拷贝至项目中, 需要 react 版本 >= 16.7

yarn add react-hooks-redux
复制代码

我们用了不到 35 行代码就声明了一个完整的 react-redux 的例子, 拥抱 hooks。

import React from 'react';
import ReactHookRedux from 'react-hooks-redux';

// 通过 ReactHookRedux 获得 Provider 组件和一个 sotre 对象
const { Provider, store } = ReactHookRedux({
  isDev: true, // 打印日志
  initialState: { name: 'dog', age: 0 },
});

function actionOfAdd() {
  return {
    type: 'add the count',
    reducer(state) {
      return { ...state, age: state.age + 1 }; // 每次需要返回一个新的 state
    },
  };
}

function Button() {
  function handleAdd() {
    store.dispatch(actionOfAdd()); //dispatch
  }
  return <button onClick={handleAdd}>add</button>;
}

function Page() {
  const state = store.useContext();
  return <div>{state.age} <Button/> </div>;
}

export default function App() {
  return <Provider><Page /></Provider>;
}
复制代码

middleware 的编写

绝大部分情况,你不需要编写middleware, 不过它也极其简单。middleware 是一个一维数组,数组中每个对象都是一个函数, 传入了参数并且如果返回的对象存在, 就会替换成 nextState 并且继续执行下一个 middleware。

我们可以使用 middleware 进行打印日志、编写chrome插件或者二次处理 state 等操作。

我们看看 middleware 的源码:

let nextState = reducer(lastState, action);
for (let i = 0; i < middleware.length; i++) {
  const newState = middleware[i](lastState, nextState, action, isDev);
  if (newState) {
    nextState = newState;
  }
}
return nextState;
复制代码

性能和注意的事项

性能(和实现上)上最大的区别是,react-hooks-redux 使用 useConnect 钩子代替 connect 高阶组件进行 dispatch的派发。

在传统的 react-redux 中,如果一个组件被 connect 高阶函数进行处理,那么当 dispatch 时,这个组件相关的 mapStateToProps 函数就会被执行,并且返回新的 props 以激活组件更新。

而在 hooks 风格中,当一个组件被声明了 useContext() 时,context 相关联的对象被变更了,这个组件会进行更新。

理论上性能和 react-redux 是一致的,由于 hooks 相对于 class 有着更少的声明,所以应该会更快一些。

所以,我们有节制的使用 useContext 可以减少一一些组件被 dispatch 派发更新。

如果我们需要手动控制减少更新 可以参考useMemo 钩子的使用方式进行配合。

以上都是理论分析,由于此库和此文档是一个深夜的产物,并没有去做性能上的基准测试,所以有人如果愿意非常欢迎帮忙做一些基准测试。

异步action的例子

import React from 'react';
import ReactHookRedux, { reducerInAction, devLog } from 'react-hooks-redux';

// 通过 ReactHookRedux 获得 Provider 组件和一个 sotre 对象
const { Provider, store } = ReactHookRedux({
  isDev: true, // default is false
  initialState: { count: 0, asyncCount: 0 }, // default is {}
  reducer: reducerInAction, // default is reducerInAction 所以可省略
  middleware: [devLog], // default is [devLog] 所以可省略
  actions: {}, // default is {} 所以可省略
});

// 模拟异步操作
function timeOutAdd(a) {
  return new Promise(cb => setTimeout(() => cb(a + 1), 500));
}

const actions = {
  // 如果返回的是一个function,我们会把它当成类似 react-thunk 的处理方式,并且额外增加一个ownState的对象方便获取state
  asyncAdd: () => async (dispatch, ownState) => {
    const asyncCount = await timeOutAdd(ownState.asyncCount);
    dispatch({
      type: 'asyncAdd',
      // if use reducerInAction, we can add reducer Function repeat reducer
      reducer(state) {
        return {
          ...state,
          asyncCount,
        };
      },
    });
  },
};

function Item() {
  const state = store.useContext();
  return <div>async-count: {state.asyncCount}</div>;
}

function Button() {
  async function handleAdd() {
    // 使用 async dispatch
    await store.dispatch(actions.asyncAdd());
  }
  return <button onClick={handleAdd}>add</button>;
}

export default function App() {
  return (
    <Provider>
      <Item />
      <Button />
    </Provider>
  );
}

复制代码

谢谢阅读。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Web Design for ROI

Web Design for ROI

Lance Loveday、Sandra Niehaus / New Riders Press / 2007-10-27 / USD 39.99

Your web site is a business--design it like one. Billions of dollars in spending decisions are influenced by web sites. So why aren't businesses laser-focused on designing their sites to maximize thei......一起来看看 《Web Design for ROI》 这本书的介绍吧!

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具