何时使用本机React.useReducer Hook及其与Redux的区别

Rel*_*ros 17 reactjs redux react-hooks

因此,React 16.8中提供了挂钩。从他们的文档来看,Hooks可以作为功能组件中状态的替代者。基本挂钩是:useStateuseEffectuseContext,但也有一些额外的钩子,其和为之一useReducer,它看起来像它使用相同的action-dispatch的终极版做架构。

问题是,是否由于相似而取代Redux?

是否更适合特定项目?

它适合哪里?

Shu*_*tri 19

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

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

虽然useReducer这是Redux工作方式的一部分,但它并不完全是Redux。为了使您能够使用分派并深入了解组件,您仍然必须结合使用useContextuseReducer就像重新发明轮子一样。

除此之外,还useReducer为您提供了一种dispatch方法,您可以使用该方法将简单的旧对象作为操作进行分派。目前还没有办法添加middlewares到这些,例如thunksaga等等。

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

此外,React docs声明了状态逻辑复杂时useReducer的替代方法useState

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

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


for*_*d04 19

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 = () => {
  // You can extract this UI logic in its own custom hook for better encapsulation
  const [state, dispatch] = useContext(GlobalContext);
  // ...
};
Run Code Online (Sandbox Code Playgroud)

数据存储

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

减速器

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

中间件API

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

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

const dispatchAsync = dispatch => {
  fetchData().then(data => dispatch({type: "increment"}, data)) 
};
Run Code Online (Sandbox Code Playgroud)

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

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

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


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

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

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

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

一般经验法则:开始为您的应用程序使用 vanilla 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 = () => {
  // You can extract this UI logic in its own custom hook for better encapsulation
  const [state, dispatch] = useContext(GlobalContext);
  // ...
};
Run Code Online (Sandbox Code Playgroud)
const [state, dispatch] = useContext(GlobalContext);
// ...
<button onClick={() => dispatchAsync(dispatch)}> Process </button>

const dispatchAsync = dispatch => {
  fetchData().then(data => dispatch({type: "increment"}, data)) 
};
Run Code Online (Sandbox Code Playgroud)

  • 好吧...这应该是公认的答案!做得好! (3认同)

Joe*_*lay 9

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

另一方面,Redux可以做更多的事情-除其他功能外,它还可以通过上下文将状态提供给整个应用程序使用,然后提供API将深层嵌套的组件连接到该状态而无需传递道具。

换句话说:

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

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


Rel*_*ros 9

因此,如果要比较Redux和useReducer

Redux:

  • 集中国家
  • 加强解耦
  • 有中间件:Redux thunk和Redux logger
  • 动作只能击中一个商店
  • 也许更适合大型项目

useReducer:

  • 地方政府
  • 没有包装器组件
  • 需要useContext以重新发明轮子
  • 带有其他本机挂钩
  • 无需额外的依赖
  • 可能有多个商店(实际上可以充当商店的减速器)
  • 也许更适合小型项目