【譯】不要再問我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——這些都是有效的選擇,取決於你正在作的事情),那麼我怎樣可使這些技術互補而且和諧共處呢?」。

相關文章
相關標籤/搜索