[译] React Hooks 愈来愈火了,它会取代传统的 Redux 吗?

前言

React Hooks 自推出以后,收到了很多追捧, 不少问题也随之而来。javascript

本文就其中的一个话题展开讨论:React Hooks 是否会取代传统的Redux ?css

我认为: 不会.html

在我看来,相比于传统的Class Component, Hooks 并无提供什么新的状态功能,只不过是对原有的 API 作了加强。java

相比以前,Hoos 更加简洁,也提高了原生 API 的可用性,适用的场景也愈来愈多。react

为了阐明个人观点, 咱们先作一些回顾。编程


Redux 是什么

Redux 是一个 可预测的状态管理工具,能够轻松集成在 React 应用中。 它有不少优势, 好比:redux

  • 单一数据源
  • 数据共享
  • 事务状态
  • 将数据状态I/O和反作用相隔离
  • 状态回朔, 又称 时光机
  • 一系列辅助工具带来的强大调试能力

总的来讲, Redux 提供了应对大型应用的代码组织和调试能力,在程序出错时, 能帮你快速定位问题。segmentfault

Hooks 是什么

在下的这边文章科普了Hooks的一些基础功能, 感兴趣的能够看一下。api

[全面了解 React 新功能: Suspense 和 Hooks ][segmentfault.com/a/119000001…]bash

Hooks 的主要优势:

  • 能够在函数式组件中定义数据状态,也能经过一些Hooks来模拟生命周期方法。
  • 逻辑复用;能够把公共逻辑抽象成一个个单独的Hook, 从传统的面向生命周期编程 转变为面向业务逻辑编程。
  • 共享公共行为,相似Render Props.

两家各有所长,好在如今有 react-redux Hooks(react-redux.js.org/next/api/ho…) 和 Reducer Hook (reactjs.org/docs/hooks-…) 这样的工具,咱们就没有必要纠结二者之间如何选择,雨露均沾, 美滋滋。

Hooks 带来了那些变化

  • 改变了咱们编写组件的方式, 有了更多选择,你能够抛弃生命周期方法, 拥抱Hooks。
  • Render Props 这种模式也有了更好的归宿

Hooks 不能取代哪些技术

  • Redux
  • HOC
  • 容器组件视图组件之间的隔离, 分离纯逻辑和视觉效果, 更易于测试。

什么时候使用Hooks

任什么时候候你均可以使用Redux 来管理状态,只要你喜欢。 可是若是你的应用足够简单,只包含单个视图,须要一个地方临时保存状态,不须要和其余组件共享数据,或者甚至都没有异步I/O都没有(有也无所谓)。 这时候就到Hooks大显身手了,这些情景下用Redux, 固然也能够,不过这种作法叫用牛刀杀鸡鸡。

来看个例子:

import React, { useState } from 'react';
import t from 'prop-types';
import TextField, { Input } from '@material/react-text-field';

const noop = () => {};

const Holder = ({
  itemPrice = 175,
  name = '',
  email = '',
  id = '',
  removeHolder = noop,
  showRemoveButton = false,
}) => {
  const [nameInput, setName] = useState(name);
  const [emailInput, setEmail] = useState(email);
const setter = set => e => {
    const { target } = e;
    const { value } = target;
    set(value);
  };
return (
    <div className="row">
      <div className="holder">
        <div className="holder-name">
          <TextField label="Name">
            <Input value={nameInput} onChange={setter(setName)} required />
          </TextField>
        </div>
        <div className="holder-email">
          <TextField label="Email">
            <Input
              value={emailInput}
              onChange={setter(setEmail)}
              type="email"
              required
            />
          </TextField>
        </div>
        {showRemoveButton && (
          <button
            className="remove-holder"
            aria-label="Remove membership"
            onClick={e => {
              e.preventDefault();
              removeHolder(id);
            }}
          >
            &times;
          </button>
        )}
      </div>
      <div className="line-item-price">${itemPrice}</div>
      <style jsx>{cssHere}</style>
    </div>
  );
};

export default Holder;

复制代码

上面的例子 使用 useState 来跟踪表单中的 nameemail

const [nameInput, setName] = useState(name);
const [emailInput, setEmail] = useState(email);
复制代码

你可能会注意到还有一个 removeHolder ,这个action creator 来自 Redux 。这种模式下,各类方法均可以混合搭配。

在 Hooks 出现以前, 可使用 local state 保存状态和更新状态 用以应对这种状况。若是是我写这个的话, 我更倾向于把它塞到Redux中, 再经过Prop去取状态吧。

反正到如今, 我作过的全部React应用, 都用到了Redux,原则也很简单:

组件状态用组件状态,应用状态用 Redux。 各司其职, 相得益彰。

什么时候使用Redux

另外一个常见的疑问是, 我应该把全部的数据和状态都放在Redux吗? 若是不这么作的话, 是否是就没法使用时间旅行?

答案是不会的。

由于应用中有不少状态是临时的,种种局限不足觉得日志遥测或者时间旅行提供足够多的信息。 除非你在作的是一个具备协同能力的文本编辑器(好比我以前参与的Lark Docs, 还有腾讯文档等),能够把用户的每个操做,每个changeSet 的数据都保存起来, 包括光标位置等信息。

每次你往Redux 里添加数据的时候, 随之而来的是一层抽象和额外的复杂度。

换言之, 每次你要用Redux的时候, 要知道本身为啥须要用到它。 若是你的应用有以下需求, 那就能够考虑使用Redux:

  • 须要保存或者加载状态
  • 跨组件共享状态
  • 须要与其余组件共享业务逻辑或数据处理过程

仍是那个例子:

访问连接: tddday.com/

import React from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { compose } from 'ramda';
import page from '../../hocs/page.js';
import Purchase from './purchase-component.js';
import { addHolder, removeHolder, getHolders } from './purchase-reducer.js';
const PurchasePage = () => {
  // You can use these instead of
  // mapStateToProps and mapDispatchToProps
  const dispatch = useDispatch();
  const holders = useSelector(getHolders);
const props = {
    // Use function composition to compose action creators
    // with dispatch. See "Composing Software" for details.
    addHolder: compose(
      dispatch,
      addHolder
    ),
    removeHolder: compose(
      dispatch,
      removeHolder
    ),
    holders,
  };
return <Purchase {...props} />;
};
// `page` is a Higher Order Component composed of many
// other higher order components using function composition.
export default page(PurchasePage);

复制代码

这个组件并不处理任何DOM, 是一个纯展现型的组件,并用 React-Redux hooks API 链接到 Redux 上。

之因此用到 Redux,是由于其余部分须要这个表单的数据。它的状态不是本地化到单个组件中,而是在组件之间共享;

Redux 容许咱们干净地将反作用与其余组件逻辑分离开来,不须要咱们模拟 I/O 服务。

相比 redux-thunk,我更喜欢使用 redux-saga 的缘由就是后者的隔离功能)。

为了在这个用例上追赶 Redux 的脚步,React 的 API 须要提供反作用隔离功能。

Redux 是一种架构

Redux 与状态管理库有着很大区别。但本质上,也是 Flux 架构 的一个子集。

与库相比,Redux 向来更接近一种架构和非强制性的约定(convention)。

事实上,Redux 的基本实现只须要几十行代码。

这也是 Redux 的一大好处。若是你想多用一些本地组件状态和 hook API,不想把全部内容都塞到 Redux 里,那也彻底没问题。

React 提供了一个 useReducer hook,能够用它接入你的 Redux 风格的 Reducer。这对不常见的状态逻辑、依赖状态等内容很是有用。

若是你的用例是要将临时状态装入单个组件,也可使用 Redux 架构,但要用 useReducer hook 取代 Redux 来管理状态。

若是你后面须要维持或共享这个状态, 就须要把它保存到Redux里了。

结语

Hooks 并不会替代传统的 Redux, 它的出现为咱们编写组件提供了更多的灵活性, 更多的可能, 但愿各位FEer 都能及时拥抱这个新特性, 找到本身最喜欢的开发姿式~

行文粗浅, 如有疏漏, 还请指正。

附原文连接: medium.com/javascript-…

相关文章
相关标签/搜索