Gatsby Context API не отображает свою ценность - PullRequest
0 голосов
/ 12 марта 2020

Пытается отобразить состояние из Context API, но в консоли оно отображается как undefined и ничего не отображает.

здесь находится файл контекста

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

, а здесь - где значение должно быть отображено

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

Я пытался сделать то же самое с компонентом класса, но это не решило проблему. Когда я поддерживаю контекст журнала, он выглядит как объект с неопределенными значениями.

Есть идеи?

1 Ответ

1 голос
/ 12 марта 2020

Контекстный API в целом

Из комментариев кажется, что потенциальная проблема заключается в том, что вы не визуализируете <Login /> как дочерний элемент <GlobalContextProvider />. Когда вы используете получателя контекста, либо в качестве ловушки, либо в качестве функции, где-то в дереве компонентов должен быть соответствующий поставщик в качестве родительского элемента.

Например, они не будут работать:

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

, поскольку в обоих из них компонент Login является либо родным поставщиком поставщика контекста, либо поставщик полностью отсутствует.

Это, однако, будет работать:

<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 в его собственный файл компонента. Затем вы можете поместить GlobalContextProvider в Layout и поместить контекстного потребителя в новый компонент. Это сработает, потому что h1 визуализируется как дочерний элемент макета.
  2. Это сделать некоторую перестановку.

Возможно, вы захотите поместить провайдера в макет и попробовать потреблять его на странице. Вы можете подумать, что это сработает, потому что h1 по-прежнему отображается как дочерний элемент макета, верно? Это правильно, но контекст не используется h1. Контекст визуализируется h1, а потребляется Index, который является родителем <Layout>. Использование его на уровне страницы возможно, но вам нужно создать другой компонент (IndexContent или что-то подобное), использовать ваш контекст в там и визуализировать , что как ребенок макета. В качестве примера (с кратким описанием импорта):

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

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

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