javascript - Gatsby Context API 不呈现其值

标签 javascript reactjs gatsby react-context

尝试从 Context API 渲染状态,但在控制台中它显示为 未定义 并且不渲染任何内容。

这是上下文文件

import React, { useReducer, createContext } from "react"

export const GlobalStateContext = createContext()
export const GlobalDispatchContext = createContext()

const initialState = {
  isLoggedIn: "logged out",
}

function reducer(state, action) {
  switch (action.type) {
    case "TOGGLE_LOGIN":
      {
        return {
          ...state,
          isLoggedIn: state.isLoggedIn === false ? true : false,
        }
      }
      break

    default:
      throw new Error("bad action")
  }
}

const GlobalContextProvider = ({ children }) => {
  const [state, dispatch] = useReducer(reducer, initialState)
  return (
    <GlobalStateContext.Provider value={state}>
      {children}
    </GlobalStateContext.Provider>
  )
}

export default GlobalContextProvider

这里是应该呈现值(value)的地方

import React, { useContext } from "react"
import {
  GlobalStateContext,
  GlobalDispatchContext,
} from "../context/GlobalContextProvider"

const Login = () => {
  const state = useContext(GlobalStateContext)
  console.log(state)
  return (
    <>
      <GlobalStateContext.Consumer>
        {value => <p>{value}</p>}
      </GlobalStateContext.Consumer>
    </>
  )
}

export default Login

我之前尝试过使用类组件进行相同的操作,但没有解决问题。当我控制台日志上下文时,它看起来像具有未定义值的对象。

有什么想法吗?

最佳答案

Context API 概述

从评论来看,潜在的问题似乎是您没有渲染 <Login />作为 <GlobalContextProvider /> 的 child 。当您使用上下文使用者时,无论是作为钩子(Hook)还是作为函数,组件树中的某个位置都需要有一个匹配的提供者作为其父级。

例如,这些不起作用:

<div>
    <h1>Please log in!</h1>
    <Login />
</div>
<React.Fragment>
    <GlobalContextProvider />
    <Login />
</React.Fragment>

因为在这两个组件中,登录组件要么是上下文提供程序的同级组件,要么完全缺少提供程序。

但是,这会起作用:

<React.Fragment>
    <GlobalContextProvider>
        <Login />
    </GlobalContextProvider>
</React.Fragment>

因为 Login 组件是 GlobalContextProvider 的子组件。

与 Gatsby 相关

无论您使用什么库或框架来制作应用程序,这个概念都是正确的。具体来说,在 Gatsby 中,您需要做一些工作才能使其在页面级别工作,但这是可能的。

假设您定义了 Layout.jsx 文件和以下页面:

const Index = () => (
    <Layout>
        <h1>{something that uses context}</h1>
    </Layout>
)

您有 2 个选择:

  1. 更简单的选择是提取 h1到它自己的组件文件中。然后你可以输入 GlobalContextProviderLayout并将上下文消费者放入新组件中。这是可行的,因为 h1 被渲染为布局的子级。
  2. 是进行一些洗牌。

您可能倾向于将提供程序放入布局中并尝试在页面中使用它。您可能认为这会起作用,因为 h1 仍然被渲染为布局的子级,对吧?这是正确的,但 h1 并未消耗上下文。上下文由 h1 渲染并由 Index 消耗,Index 是 <Layout> 的父级。 。在页面级别使用它是可能的,但您必须做的是创建另一个组件(IndexContent或类似的组件),在那里使用您的上下文,然后渲染那个 作为布局的子元素。举个例子(为简洁起见,省略了导入):

const Layout = ({children}) => (
    <GlobalContextProvider>
        {children}
    </GlobalContextProvider>
);

const IndexContent = () => {
    const {text} = useContext(GlobalStateContext);
    return <h1>{text}</h1>;
}

const Index = () => (
    <Layout>
        <IndexContent />
    </Layout>
);

关于javascript - Gatsby Context API 不呈现其值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60653932/

相关文章:

javascript - jQuery 动画 Complete 在事件完成之前触发

javascript - 如何使用reactjs和react-router实现正确的布局

graphql - 如何向 graphQL 查询添加变量?

graphql - Gatsby - 使用 createRemoteFileNode 获取远程图像

javascript - Gatsby Config 在 Javascript 文件中给出错误 ??运算符(operator)

javascript - 带有 Javascript 数组的 Chartjs 标签

javascript - 使用 jQuery addclass 添加 CSS 子类

javascript - 如何在Angularjs中推迟img src url计算?

css - 如何使用 CSS-in-JS 方法设置 body 标签的样式?

reactjs - 需要了解配置 React 和 cypress 的最佳方法