[前端] useReducercreateContext代替Redux原理示例解析

2349 3
Honkers 2022-11-9 10:41:27 | 显示全部楼层 |阅读模式
目录

    前言采用react-redux实现采用react hooks模拟redux实现异步action总结




前言

最近看到很多采用useReducer + createContext 实现一个简易的redux的方案,今天亲自试了一下,发现还是会有一些区别的。

采用react-redux实现

这里使用react-redux 实现一个简单的状态管理例子。
App.jsx根组件
import React from 'react';
import { Button } from './Button';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import A from './a';
export default function ButtonDemo1() {
  const reducer = (state, action) => {
    const { nam, theme } = state;
    switch (action.type) {
      case 'UPDATENAME':
        return {
          ...state,
          name: `${name} + 1`,
        };
      case 'UPDATETHEME':
        return {
          ...state,
          theme: theme === 'dark' ? 'light' : 'dark',
        };
      default:
        return state;
    }
  };
  const store = createStore(reducer, {
    name: 'fx',
    theme: 'dark',
  });
  return (
    <Provider store={store}>
      <div>
        <Button />
        <A />
      </div>
    </Provider>
  );
}
A组件用于dispatch和接收store。
A.jsx
import React, { useContext } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { reduxContent } from './index1';
export default function A() {
  const dispatch = useDispatch();
  return (
    <div onClick={() => dispatch({ type: 'UPDATENAME' })}>
      {useSelector((state) => state.name)}
    </div>
  );
}
效果如图:


可以看到,Button组件未使用redux store,因此正常渲染了一次。

采用react hooks模拟redux实现

这里采用useReducer + createContext 模拟实现一个redux:
App.jsx
import React, { useReducer, createContext } from 'react';
import { Button } from 'concis';
import A from './a';
export const reduxContent = createContext({});
export default function ButtonDemo1() {
  const reducer = (state, action) => {
    const { name, theme } = state;
    switch (action.type) {
      case 'UPDATENAME':
        return {
          ...state,
          name: `${name} + 1`,
        };
      case 'UPDATETHEME':
        return {
          ...state,
          theme: theme === 'dark' ? 'light' : 'dark',
        };
      default:
        return state;
    }
  };
  const [redux, dispatch] = useReducer(reducer, {
    name: 'fx',
    theme: 'dark',
  });
  return (
    <reduxContent.Provider value={{ redux, dispatch }}>
        <Button />
        <A />
    </reduxContent.Provider>
  );
}
A.jsx
import React, { useContext } from 'react';
import { reduxContent } from './index1';
export default function A() {
  const { redux, dispatch } = useContext(reduxContent);
  return (
    <div onClick={() => dispatch({ type: 'UPDATENAME' })}>
      {redux.name}
    </div>
  );
}
同样,子组件也可以对store中的状态进行get和dispatch,但是会出现这样的问题:


可以看到,Button组件并没有使用store中的内容,但是会随着A组件一起跟着重新渲染,原因其实就是采用这种方式store是存储在根组件的,根组件状态发生了变化(useReducer),子组件跟着一起重新渲染了,因此解决这个问题的思路其实和解决常规的子组件没变化一起被更新的思路是一样的。
可以采用 useMemo限制 + memo 浅比较。
因此只需要在App.jsx中这样修改:
const renderButton = React.useMemo(() => {
    return <Button />;
  }, []);
  return (
    <reduxContent.Provider value={{ redux, dispatch }}>
      <div style={{ display: 'flex', flexWrap: 'wrap' }}>
        {renderButton}
        <A />
      </div>
    </reduxContent.Provider>
  );
}
Button.jsx
const Button = (props) => {
    ......
})
export default React.memo(Button);

异步action

同样,如果需要异步dispatch的话,简单的场景其实单纯使用异步操作就可以完成,但是在复杂的场景下很难对于异步流进行管理和维护,这时就需要借助redux中间件了,类似redux-thunk、redux-saga,而这也是使用hooks无法实现的,无法处理副作用,拦截action去更好的reducer。

总结

当然,并不是说采用react hooks所实现的状态管理方式没有好处,这样可以更加贴合react原生,采用react自身所提供的hook,并且可以减少项目中的redux各种实例、减少代码体积,对于小型项目或是不需要很多全局状态的项目,这种方式确实是不错的选择。但是redux依旧是大型项目中最可靠的保障存在。
以上就是useReducer createContext代替Redux原理示例解析的详细内容,更多关于useReducer createContext代替Redux的资料请关注中国红客联盟其它相关文章!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Honkers

荣誉红客

关注
  • 4004
    主题
  • 36
    粉丝
  • 0
    关注
这家伙很懒,什么都没留下!

中国红客联盟公众号

联系站长QQ:5520533

admin@chnhonker.com
Copyright © 2001-2025 Discuz Team. Powered by Discuz! X3.5 ( 粤ICP备13060014号 )|天天打卡 本站已运行