尝试从 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 个选择:
- 更简单的选择是提取
h1
到它自己的组件文件中。然后你可以输入GlobalContextProvider
在Layout
并将上下文消费者放入新组件中。这是可行的,因为 h1 被渲染为布局的子级。 - 是进行一些洗牌。
您可能倾向于将提供程序放入布局中并尝试在页面中使用它。您可能认为这会起作用,因为 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/