Redux 毫無疑問是衆多 React 項目首選的狀態管理方案,但我以爲 Redux 的開發體驗並很差。javascript
好比當你正在開發一個很複雜的功能,中途須要不斷添加全局狀態,每次添加都不得不重複以下步驟:css
myFeature
。my-feature/actions.js
、my-feature/reducer.js
、my-feature/type.js
以上只是加個狀態而已,寫不少模板代碼仍是其次,最要命的是會打斷你寫代碼的思路。java
並且隨着項目愈來愈大, redux 的狀態樹也會變大,維護也會變困難。react
useContext
和 useReducer
是 React 16.8 引入的新 API。git
useContext
:可訪問全局狀態,避免一層層的傳遞狀態。github
useReducer
:用過 Redux 確定不會陌生,它主要用於更新複雜邏輯的狀態。redux
下面經過一個簡單例子介紹 useContext + useReducer 是如何替代 Redux 的。app
代碼已放到 codesandbox,查看完整代碼dom
這個例子只有一個功能,點擊按鈕改變字體顏色。ide
首先用 create-react-app 建立一個項目,也能夠在 CodeSandbox 上建立一個 React App。
import React from 'react'
const ShowArea = (props) => {
return (
<div style={{color: "blue"}}>字體顏色展現爲blue</div>
)
}
export default ShowArea
複製代碼
import React from "react";
const Buttons = props => {
return (
<React.Fragment> <button>紅色</button> <button>黃色</button> </React.Fragment> ); }; export default Buttons; 複製代碼
import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";
import ShowArea from './ShowArea'
import Buttons from './Buttons'
function App() {
return (
<div className="App"> <ShowArea /> <Button /> </div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement); 複製代碼
很明顯 ShowArea 組件須要一個顏色狀態,因此咱們建立 color.js 來處理狀態。
// color.js
import React, { createContext } from "react";
// 建立 context
export const ColorContext = createContext({});
/** * 建立一個 Color 組件 * Color 組件包裹的全部子組件均可以經過調用 ColorContext 訪問到 value */
export const Color = props => {
return (
<ColorContext.Provider value={{ color: "blue" }}> {props.children} </ColorContext.Provider> ); }; 複製代碼
修改 index.js,讓全部子組件均可以訪問到顏色。
// index.js
···
···
···
import { Color } from "./color";
function App() {
return (
<div className="App"> <Color> <ShowArea /> <Buttons /> </Color> </div>
);
}
···
···
···
複製代碼
在 ShowArea 組件中獲取顏色
// ShowArea.js
···
···
···
import { ColorContext } from "./color";
const ShowArea = props => {
const { color } = useContext(ColorContext);
return <div style={{ color: color }}>字體顏色展現爲{color}</div>;
};
···
···
···
複製代碼
接着在 color.js 中添加 reducer, 用於處理顏色更新的邏輯。
import React, { createContext, useReducer } from "react";
// 建立 context
export const ColorContext = createContext({});
// reducer
export const UPDATE_COLOR = "UPDATE_COLOR"
const reducer = (state, action) => {
switch(action.type) {
case UPDATE_COLOR:
return action.color
default:
return state
}
}
/** * 建立一個 Color 組件 * Color 組件包裹的全部組件均可以訪問到 value */
export const Color = props => {
const [color, dispatch] = useReducer(reducer, 'blue')
return (
<ColorContext.Provider value={{color, dispatch}}> {props.children} </ColorContext.Provider> ); }; 複製代碼
爲按鈕添加點擊事件,調用 dispatch 就能夠更新顏色了。
// buttons.js
import React, { useContext } from "react";
import { colorContext, UPDATE_COLOR } from "./color";
const Buttons = props => {
const { dispatch } = useContext(colorContext);
return (
<React.Fragment> <button onClick={() => { dispatch({ type: UPDATE_COLOR, color: "red" }); }} > 紅色 </button> <button onClick={() => { dispatch({ type: UPDATE_COLOR, color: "yellow" }); }} > 黃色 </button> </React.Fragment> ); }; export default Buttons; 複製代碼
因此 useContext + useReducer 徹底能夠替代 React 進行狀態管理。可是目前絕大多數 React 項目仍在使用 Redux,因此深刻學習 Redux 仍是頗有必要的。