useContext 在 useQuery 时返回 null

Posted

技术标签:

【中文标题】useContext 在 useQuery 时返回 null【英文标题】:useContext returning null upon useQuery 【发布时间】:2021-07-18 05:16:34 【问题描述】:

我正在为设置页面制作一个包装器,以便它可以在每个设置页面上重复使用。在其中,有一个 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

这段代码有什么问题?

【问题讨论】:

&lt;AccountSettings/&gt; 组件是 &lt;SettingsWrap /&gt; 的子组件吗? 是的,那里有用户被传递到的子组件。 其他子组件是否可以通过UserContext访问用户? 不,它们的 props 由拥有 useContext 的父组件提供 【参考方案1】:

上下文有一个默认值,然后可以通过使用提供程序设置为不同的其他值,就像您所做的那样。提供者的值仅影响组件的子子树中的组件。相反,上下文的当前值是最近的祖先提供者设置的值,如果不存在,则为上下文的默认值。

检查以下示例:

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。

在您的示例中,SettingsListAccountSettings 的父级)是UserContext 的假定使用者,没有祖先提供者(因为它不位于组件树中包含的提供者之下)。因此,运行useContext(UserContext) 将始终在组件的子树中返回null,默认值或UserContext。尝试将SettingsList 放在具有祖先提供程序的子树中,它会起作用。

【讨论】:

这就是我后来在尝试更多玩弄时才意识到的,谢谢!【参考方案2】:

显然,当我在传递“用户”的子组件中使用 useContext 时,它工作得非常好。在父组件中使用上下文而不是实际组件是我的错误。

【讨论】:

以上是关于useContext 在 useQuery 时返回 null的主要内容,如果未能解决你的问题,请参考以下文章

返回上一个屏幕时执行 useQuery() 挂钩反应原生堆栈导航器

在功能组件中,useContext 在 console.log 中工作,但在渲染时返回错误

useContext 返回未定义

使用 useQuery 进行批处理反应钩子返回未定义

从 Vue 3 组合 API 中的函数内部返回 Apollo useQuery 结果

如何在反应路由器中调用阿波罗客户端 useQuery?