admin管理员组文章数量:1326063
I understand React Context is useful for sharing state across a deep ponent tree without having to do prop drilling. However, I can't find a good way to share the same context values across multiple separate ponent trees. The app I work in isn't a true React front-end; rather, it has a few React trees sprinkled throughout the page. I'd like to share state among them using context. I know Redux can handle this, but I'm trying to avoid using that if possible.
// counter-context.jsx
import React, { useState, createContext } from 'react';
const CounterContext = createContext();
const CounterContextProvider = ({ children }) => {
const [counter, setCounter] = useState(0);
function increment() {
setCounter(counter + 1);
}
return (
<CounterContext.Provider value={{ counter, increment }}>
{children}
</CounterContext.Provider>
);
};
export { CounterContextProvider, CounterContext };
// FirstComponent.jsx
import React, { useContext } from 'react';
import { render } from 'react-dom';
import { CounterContextProvider, CounterContext } from './CounterContext';
const FirstComponent = () => {
const { counter } = useContext(CounterContext);
return <p>First ponent: {counter}</p>;
};
render(
<CounterContextProvider>
<FirstComponent />
</CounterContextProvider>,
document.getElementById('first-ponent')
);
// SecondComponent.jsx
import React, { useContext } from 'react';
import { render } from 'react-dom';
import CounterContext from './CounterContext';
const SecondComponent = () => {
const { counter } = useContext(CounterContext);
return <p>Second ponent: {counter}</p>;
};
render(
<CounterContextProvider>
<SecondComponent />
</CounterContextProvider>,
document.getElementById('second-ponent')
);
If I add a button in FirstComponent
that invokes increment
, I want the updated counter
value to also reflect in SecondComponent
. But given a new instance of CounterContextProvider
is created, I'm not sure how to acplish that. Is there a relatively clean way, or am I stuck with Redux?
I understand React Context is useful for sharing state across a deep ponent tree without having to do prop drilling. However, I can't find a good way to share the same context values across multiple separate ponent trees. The app I work in isn't a true React front-end; rather, it has a few React trees sprinkled throughout the page. I'd like to share state among them using context. I know Redux can handle this, but I'm trying to avoid using that if possible.
// counter-context.jsx
import React, { useState, createContext } from 'react';
const CounterContext = createContext();
const CounterContextProvider = ({ children }) => {
const [counter, setCounter] = useState(0);
function increment() {
setCounter(counter + 1);
}
return (
<CounterContext.Provider value={{ counter, increment }}>
{children}
</CounterContext.Provider>
);
};
export { CounterContextProvider, CounterContext };
// FirstComponent.jsx
import React, { useContext } from 'react';
import { render } from 'react-dom';
import { CounterContextProvider, CounterContext } from './CounterContext';
const FirstComponent = () => {
const { counter } = useContext(CounterContext);
return <p>First ponent: {counter}</p>;
};
render(
<CounterContextProvider>
<FirstComponent />
</CounterContextProvider>,
document.getElementById('first-ponent')
);
// SecondComponent.jsx
import React, { useContext } from 'react';
import { render } from 'react-dom';
import CounterContext from './CounterContext';
const SecondComponent = () => {
const { counter } = useContext(CounterContext);
return <p>Second ponent: {counter}</p>;
};
render(
<CounterContextProvider>
<SecondComponent />
</CounterContextProvider>,
document.getElementById('second-ponent')
);
If I add a button in FirstComponent
that invokes increment
, I want the updated counter
value to also reflect in SecondComponent
. But given a new instance of CounterContextProvider
is created, I'm not sure how to acplish that. Is there a relatively clean way, or am I stuck with Redux?
- You can create a context for the mon parent of those two ponents and pass only the info you need. – Praneeth Paruchuri Commented Sep 9, 2019 at 20:05
- 3 The two ponents don't have a mon parent – Andrew Gibson Commented Sep 9, 2019 at 20:20
- Can you clarify how redux could solve this problem? I am in a similar situation but I do have redux available to me. Thanks in advance! – austinbruch Commented Sep 3, 2020 at 14:46
3 Answers
Reset to default 1The two ponents can be rendered using react Portal so that they both fall under the same Parent.Now there will be one provider that can be used by both the ponents
As Hari Abinesh mentioned, portals is a way to solve this problem, if your use case is not too plex.
Docs: https://reactjs/docs/portals.html
// counter-context.jsx
import React, { useState, createContext } from 'react';
const CounterContext = createContext();
const CounterContextProvider = ({ children }) => {
const [counter, setCounter] = useState(0);
function increment() {
setCounter(counter + 1);
}
return (
<CounterContext.Provider value={{ counter, increment }}>
{children}
</CounterContext.Provider>
);
};
export { CounterContextProvider, CounterContext };
// FirstComponent.jsx
import React, { useContext } from 'react';
import { render, createPortal } from 'react-dom';
import { CounterContextProvider, CounterContext } from './CounterContext';
const FirstComponent = () => {
const { counter } = useContext(CounterContext);
const portalElement = document.getElementById('span-portal')
return (
<React.Fragment>
<p>First ponent: {counter}</p>
{createPortal(counter, portalElement)}
</React.Fragment>
);
};
render(
<CounterContextProvider>
<FirstComponent />
</CounterContextProvider>,
document.getElementById('first-ponent')
);
// SecondComponent.jsx
import React from 'react';
import { render } from 'react-dom';
const SecondComponent = () => {
return <p>Second ponent: <span id='span-portal'></span> </p>;
};
// At this point, you might not even need context at all if it's only going
// to be rendered from one ponent.
render(
<SecondComponent />,
document.getElementById('second-ponent')
);
Another way is to use react-relink. It is much simpler than Redux, designed to work across different React ponent trees and you don't need to wrap your ponents in any <Provider>
s. That is, if you're willing to resort to more than just built-in React solutions.
// counter-context.jsx -> counter-source.jsx
import { createSource, useRelinkValue } from 'react-relink';
export const CounterSource = createSource({
default: 1,
})
export function useCounterValue() {
return useRelinkValue(CounterSource);
}
export function incrementCounter() {
CounterSource.set(c => c + 1)
}
// FirstComponent.jsx
import React from 'react';
import { render } from 'react-dom';
import { useCounterValue } from './counter-source';
const FirstComponent = () => {
const counter = useCounterValue();
return <p>First ponent: {counter}</p>;
};
render(
<FirstComponent />,
document.getElementById('first-ponent')
);
// SecondComponent.jsx
import React from 'react';
import { render } from 'react-dom';
import { useCounterValue } from './counter-source';
const SecondComponent = () => {
const counter = useCounterValue();
return <p>Second ponent: {counter}</p>;
};
render(
<SecondComponent />,
document.getElementById('second-ponent')
);
You cannot share the context between two separate states. Unless you will be duplicating your context on the window object and reading from it. Also, there are these package which might help, however, this is very unadvisable: https://www.npmjs./package/@fluentui/global-context, https://github./dai-shi/use-context-selector#bridgeprovider
本文标签: javascriptHow to share React context state across separately mounted component treesStack Overflow
版权声明:本文标题:javascript - How to share React context state across separately mounted component trees - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1742196413a2431162.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论