我正在使用通过上下文传递的函数。
ChildComponent.contextType = SomeContext;
现在我使用 this.context.someFunction();
。这行得通。
如果我需要来自两个不同父组件的函数,我该怎么做?
原文由 ATOzTOA 发布,翻译遵循 CC BY-SA 4.0 许可协议
另一种解决方案是创建一个单独的上下文来提供其他上下文:
import React, { createContext, memo, useContext } from "react";
import isEqual from "react-fast-compare";
export const MultiContext = createContext(null);
MultiContext.displayName = "MultiContext";
export const MultiContextProvider = memo(
function({ map, children }) {
const contextMap = {};
for (const i in map) {
contextMap[i] = useContext(map[i]);
}
return (
<MultiContext.Provider value={contextMap}>
{children}
</MultiContext.Provider>
);
},
(prevProps, nextProps) => isEqual(prevProps.children, nextProps.children)
);
MultiContextProvider.displayName = "MultiContextProvider";
用法示例:
class DemoConsumer extends React.Component {
static contextType = MultiContext;
render() {
return JSON.stringify({
someValue: this.context.SomeContext.someValue,
otherValue: this.context.OtherContext.otherValue,
});
}
}
function App() {
return (
<MultiContextProvider map={{ SomeContext, OtherContext }}>
<MultiContextDemoClassConsumer />
</MultiContextProvider>
);
}
演示:
const {
createContext,
memo,
useContext,
useState,
useEffect,
} = React;
const MultiContext = createContext(null);
MultiContext.displayName = "MultiContext";
const MultiContextProvider = memo(
function({ map, children }) {
console.log("render provider");
const contextMap = {};
for (const i in map) {
contextMap[i] = useContext(map[i]);
}
return (
<MultiContext.Provider value={contextMap}>
{children}
</MultiContext.Provider>
);
},
(prevProps, nextProps) => isEqual(prevProps.children, nextProps.children)
);
MultiContextProvider.displayName = "MultiContextProvider";
const initialMinutes = new Date().getMinutes();
const MinutesContext = createContext(initialMinutes);
MinutesContext.displayName = "MinutesContext";
const IncrementContext = createContext(0);
IncrementContext.displayName = "IncrementContext";
class MultiContextDemoClassConsumer extends React.Component {
static contextType = MultiContext;
render() {
return JSON.stringify(this.context);
}
}
const multiContextMap = { MinutesContext, IncrementContext };
function App() {
const forceUpdate = useForceUpdate();
const [minutes, setMinutes] = useState(initialMinutes);
useEffect(() => {
const timeoutId = setInterval(() => {
// console.log('set minutes')
setMinutes(new Date().getMinutes());
}, 1000);
return () => {
clearInterval(timeoutId);
};
}, [setMinutes]);
const [increment, setIncrement] = useState(0);
console.log("render app");
return (
<MinutesContext.Provider value={minutes}>
<IncrementContext.Provider value={increment}>
<MultiContextProvider map={multiContextMap}>
<MultiContextDemoClassConsumer />
</MultiContextProvider>
<button onClick={() => setIncrement(i => i + 1)}>Increment</button>
<button onClick={forceUpdate}>Force Update</button>
</IncrementContext.Provider>
</MinutesContext.Provider>
);
}
ReactDOM.render(<App />, document.getElementById("root"));
<script type="module">
import React from 'https://dev.jspm.io/react@16';
import ReactDOM from 'https://dev.jspm.io/react-dom@16';
import useForceUpdate from 'https://dev.jspm.io/use-force-update@1.0.7';
import isEqual from 'https://dev.jspm.io/react-fast-compare@3.0.1';
window.React = React;
window.ReactDOM = ReactDOM;
window.useForceUpdate = useForceUpdate.default;
window.isEqual = isEqual;
</script>
<div id="root"></div>
原文由 Dimitar Nestorov 发布,翻译遵循 CC BY-SA 4.0 许可协议
您仍然可以将函数作为子消费者节点与 16.3 上下文 API 一起使用,这是 React 文档建议做 的:
要在组件的上下文中使用函数,您通常会将组件包装在 HOC 中,以便将上下文作为 props 传入:
如果您正在运行 React 16.8+,您还可以使用钩子更干净地执行此操作,而无需使用 HOC:
或者,如果您大量使用这些上下文,您甚至可以制作自定义挂钩以进一步简化: