英文:
ReactJS with nested context providers: useContext always returns undefined
问题
Main.js
import { MyProvider } from "../../contexts/MyProvider.js";
import { YourProvider } from "../../contexts/YourProvider.js";
import Header from "./Header.js";
import Footer from "./Footer.js";
export default function Main({children}) {
return (
<MyProvider>
<YourProvider>
<Header/>
<main>
<div>
{children}
</div>
</main>
<Footer/>
</YourProvider>
</MyProvider>
);
}
MyProvider.js/YourProvider.js
import { createContext, useState, useEffect } from 'react';
import { getMyValue } from "../../lib.js";
export const MyContext = createContext();
export function MyProvider({children}) {
const [myValue, setMyValue] = useState(undefined);
useEffect(() => {
getMyValue().then(result => {
setMyValue(result);
});
}, []);
return (
<MyContext.Provider value={myValue}>
{children}
</MyContext.Provider>
);
}
Child1.js
import { useContext, useEffect } from "react";
import { MyContext } from "../../contexts/MyProvider.js";
import { YourContext } from "../../contexts/YourProvider.js";
import Main from "./Main.js";
import Child2 from "./Child2.js";
export default function Child1({children}) {
const myValue = useContext(MyContext);
const yourValue = useContext(YourContext);
useEffect(() => {
console.log(myValue); // always undefined
console.log(yourValue); // always undefined
}, [myValue, yourValue]);
return (
<Main>
<p>{myValue}</p>
<p>{yourValue}</p>
<Child2/>
</Main>
);
}
Child2.js
import { useContext, useEffect } from "react";
import { MyContext } from "../../contexts/MyProvider.js";
import { YourContext } from "../../contexts/YourProvider.js";
export default function Child2({children}) {
const myValue = useContext(MyContext);
const yourValue = useContext(YourContext);
useEffect(() => {
console.log(myValue); // initially undefined, then the real value
console.log(yourValue); // initially undefined, then the real value
}, [myValue, yourValue]);
return (
<div>
<p>{myValue}</p>
<p>{yourValue}</p>
</div>
);
}
英文:
I have a wrapper component (Main.js) which wraps around all sites in my ReactJS project. I use multiple providers/contexts (MyProvider.js/YourProvider.js) which asynchronously load a value which is used in various child components. They are nested in my Main.js.
My problem is that the direct child components of Main.js (Child1.js) only receive undefined when accessing the contexts. Even useEffects do not detect the changes. The child components of the child components (Child2.js) also receive undefined, but are changed after.
Why is this the case?
Why does it only occur of the direct children and why does it work for the sub children?
Is this connected to the nesting of the providers?
Here a small example:
Main.js
import { MyProvider } from "../../contexts/MyProvider.js";
import { YourProvider } from "../../contexts/YourProvider.js";
import Header from "./Header.js";
import Footer from "./Footer.js";
export default function Main({children}) {
return (
<MyProvider>
<YourProvider>
<Header/>
<main>
<div>
{children}
</div>
</main>
<Footer/>
</YourProvider>
</MyProvider>
);
}
MyProvider.js/YourProvider.js
import { createContext, useState, useEffect } from 'react';
import { getMyValue } from "../../lib.js";
export const MyContext = createContext();
export function MyProvider({children}) {
const [myValue, setMyValue] = useState(undefined);
useEffect(() => {
getMyValue().then(result => {
setMyValue(result);
});
}, []);
return (
<MyContext.Provider value={myValue}>
{children}
</MyContext.Provider>
);
}
Child1.js
import { useContext, useEffect } from "react";
import { MyContext } from "../../contexts/MyProvider.js";
import { YourContext } from "../../contexts/YourProvider.js";
import Main from "./Main.js";
import Child2 from "./Child2.js";
export default function Child1({children}) {
const myValue = useContext(MyContext);
const yourValue = useContext(YourContext);
useEffect(() => {
console.log(myValue); // always undefined
console.log(yourValue); // always undefined
}, [myValue, yourValue]);
return (
<Main>
<p>{myValue}</p>
<p>{yourValue}</p>
<Child2/>
</Main>
);
}
Child2.js
import { useContext, useEffect } from "react";
import { MyContext } from "../../contexts/MyProvider.js";
import { YourContext } from "../../contexts/YourProvider.js";
export default function Child2({children}) {
const myValue = useContext(MyContext);
const yourValue = useContext(YourContext);
useEffect(() => {
console.log(myValue); // initially undefined, then the real value
console.log(yourValue); // initially undefined, then the real value
}, [myValue, yourValue]);
return (
<div>
<p>{myValue}</p>
<p>{yourValue}</p>
</div>
);
}
答案1
得分: 1
你正在访问 Child1
中 Main
上方的 MyContext
和 YourContext
。上下文消费者必须是其提供者的子元素文档。
在 Child2
中可行,因为您将其作为 Main
的子元素传递,并且 Main
的子元素被定义为 MyProvider
和 YourProvider
的子元素。
您需要做的是将提供者移到消费者上方,例如:
function App() {
return (
<MyProvider>
<YourProvider>
<Main>
<Child1/>
</Main>
</YourProvider>
</MyProvider>
);
}
export default function Child1({children}) {
const myValue = useContext(MyContext);
const yourValue = useContext(YourContext);
useEffect(() => {
console.log(myValue); // 始终为undefined
console.log(yourValue); // 始终为undefined
}, [myValue, yourValue]);
return (
<>
<p>{myValue}</p>
<p>{yourValue}</p>
<Child2/>
</>
);
}
英文:
You are accessing MyContext
and YourContext
above Main
in Child1
. Context consumers must be children of their providers docs.
It works in Child2
because you are passing it as a child to Main
and Main
's children are defined as children of MyProvider
and YourProvider
.
What you need to do is move your providers above your consumers for example:
function App() {
return (
<Main>
<Child1/>
</Main>
);
}
export default function Child1({children}) {
const myValue = useContext(MyContext);
const yourValue = useContext(YourContext);
useEffect(() => {
console.log(myValue); // always undefined
console.log(yourValue); // always undefined
}, [myValue, yourValue]);
return (
<>
<p>{myValue}</p>
<p>{yourValue}</p>
<Child2/>
</>
);
}
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论