【译】不要再问我React Hooks可否取代Redux了

原文地址: Stop Asking if React Hooks Replace Redux

许多同事一直问我一些相似的问题:html

“若是咱们在项目中使用hooks,咱们是否还须要Redux?”react

“React Hooks会不会使Redux太过期了?我能不能用Hooks来作全部Redux能作的事呢?”git

在Google中搜索会发现,你们常常问这些问题。github

“React Hooks是否会取代Redux?”,最简单的回答是“不必定”。redux

更细致但礼貌的答案是“嗯,那取决于你正在作的项目类型”。api

我更倾向于告诉你们的答案是“我不肯定你是否知道你在说什么”。有几个缘由能够说明,为何“React Hooks是否会取代Redux”是一个本质上有缺陷的问题。首先:数组

Redux一直是非强制性的

经过Dan Abramov(Redux的创造者之一)的一篇文章【You Might Not Need Redux】能够看出,若是你不须要使用它,则无需替换任何东西。app

Redux是一个JavaScript库,而且若是你用的是React(另外一个JavaScript库),那么为了使用Redux,你还须要在应用中加载一个React-Redux的JavaScript库。在项目中使用依赖库会增长打包体积,这会增长你应用的加载时间。基于这个缘由,你不该该使用一些库,像jQuery、Redux、MobX(另外一个状态管理库),甚至是React,除非你有明确的理由要使用它们。ide

当你们问到“是否hooks会替代Redux”,他们彷佛常常以为,他们的React应用须要使用其中一种。事实并不是如此,若是你正在写的应用没有不少状态须要被储存,或者你的组件结构很简单,能够避免过分的prop传递,以及基于React自己提供的特性,你的状态已经足够可控了,无论有没有hooks,这些状况使用状态管理就没有多大意义了。函数

即便你确实有许多的状态,或者有像老树根同样扭曲分叉的React组件结构,你仍然不须要状态管理库。Prop传递可能很麻烦,可是React给了你许多状态管理选项,而且hooks绝对能够帮你很好地组织状态。Redux是一个轻量级的库,可是它的设置很复杂,增长了打包体积,而且不少地方须要权衡。有不少缘由能够说明,为何你应该选择不在项目中使用它,而且这些缘由颇有说服力。

你并不老是须要Redux,这也是在说,你依然有许多理由去使用它的。若是你的项目在一开始就使用了Redux,那么它多是一个很好的理由,不管它是否作了这些:组织(应用状态的可预测性、单一的数据流,在复杂的应用中颇有用)、中间件、Redux的强有力的开发工具和调试能力。若是你有使用Redux的理由,它不会由于React Hooks变得无效。若是你以前须要Redux,那么你如今仍然须要。这是由于:

React Hooks和Redux并无试图解决一样的问题

Redux是一个状态管理库,Hooks是React最近更新的部分特性,让你的函数组件能够作类组件能作的事情。

因此不使用类组件来写React应用忽然会让状态管理库变得过期了呢?

固然不会!

经过文档能够看出,React Hooks被开发出来主要是这三个理由:

  • 难以复用类组件之间的逻辑
  • 生命周期中常常包含一些莫名其妙的不相关逻辑
  • 类组件难以被机器和人理解

注意,没有一条理由的动机直接代表要作一些与状态管理相关的事情。

话说如此,React Hooks确实提供了一些选择去管理应用的状态。尤为是useStateuseReduceruseContext方法,提供来新的方式去维护你的状态,这被证实比先前React提供的选项更好、更有条理。

可是这些hooks并非什么新东西或神奇的东西,而且它们也没有使状态管理过期,由于事实是:

React Hooks并无让你的应用能够作一些之前作不到的事情

那就对了,你如今能够写函数组件来作一些之前只能用类组件来作的事情,可是这些函数组件并不能作一些类组件作不到的事情,除了能够更好地组织和复用代码的能力。它们不必定让你的应用更好,而是让开发者的体验更好。

useStateuseReducer只是管理组件状态的方法,而且它们的工做原理同类组件的this.statethis.setState是同样的,你仍然须要传递你的props。

useContext是你们认为在Redux板上钉钉的特性,由于它可让你在组件之间共享应用的状态,而不须要经过prop传递,可是它也没有真正的作任何新的事情。context API如今是React的一部分,useContext仅仅是让你不用<Consumer>包裹也可使用context。而且有一些开发这用context来管理整个应用的状态,这不是设计context的目的。经过文档能够看出:

Context is designed to share data that can be considered “global” for a tree of React components, such as the current authenticated user, theme, or preferred language.

Context是为了共享数据而被设计出来的,能够认为是React组件树的“全局”,好比当前已受权的用户、主题或者首选的语言。

换句话说,就是那些预计不会频繁更新的东西。

文档中也建议有节制地使用context,由于“它会使得组件难以复用”。他们也提醒开发者,若是开发者不当心,context很容易触发没必要要的重复渲染。

我见过项目成功地使用React Context来管理应用状态,这是有可能的,也不失为一种选择。可是状态管理并不彻底是context被设计出来去作的事情,并且Redux和其余状态管理库被设计出来就是为了处理这种特定的目的。

此外,React Hooks也毫不意味着Redux的消亡,由于若是你看一眼React-Redux最近更新的文档,你会明白:

React-Redux也有本身的hooks

没错,React Hooks正在帮助React-Redux恢复活力并移除来它的一些痛点,与“替代”的说法相差甚远。

我在另外一篇文章中对React-Redux进行了深刻研究,这里要说的重点。在hooks以前,你必须定义mapStateToPropsmapDispatchToProps两个函数,而且用connect包裹你的组件来建立一个高阶组件,它会传递dispatch方法和部分Redux贮存的状态,这些状态是你在mapping函数中指定做为props传递到组件中的。

让咱们来看一个很是简单的计数器应用的例子(太简单甚至都不须要Redux,可是这里主要是为了展现一些信息)。假设咱们已经定义了Redux store和incrementdecrement两个action creator(完整的源码在这里)。

import React from 'react';
import {connect} from 'react-redux';
import * as actions from '../actions/actions';

class App extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {
    const {count, increment, decrement} = this.props;

    return (
      <div>
        <h1>The count is {count}</h1>
        <button onClick={() => increment(count)}>+</button>
        <button onClick={() => decrement(count)}>-</button>
      </div>
    );
  }
}

const mapStateToProps = store => ({
  count: store.count
});

const mapDispatchToProps = dispatch => ({
  increment: count => dispatch(actions.increment(count)),
  decrement: count => dispatch(actions.decrement(count))
});

export default connect(mapStateToProps, mapDispatchToProps)(App);

太使人烦恼了!若是咱们没必要包裹组件到高阶组件中,就可让组件取到Redux store的值,这样不是更友好吗?是的,这就是hooks出现的缘由。Hooks就是为了复用代码和消除因为高阶组件产生的“嵌套地狱”。下面是一个相同的组件,使用React-Redux hooks转换成函数组件。

import React from 'react';
import * as actions from '../actions/actions';
import {useSelector, useDispatch} from 'react-redux';

const App = () => {
  const dispatch = useDispatch();
  const count = useSelector(store => store.count);

  return (
    <div>
      <h1>The count is {count}</h1>
      <button onClick={() => dispatch(actions.increment(count))}>+</button>
      <button onClick={() => dispatch(actions.decrement(count))}>-</button>
    </div>
  );
}

export default App;

是否是很漂亮?简而言之,useSelector让你能够保存部分Redux store的值到你的组件。useDispatch更简单,它仅仅为你提供了一个dispatch函数,你能够用它来发送状态更新到Redux store。最棒的是,你再也不须要写这些丑陋的mapping函数和用connect函数来包裹组件。如今,一切都很好地包含在你的组件中,它更简洁,所以更容易阅读,而且更有条理。重点是:

没有必要比较React Hooks和Redux孰优孰劣

毫无疑问,这两项技术能够很好地互补。React Hooks不会替代Redux,它们仅仅为你提供来新的、更好的方式去组织你的React应用。若是你最终决定使用Redux来管理状态,可让你编写更好的链接组件。

因此,请不要再问“React Hooks是否会取代Redux?”。

相反,开始问本身“我正在制做什么样的应用?我须要什么样的状态管理?Redux能够用吗,仍是有些过分使用呢?hooks能够用吗,仍是应该用类组件?若是我决定使用Redux和React Hooks(或者MobX和React Hooks,或者Redux和jQuery,不用React——这些都是有效的选择,取决于你正在作的事情),那么我怎样可使这些技术互补而且和谐共处呢?”。

相关文章
相关标签/搜索