何时使用原生 React.useReducer Hook 以及它与 Redux 的区别

IT技术 reactjs redux react-hooks
2021-05-12 00:51:42

所以,Hook 可以从 React 16.8 获得。从他们的文档中可以看出,Hooks 是功能组件中状态的替代者。基本的钩子是:useState, useEffect, useContext,但还有一些额外的钩子,其中之一是useReducer,看起来它使用与action-dispatchRedux相同的架构。

问题是它是否因为相似而取代 Redux?

它是否更适合特定项目?

它适合哪里?

4个回答

Redux 是一个以特定方式鼓励数据流的库。

react-redux 另一方面实现了 React 友好的方法,并提供了很多中间件和包装器,这样库使用者就不必自己设置整个过程。

虽然useReducer它是 Redux 工作方式的一部分,但它并不是 Redux 的全部。为了让您在组件的深处使用 dispatch 和 state,您仍然必须使用useContextuseReducer组合,这就像重新发明轮子一样。

最重要的是,它useReducer只是为您提供了一种dispatch方法,您可以使用方法将普通的旧对象作为操作进行分派。还没有办法添加middlewares到这些,例如thunksaga等等。

你也可以在你的应用程序中使用多个 reducer,useReducer但是将它们组合成一个 store 的方式仍然必须由开发人员管理。

此外,React 文档状态useReduceruseState状态逻辑复杂时的替代方案

useReduceruseState当您具有涉及多个子值的复杂状态逻辑或下一个状态取决于前一个状态时,通常更可取useReducer还可以让您优化触发深度更新的组件的性能,因为您可以向下传递调度而不是回调。

什么样钩useContextuseReducer做的是,他们消除对依赖Redux于小型的应用程序。

所以,如果要比较 Redux 和 useReducer

还原:

  • 中央集权国家
  • 进一步解耦
  • 有中间件:Redux thunk 和 Redux logger
  • 动作只能命中一个商店
  • 也许更适合大项目

使用减速器:

  • 本地状态
  • 没有包装组件
  • 需要 useContext 来重新发明轮子
  • 带有其他原生钩子
  • 不需要额外的依赖
  • 可能有多个商店(实际上是可以充当商店的减速器)
  • 也许更适合小项目

1.)useReducer是作为 Redux 的替代品吗?

让我们澄清一下 Redux 是什么,这样我们就可以将它的主要部分与普通的 React 解决方案进行比较useReducer

在此处输入图片说明 (受本文启发

如何用香草 React 替换所有部件

动作调度器/状态选择器

这是 React Redux 所做的替代:

import { useReducer, useContext, useMemo } from "react"
import { rootReducer } from "./reducers"

const GlobalContext = React.createContext()

const Provider = ({ children }) => {
  const [state, dispatch] = useReducer(rootReducer, { count: 0 });
  const store = useMemo(() => [state, dispatch], [state]);

  // You can also separate dispatch and state context providers
  return (
    <GlobalContext.Provider value={store}>{children}</GlobalContext.Provider>
  );
};

// Provider is placed at top-level to emulate a global state store
ReactDOM.render(<Provider> <App /> </Provider>, document.getElementById('root'))

const Comp = () => {
  // extract this UI logic in its own custom hook for better encapsulation
  const [state, dispatch] = useContext(GlobalContext);
  // ...
};

数据存储

Redux 存储可以被实例化 ( createStore) 并非常灵活地访问。使用 vanilla React,商店绑定到useReducerUI 中的一个。我们可以通过上下文或props传递它的状态。

存储减速机

rootReducer与 Redux完全相同的纯函数用于 vanilla。

中间件API

redux-thunk并且redux-sagaRedux中两个最流行的异步操作和副作用中间件使用useReducer,我们没有任何内置的中间件 API。相反,我们先进行异步处理,然后将结果转发到dispatch

const [state, dispatch] = useContext(GlobalContext);
// ...
<button onClick={() => dispatchAsync(dispatch)}> Process </button>

const dispatchAsync = dispatch => {
  fetchData().then(data => dispatch({type: "increment"}, data)) 
};

useReducer只要涵盖了它们的通用 API仍然可以将现有的 Redux 中间件与 集成- 您可以查看此答案以获取更多信息。

Redux DevTools(时间旅行,调试支持)

没有可用的直接集成useReducer,因此您可能会在这里错过一个重要的工作流程工具。复验库使用终极版DevTools也检查useStateuseReducer(没有测试虽然)。


2.) 它是否更适合特定项目?它适合哪里?

useReducer使用从本地状态和组件范围开始。如您所见,它还可以提升到全局范围以接管 Redux 的大部分角色。

在某些情况下,useReducer甚至可以提供更大的灵活性,因为全局状态可以在多个上下文之间进行划分。示例:将不同状态树/上下文中的低优先级和高优先级状态更改分开。

使用 vanilla React,您将主要错过 Redux DevTools 和流行的中间件库。在另一方面功能,如combineReducers可以很容易地重新实现了useReducer,因为看到这里

一般经验法则:开始为您的应用程序使用 vanilla React 并逐步添加像全局 Redux 存储这样的功能,一旦您觉得,这将成为强制性的(也取决于应用程序的大小)。


useReducer的状态是单个组件的本地状态 - 如果您想在整个应用程序中使用此状态,则需要dispatch通过 props 向下传递它(和/或函数)。它实际上只是一个更结构化的版本useState- 事实上,它useStateuseReducer在后台使用

另一方面,Redux 做得更多——除其他外,它通过 Context 使整个应用程序可以使用状态,然后提供 API 将您的深层嵌套组件连接到此状态,而无需向下传递props。

所以换句话说:

  • useReducer为您提供结构化的本地状态更新。
  • Redux 为您提供结构化和集中的状态更新。

如果你想“推出自己的终极版”与鱼钩,你需要使用的某种组合useReduceruseContext