對比React 16.3的新Context API和Redux

原問題

react16.3的context api能否完全取代redux?www.zhihu.com圖標

這個問題包括兩個部分:

  • Redux和React 16.3中的新Context API分別解決了什麼問題?
  • 什麼情況下更適合用Redux?

1 Redux和React 16.3中的新Context API分別解決了什麼問題?

看了下,React 16.3的新Context API大概是這種感覺:

React對象多了一個新方法

React.createContext<T>(defaultValue: T)

這個方法接受一個值作為默認上下文,返回一個包括了兩個組件類的對象:

{ Provider: React.ComponentType<{value: T}>, Consumer: React.ComponentType<{children: (value: T)=> React.ReactNode}>}

之後,創建Consumer組件時,Consumer組件的children函數會收到外部對應的Provider組件的props.value作為參數,例如:

type Theme = light | dark;// Pass a default theme to ensure type correctnessconst ThemeContext: Context<Theme> = React.createContext(light);class ThemeToggler extends React.Component { state = {theme: light}; render() { return ( // Pass the current context value to the Providers `value` prop. // Changes are detected using strict comparison (Object.is) <ThemeContext.Provider value={this.state.theme}> <button onClick={() => this.setState(state => ({ theme: state.theme === light ? dark : light, })) }> Toggle theme </button> {this.props.children} </ThemeContext.Provider> ); }}class Title extends React.Component { render() { return ( // The Consumer uses a render prop API. Avoids conflicts in the // props namespace. <ThemeContext.Consumer> {theme => ( <h1 stylex={{color: theme === light ? #000 : #fff}}> {this.props.children} </h1> )} </ThemeContext.Consumer> ); }}

注意Consumer組件中的children函數收到了theme作為參數。

跟之前的Context API相比,現在只有每次調用createContext返回的Provider和Consumer之間可以互相傳遞信息,當然,和舊的Context API類似,Consumer仍然需要在Provider之內渲染才能收到由Provider提供的上下文,其他情況下只能收到上面提到的defaultValue作為上下文。

那麼,新API解決了什麼問題?

  • 和組件props相比,新舊的Context API和Redux都解決了props存在的「只要是子組件需要的信息,即使父組件不需要,也必須先傳給父組件然後一層層傳到子組件」的問題
  • 和Redux相比,新舊的Context API都解決了Redux存在的「一些信息的內容需要根據組件的包含關係決定,而Redux難以處理這類包含關係」的問題
  • 和舊的Context API相比,新API解決了舊API無法處理「兩個互相嵌套的組件提供的兩個Context中,key相同的部分會衝突」的問題

但至少Redux解決的以下問題,在Context API中仍然沒有得到解決:

  • 邏輯/數據/視圖分離的代碼結構(reducer/store/component),很好地劃分了代碼職責
  • 在不同項目之間通用的存儲和事件機制,從而允許redux-devtools和time travel這種通用的開發工具、以及類似redux-observable這種強大中間件的存在(store/action)

2 什麼情況下更適合用Redux?

至於什麼時候actually need Redux,個人感覺沒有固定的標準。

個人認同的是RxJS 5之後的維護者Ben Lesh的看法:

Ask yourself: can I use everything in my store to render an app elsewhere? A mobile app? A desktop app? A custom canvas UI? Is there anything I couldnt use in those? Then it probably doesnt belong in my store.

從這個意義上,感覺Redux適合

  • 作為路由信息的補充,也就是完全可以序列化到路由,但因為設計原因無法放進路由的那些內容
  • 存儲跟領域模型相關的數據,例如後端Model的緩存以及會話認證信息

其他例如窗口大小、臨時Modal狀態、視覺主題等等狀態,都適合放在新Context或props中。

推薦閱讀:

redux 有什麼缺點?
揭秘 React 狀態管理
使用 Redux-Arena 組合 React 組件
下一代狀態管理工具 immer 簡介及源碼解析
重用 Redux 中的 reducer

TAG:React | Redux | 前端開發框架和庫 |