上一节介绍了 useState、useEffect 这两个最基本的 API,接下来介绍的 useContext 是 React 帮你封装好的,用来处理多层级传递数据的方式,跨层级祖先组件想要给孙子组件传递数据的时候,除了一层层 props 往下透传之外,我们还可以使用 React Context API 来帮我们做这件事,举个简单的例子:
useContext 减少组件层级
const { Provider, Consumer } = React.createContext(null);
function Bar() {
return <Consumer>{color => <div>{color}</div>}</Consumer>;
}
function Foo() {
return <Bar />;
}
function App() {
return (
<Provider value={"grey"}>
<Foo />
</Provider>
);
}
通过 React createContext 的语法,在 APP 组件中可以跨过 Foo 组件给 Bar 传递数据。而在 React Hooks 中,我们可以使用 useContext 进行改造。
const colorContext = React.createContext("gray");
function Bar() {
const color = useContext(colorContext);
return <div>{color}</div>;
}
function Foo() {
return <Bar />;
}
function App() {
return (
<colorContext.Provider value={"red"}>
<Foo />
</colorContext.Provider>
);
}
传递给 useContext 的是 context 而不是 consumer,返回值即是想要透传的数据了。用法很简单,使用 useContext 可以解决 Consumer 多状态嵌套的问题。
function HeaderBar() {
return (
<CurrentUser.Consumer>
{user =>
<Notifications.Consumer>
{notifications =>
<header>
Welcome back, {user.name}!
You have {notifications.length} notifications.
</header>
}
}
</CurrentUser.Consumer>
);
}
而使用 useContext 则变得十分简洁,可读性更强且不会增加组件树深度。
function HeaderBar() {
const user = useContext(CurrentUser);
const notifications = useContext(Notifications);
return (
<header>
Welcome back, {user.name}!
You have {notifications.length} notifications.
</header>
);
}
useReducer的使用
useReducer 这个 Hooks 在使用上几乎跟 Redux/React-Redux 一模一样,唯一缺少的就是无法使用 redux 提供的中间件。我们将上述的计时器组件改写为 useReducer。
import React, { useReducer } from "react";
const initialState = {
count: 0
};
function reducer(state, action) {
switch (action.type) {
case "increment":
return { count: state.count + action.payload };
case "decrement":
return { count: state.count - action.payload };
default:
throw new Error();
}
}
function App() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<>
Count: {state.count}
<button onClick={() => dispatch({ type: "increment", payload: 5 })}>
+
</button>
<button onClick={() => dispatch({ type: "decrement", payload: 5 })}>
-
</button>
</>
);
}
用法跟 Redux 基本上是一致的,用法也很简单,算是提供一个 mini 的 Redux 版本。
关注我,下一节学习 useContext 减少组件层级和useReducer的使用。