不要再问React Hooks能否取代 Redux 了

2019 年 9 月 14 日 前端大全

(给前端大全加星标,提升前端技能

英文:Max González  译文:连城

https://zhuanlan.zhihu.com/p/81126574

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

“如果我们在项目中使用hooks,我们是否还需要Redux?”

“React Hooks会不会使Redux太过时了?我能不能用Hooks来做所有Redux能做的事呢?”

在Google中搜索会发现,大家经常问这些问题。

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

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

我更倾向于告诉大家的答案是“我不确定你是否知道你在说什么”。有几个原因可以说明,为什么“React Hooks是否会取代Redux”是一个本质上有缺陷的问题。首先:

Redux一直是非强制性的

通过Dan Abramov(Redux的创造者之一)的一篇文章【You Might Not Need Redux】可以看出,如果你不需要使用它,则无需替换任何东西。

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

当大家问到“是否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确实提供了一些选择去管理应用的状态。尤其是useState、useReducer和useContext方法,提供来新的方式去维护你的状态,这被证明比先前React提供的选项更好、更有条理。

但是这些hooks并不是什么新东西或神奇的东西,并且它们也没有使状态管理过时,因为事实是:

React Hooks并没有让你的应用可以做一些以前做不到的事情

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

useState和useReducer只是管理组件状态的方法,并且它们的工作原理同类组件的this.state和this.setState是一样的,你仍然需要传递你的props。

useContext是大家认为在Redux板上钉钉的特性,因为它可以让你在组件之间共享应用的状态,而不需要通过prop传递,但是它也没有真正的做任何新的事情。context API现在是React的一部分,useContext仅仅是让你不用 包裹也可以使用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之前,你必须定义mapStateToProps和mapDispatchToProps两个函数,并且用connect包裹你的组件来创建一个高阶组件,它会传递dispatch方法和部分Redux贮存的状态,这些状态是你在mapping函数中指定作为props传递到组件中的。

让我们来看一个非常简单的计数器应用的例子(太简单甚至都不需要Redux,但是这里主要是为了展示一些信息)。假设我们已经定义了Redux store和increment、decrement两个action creator(完整的源码在这里)。

  
  
    
  1. import React from 'react';

  2. import {connect} from 'react-redux';

  3. import * as actions from '../actions/actions';


  4. class App extends React.Component {

  5. constructor(props) {

  6. super(props);

  7. }


  8. render() {

  9. const {count, increment, decrement} = this.props;


  10. return (

  11. <div>

  12. <h1>The count is {count}</h1>

  13. <button onClick={() => increment(count)}>+</button>

  14. <button onClick={() => decrement(count)}>-</button>

  15. </div>

  16. );

  17. }

  18. }


  19. const mapStateToProps = store => ({

  20. count: store.count

  21. });


  22. const mapDispatchToProps = dispatch => ({

  23. increment: count => dispatch(actions.increment(count)),

  24. decrement: count => dispatch(actions.decrement(count))

  25. });


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

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

  
  
    
  1. import React from 'react';

  2. import * as actions from '../actions/actions';

  3. import {useSelector, useDispatch} from 'react-redux';


  4. const App = () => {

  5. const dispatch = useDispatch();

  6. const count = useSelector(store => store.count);


  7. return (

  8. <div>

  9. <h1>The count is {count}</h1>

  10. <button onClick={() => dispatch(actions.increment(count))}>+</button>

  11. <button onClick={() => dispatch(actions.decrement(count))}>-</button>

  12. </div>

  13. );

  14. }


  15. 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——这些都是有效的选择,取决于你正在做的事情),那么我怎样可以使这些技术互补并且和谐共处呢?”。



推荐阅读

(点击标题可跳转阅读)

从 Mixin 到 HOC 再到 Hook

为什么 'XX' 不是一个 Hooks API?

30 分钟精通 React 新特性——React Hooks



觉得本文对你有帮助?请分享给更多人

关注「前端大全」加星标,提升前端技能

好文章,我在看❤️

登录查看更多
0

相关内容

React.js(React)是 Facebook 推出的一个用来构建用户界面的 JavaScript 库。

Facebook开源了React,这是该公司用于构建反应式图形界面的JavaScript库,已经应用于构建Instagram网站及 Facebook部分网站。最近出现了AngularJS、MeteorJS 和Polymer中实现的Model-Driven Views等框架,React也顺应了这种趋势。React基于在数据模型之上声明式指定用户界面的理念,用户界面会自动与底层数据保持同步。与前面提及 的框架不同,出于灵活性考虑,React使用JavaScript来构建用户界面,没有选择HTML。Not Rest

从HPO到NAS: 自动深度学习
专知会员服务
37+阅读 · 2020年6月15日
Python导论,476页pdf,现代Python计算
专知会员服务
253+阅读 · 2020年5月17日
【实用书】Python爬虫Web抓取数据,第二版,306页pdf
专知会员服务
115+阅读 · 2020年5月10日
【电子书】C++ Primer Plus 第6版,附PDF
专知会员服务
83+阅读 · 2019年11月25日
21个必须知道的机器学习开源工具!
AI100
13+阅读 · 2019年9月13日
msf实现linux shell反弹
黑白之道
49+阅读 · 2019年8月16日
2020年你应该知道的8种前端JavaScript趋势和工具
前端之巅
5+阅读 · 2019年6月9日
React Native 分包哪家强?看这文就够了!
程序人生
12+阅读 · 2019年1月16日
说说我的老同事,前端大神程劭非
余晟以为
17+阅读 · 2019年1月14日
Pipenv: 吹嘘自己无所不能,实际上没什么卵用
Python程序员
3+阅读 · 2018年12月21日
刚开始学编程?这几款小工具能让你事半功倍
Vue.js 很好,但是比 Angular 或 React 更好吗?
程序猿
3+阅读 · 2017年8月27日
十五条有用的Golang编程经验
CSDN大数据
5+阅读 · 2017年8月7日
Arxiv
8+阅读 · 2018年4月8日
Arxiv
5+阅读 · 2015年9月14日
VIP会员
相关资讯
21个必须知道的机器学习开源工具!
AI100
13+阅读 · 2019年9月13日
msf实现linux shell反弹
黑白之道
49+阅读 · 2019年8月16日
2020年你应该知道的8种前端JavaScript趋势和工具
前端之巅
5+阅读 · 2019年6月9日
React Native 分包哪家强?看这文就够了!
程序人生
12+阅读 · 2019年1月16日
说说我的老同事,前端大神程劭非
余晟以为
17+阅读 · 2019年1月14日
Pipenv: 吹嘘自己无所不能,实际上没什么卵用
Python程序员
3+阅读 · 2018年12月21日
刚开始学编程?这几款小工具能让你事半功倍
Vue.js 很好,但是比 Angular 或 React 更好吗?
程序猿
3+阅读 · 2017年8月27日
十五条有用的Golang编程经验
CSDN大数据
5+阅读 · 2017年8月7日
Top
微信扫码咨询专知VIP会员