上下文
¥Context
Context 允许你将值传递给树深处的子级,而不必通过 props 将其传递到中间的每个组件。一个非常流行的用例是主题化。简而言之,可以想出一种在 Preact 中进行 pub-sub 风格更新的方法。
¥Context allows you to pass a value to a child deep down the tree without having to pass it through every component in-between via props. A very popular use case for this is theming. In a nutshell context can be thought of a way to do pub-sub-style updates in Preact.
使用上下文有两种不同的方式:通过较新的 createContext
API 和旧版上下文 API。两者之间的区别在于,当中间的组件通过 shouldComponentUpdate
中止渲染时,旧组件无法更新子组件。这就是为什么我们强烈建议始终使用 createContext
。
¥There are two different ways to use context: Via the newer createContext
API and the legacy context API. The difference between the two is that the legacy one can't update a child when a component inbetween aborts rendering via shouldComponentUpdate
. That's why we highly recommend to always use createContext
.
createContext
首先我们需要创建一个可以传递的上下文对象。这是通过 createContext(initialValue)
函数完成的。它返回一个用于设置上下文值的 Provider
组件和一个从上下文中检索值的 Consumer
组件。
¥First we need to create a context object we can pass around. This is done via the createContext(initialValue)
function. It returns a Provider
component that is used to set the context value and a Consumer
one which retrieves the value from the context.
仅当上下文在树中其上方没有匹配的 Provider
时,才使用 initialValue
参数。这可能有助于单独测试组件,因为它避免了创建封装 Provider
的需要。
¥The initialValue
argument is only used when a context does not have a matching Provider
above it in the tree. This may be helpful for testing components in isolation, as it avoids the need for creating a wrapping Provider
.
const Theme = createContext('light');
function ThemedButton(props) {
return (
<Theme.Consumer>
{theme => {
return <button {...props} class={'btn ' + theme}>Themed Button</button>;
}}
</Theme.Consumer>
);
}
function App() {
return (
<Theme.Provider value="dark">
<SomeComponent>
<ThemedButton />
</SomeComponent>
</Theme.Provider>
);
}
Run in REPL使用上下文的更简单方法是通过 useContext 钩子。
¥An easier way to use context is via the useContext hook.
旧版上下文 API
¥Legacy Context API
我们包含旧版 API 主要是出于向后兼容性的原因。它已被 createContext
API 取代。旧版 API 存在已知问题,例如如果中间存在在 shouldComponentUpdate
中返回 false
的组件,则会阻止更新。如果你仍然需要使用它,请继续阅读。
¥We include the legacy API mainly for backwards-compatibility reasons. It has been superseded by the createContext
API. The legacy API has known issues like blocking updates if there are components in-between that return false
in shouldComponentUpdate
. If you nonetheless need to use it, keep reading.
要通过上下文传递自定义变量,组件需要具有 getChildContext
方法。在那里你返回要存储在上下文中的新值。可以通过函数组件中的第二个参数或基于类的组件中的 this.context
来访问上下文。
¥To pass down a custom variable through the context, a component needs to have the getChildContext
method. There you return the new values you want to store in the context. The context can be accessed via the second argument in function components or this.context
in a class-based component.
function ThemedButton(props, context) {
return (
<button {...props} class={'btn ' + context.theme}>
Themed Button
</button>
);
}
class App extends Component {
getChildContext() {
return {
theme: 'light'
}
}
render() {
return (
<div>
<SomeOtherComponent>
<ThemedButton />
</SomeOtherComponent>
</div>
);
}
}
Run in REPL