반응형
여러 콘텍스트에 대응
저는 문맥을 통해 전해지는 기능을 사용하고 있습니다.
ChildComponent.contextType = SomeContext;
지금은 사용하고 있습니다.this.context.someFunction();
이거 되는구나.
2개의 다른 부모 컴포넌트의 기능이 필요한 경우 어떻게 해야 합니까?
16.3 Context API에서는 Function-as-a-Child 소비자 노드를 계속 사용할 수 있습니다.이는 React 문서에서 권장하는 작업입니다.
// Theme context, default to light theme
const ThemeContext = React.createContext('light');
// Signed-in user context
const UserContext = React.createContext({
name: 'Guest',
});
class App extends React.Component {
render() {
const {signedInUser, theme} = this.props;
// App component that provides initial context values
return (
<ThemeContext.Provider value={theme}>
<UserContext.Provider value={signedInUser}>
<Layout />
</UserContext.Provider>
</ThemeContext.Provider>
);
}
}
function Layout() {
return (
<div>
<Sidebar />
<Content />
</div>
);
}
// A component may consume multiple contexts
function Content() {
return (
<ThemeContext.Consumer>
{theme => (
<UserContext.Consumer>
{user => (
<ProfilePage user={user} theme={theme} />
)}
</UserContext.Consumer>
)}
</ThemeContext.Consumer>
);
}
컴포넌트의 컨텍스트에서 기능을 사용하려면 일반적으로 컴포넌트를 HOC로 랩하여 컨텍스트가 소품으로 전달되도록 합니다.
export const withThemeContext = Component => (
props => (
<ThemeContext.Consumer>
{context => <Component themeContext={context} {...props} />}
</ThemeContext.Consumer>
)
)
const YourComponent = ({ themeContext, ...props }) => {
themeContext.someFunction()
return (<div>Hi Mom!</div>)
}
export default withThemeContext(YourComponent)
React 16.8 이상을 실행하고 있는 경우 HOC를 사용하지 않고 후크를 사용하여 보다 깔끔하게 작업을 수행할 수도 있습니다.
import React, { useContext } from "react"
const YourComponent = props => {
const theme = useContext(ThemeContext)
const user = useContext(UserContext)
}
또, 이러한 콘텍스트를 많이 사용하는 경우는, 커스텀 훅을 만들어 한층 더 심플하게 할 수도 있습니다.
const useTheme = () => useContext(ThemeContext)
const useUser = () => useContext(UserContext)
const YourComponent = props => {
const theme = useTheme()
const user = useUser()
}
또 다른 해결책은 다른 콘텍스트를 제공하는 다른 콘텍스트를 작성하는 것입니다.
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>
또, 모든 콘텍스트를 1개의 콘텍스트로 간단하게 Marge 할 수도 있습니다.
const AppContext = React.createContext({
user: { name: 'Guest' },
theme: 'light',
})
ChildComponent.contextType = AppContext;
완료. 앱의 일부(다른 테마나 사용자 등)에 다른 컨텍스트가 있는 경우 새 값을 병합하기만 하면 됩니다.
이건 나한테 효과가 있었어.
<AuthProvider>
<ProvideSide>
<Component {...pageProps} />
</ProvideSide>
</AuthProvider>
인증 프로바이더에서 아이들을 통과시키고 컨텍스트를 제공하는 것이 전부입니다.
authprovider 컨텍스트 함수
export function AuthProvider({ children }) {
const auth = useProvideAuth();
return <authContext.Provider value={auth}>{children}</authContext.Provider>;
}
제공측 콘텐트
export function ProvideSide({ children }) {
const side = useProvideSide();
return <sideContext.Provider value={side}>{children}</sideContext.Provider>;
}
언급URL : https://stackoverflow.com/questions/53346462/react-multiple-contexts
반응형
'programing' 카테고리의 다른 글
두 개의 "선택"이 동일한지 확인합니다. (0) | 2023.03.13 |
---|---|
렌더링 메서드 내 약속 포함 Rendering React 구성 요소 (0) | 2023.03.13 |
스크립트를 대체하는 하위 테마용 wp_dequeue_script (0) | 2023.03.13 |
전송 시 JQuery가 빈 어레이를 삭제합니다. (0) | 2023.03.13 |
컨트롤러가 필요한 테스트 지침 (0) | 2023.03.13 |