useContext 在 useQuery 时返回 null
useContext returning null upon useQuery
我正在为设置页面制作一个包装器,以便它可以在每个设置页面上重复使用。在里面,有一个Context Provider,我在其中传递用户数据,但是尽管查询成功,它似乎从未传递任何东西。
SettingsWrap.tsx
export const UserContext = React.createContext(null);
const SettingsWrap = ({ children }) => {
const [session] = useSession();
const { data, loading } = useQuery<SettingsData, SettingsVars>(
SETTINGS_QUERY,
{
variables: {
id: session?.id,
},
skip: !session,
}
);
return (
<Grid container spacing={2}>
<Grid item xs={12} sm={4}>
<SettingList />
</Grid>
{data && !loading ? (
<UserContext.Provider value={data.userId}>
<Grid
item
xs={12}
sm={8}
style={{ height: "100vh", overflow: "auto" }}
>
<Container>{children}</Container>
</Grid>
</UserContext.Provider>
) : (
<Grid
item
xs={12}
sm={8}
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
height: "100vh",
}}
>
<CircularProgress />
</Grid>
)}
</Grid>
);
};
AccountSettings.tsx
const user: UserInterface = useContext(UserContext); // THIS IS NULL
这段代码有什么问题?
显然,当我在将“用户”传递给的子组件中使用 useContext 时,它工作得非常好。我在父级中使用上下文而不是实际组件是我的错误。
上下文有一个默认值,然后可以使用提供程序将其设置为不同的其他值,就像您所做的那样。提供者的值只影响组件的子树中的组件。相反,上下文的当前值是由最近的祖先提供者设置的值,或者如果 none 存在,则为上下文的默认值。
检查以下示例:
export const NumberContext = React.createContext(0); // default value
export default function App() {
return (
<div>
<Consumer /> // #1, shows 0
<NumberContext.Provider value={1}>
<Consumer /> // #2, shows 1
<NumberContext.Provider value={2}>
<Consumer /> // #3, shows 2
</NumberContext.Provider>
<div>
<div>
<Consumer /> // #4, shows 1
</div>
</div>
</NumberContext.Provider>
</div>
);
}
export function Consumer() {
const number = useContext(NumberContext)
return <p>{number}</p>
}
这是一个沙盒示例:https://codesandbox.io/s/react-contexts-6dlh1
- 第一个
Consumer
(#1
) 没有祖先提供者,因此它显示创建的上下文的默认值为 0。
- 第二个
Consumer
(#2
) 是值为 1 的提供者的直接子级,因此显示值为 1。
- 第三个
Consumer
(#3
) 有两个祖先提供者,但最近的祖先提供者提供值 2,因此这就是该组件显示的值。
- 第四个也是最后一个
Consumer
(#4
) 嵌套在第一个提供者之下(因为它位于第二个提供者之外,但仍在第一个提供者的子层次结构中)。因此它有一个值为 1 的祖先提供者,因此它也将显示值 1。
在您的示例中,SettingsList
(AccountSettings
的父级)是 UserContext
的假定消费者,没有祖先提供者(因为它不在您已包含在组件树中的提供程序)。因此 运行 useContext(UserContext)
将始终 return null
,默认值或 UserContext
,在您的组件的子树中。尝试将 SettingsList
放入具有祖先提供者的子树中,它将起作用。
我正在为设置页面制作一个包装器,以便它可以在每个设置页面上重复使用。在里面,有一个Context Provider,我在其中传递用户数据,但是尽管查询成功,它似乎从未传递任何东西。
SettingsWrap.tsx
export const UserContext = React.createContext(null);
const SettingsWrap = ({ children }) => {
const [session] = useSession();
const { data, loading } = useQuery<SettingsData, SettingsVars>(
SETTINGS_QUERY,
{
variables: {
id: session?.id,
},
skip: !session,
}
);
return (
<Grid container spacing={2}>
<Grid item xs={12} sm={4}>
<SettingList />
</Grid>
{data && !loading ? (
<UserContext.Provider value={data.userId}>
<Grid
item
xs={12}
sm={8}
style={{ height: "100vh", overflow: "auto" }}
>
<Container>{children}</Container>
</Grid>
</UserContext.Provider>
) : (
<Grid
item
xs={12}
sm={8}
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
height: "100vh",
}}
>
<CircularProgress />
</Grid>
)}
</Grid>
);
};
AccountSettings.tsx
const user: UserInterface = useContext(UserContext); // THIS IS NULL
这段代码有什么问题?
显然,当我在将“用户”传递给的子组件中使用 useContext 时,它工作得非常好。我在父级中使用上下文而不是实际组件是我的错误。
上下文有一个默认值,然后可以使用提供程序将其设置为不同的其他值,就像您所做的那样。提供者的值只影响组件的子树中的组件。相反,上下文的当前值是由最近的祖先提供者设置的值,或者如果 none 存在,则为上下文的默认值。
检查以下示例:
export const NumberContext = React.createContext(0); // default value
export default function App() {
return (
<div>
<Consumer /> // #1, shows 0
<NumberContext.Provider value={1}>
<Consumer /> // #2, shows 1
<NumberContext.Provider value={2}>
<Consumer /> // #3, shows 2
</NumberContext.Provider>
<div>
<div>
<Consumer /> // #4, shows 1
</div>
</div>
</NumberContext.Provider>
</div>
);
}
export function Consumer() {
const number = useContext(NumberContext)
return <p>{number}</p>
}
这是一个沙盒示例:https://codesandbox.io/s/react-contexts-6dlh1
- 第一个
Consumer
(#1
) 没有祖先提供者,因此它显示创建的上下文的默认值为 0。 - 第二个
Consumer
(#2
) 是值为 1 的提供者的直接子级,因此显示值为 1。 - 第三个
Consumer
(#3
) 有两个祖先提供者,但最近的祖先提供者提供值 2,因此这就是该组件显示的值。 - 第四个也是最后一个
Consumer
(#4
) 嵌套在第一个提供者之下(因为它位于第二个提供者之外,但仍在第一个提供者的子层次结构中)。因此它有一个值为 1 的祖先提供者,因此它也将显示值 1。
在您的示例中,SettingsList
(AccountSettings
的父级)是 UserContext
的假定消费者,没有祖先提供者(因为它不在您已包含在组件树中的提供程序)。因此 运行 useContext(UserContext)
将始终 return null
,默认值或 UserContext
,在您的组件的子树中。尝试将 SettingsList
放入具有祖先提供者的子树中,它将起作用。