對比React 16.3的新Context API和Redux
原問題
react16.3的context api能否完全取代redux?這個問題包括兩個部分:
- 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