Как я могу получить доступ к своему состоянию контекстного API в файле React app.js

Привет, я управляю своим состоянием приложения реакции с помощью Context API, и я могу деструктурировать состояние и функции моего контекста во всех файлах, кроме моего файла app.js.

Здесь я создал многоразовый файл под названием createDataContext, чтобы предотвратить написание дублированного кода при создании контекста и провайдера для каждого контекста.

import React, { createContext, useReducer } from 'react';

export default (reducer, actions, initialState) => {
  const Context = createContext();

  const Provider = ({ children }) => {
    const [state, dispatch] = useReducer(reducer, initialState);

    const boundActions = {};
    for(let key in actions){
      boundActions[key] = actions[key](dispatch);
    }

    return (
      <Context.Provider value={{ state, ...boundActions }}>
        { children }
      </Context.Provider>
    )
  }

  return { Context, Provider }
}

Вот мой AuthContext, который использует файл createDataContext

import createDataContext from "./createDataContext";
import api from '../api/api'

const authReducer = (state, action) => {
  switch(action.type){
    case 'signin':
      return { errorMessage: '', token: action.payload };
    case 'add_error':
      return { ...state, errorMessage: action.payload };
    default:
      return state;
  }
}

const login = dispatch => {
  return async (email, password) => {
    try {
      const res = await api.post('/users/login', { email, password });
      localStorage.setItem('token', res.data.token);
      dispatch({ type: 'signin', payload: res.data.token });
    }catch(err){
      dispatch({ type: 'add_error', payload: 'signin failed' })
    }
  }
}

export const { Context, Provider } = createDataContext(authReducer, { login }, {
  token: null,
  errorMessage: ''
});

Я могу использовать контекст и деструктор вне состояния и функций, таких как вход в систему, на моих страницах и компонентах, но не могу этого сделать в моем файле app.js.

import React, { useContext } from 'react';
import Home from './pages/home/Home';
import Login from './pages/login/Login';
import Profile from './pages/profile/Profile';
import Register from './pages/register/Register';
import { BrowserRouter as Router, Redirect, Route, Switch } from 'react-router-dom';
import Navbar from './components/navbar/Navbar';
import { Provider as AuthProvider } from './context/AuthContext';
import { Context } from './context/AuthContext';

function App() {
  const { state, login } = useContext(Context);

  return (
    <AuthProvider>
      <Router>
        <Navbar />
        <Switch>
          <Route exact path="/">
            <Home />
          </Route>
          <Route path="/login">
            <Login />
          </Route>
          <Route path="/register">
            <Register />
          </Route>
          <Route path="/profile/:id">
            <Profile />
          </Route>
        </Switch>
      </Router>
    </AuthProvider>
  );
}

export default App;

Я получаю сообщение об ошибке TypeError: Невозможно деструктурировать свойство state of Object (...) (...), поскольку оно не определено. Кто-нибудь может указать, что я или где я я ошибаюсь. Спасибо.


person Sy3d    schedule 23.06.2021    source источник


Ответы (1)


Вы не можете использовать контекст в том же компоненте, где он предоставляется. Чтобы обойти это, создайте еще один новый компонент, который является оболочкой для остальных дочерних элементов Provider.

// AppWrapper.jsx
import React from 'react'
import App from './app'
import { Provider as AuthProvider } from './context/AuthContext'

const AppWrapper = () => {
  return (
    <AuthProvider>
      <App />
    </AuthProvider>
  )
}

default export AppWrapper

Затем удалите <AuthProvider> из компонента app.js, и где бы вы ни вызывали <App /> в дереве, вместо этого вызовите <AppWrapper />. Затем внутри приложения вы можете использовать контекст, как вы пытаетесь это сделать.

person amaster    schedule 23.06.2021