Как можно использовать хук React useContext для управления приложением и условным рендерингом? - PullRequest
1 голос
/ 17 мая 2019

Я пытаюсь использовать React-хуки впервые и хочу в итоге заменить старый контекстный API. Как реализовать хуки useContext для достижения глобального состояния?

Я пытался следовать нескольким учебникам по Medium, другим постам с переполнением стека и некоторым случайным постам в блоге. Ниже приведен код, который у меня есть:

APP.JS

import React from 'react';
import { AppProvider, useAppValue } from './AppContext';
import FormLogin from './FormLogin';
import FormRegister from './FormRegister';

const App = () => {
  const initialState = {
    page: <FormLogin/>
  }

  const reducer = (state, action) => {
    switch (action.type) {
      case 'loadLogin':
        return {
          ...state,
          page: <FormLogin/>
        };
      case 'loadRegister':
        return {
          ...state,
          page: <FormRegister/>
        };
      default:
        return state;
    }
  };

  let { page } = useAppValue();
  let currentPage = page ? page : <FormLogin/>

  return (
    <AppProvider initialState={initialState} reducer={reducer}>
      <div className="App">
        {currentPage}
      </div>
    </AppProvider>    
  );
}

export default App;

APPCONTEXT.JS

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

export const AppContext = createContext();
export const AppProvider = ({reducer, initialState, children}) => (
  <AppContext.Provider value={useReducer(reducer, initialState)}>
    {children}
  </AppContext.Provider>
);

export const useAppValue = () => useContext(AppContext);

Два компонента Form - это в основном фиктивные компоненты с минимальным количеством JSX.

Я получаю несколько ошибок «Ошибка типа: невозможно прочитать свойство« страница »с неопределенными» ошибками. Это неправильный способ использовать новый хук useContext?

В идеале я хочу, чтобы каждая форма имела ссылку, которая при нажатии изменяет вас на другую форму. Т.е., если вы находитесь в форме входа в систему, но должны зарегистрироваться, она изменится на форму регистрации, и если вы находитесь в форме регистрации, но у вас уже есть учетная запись, она переключит вас на форму входа.

Ответы [ 2 ]

2 голосов
/ 17 мая 2019

Использование useContext неверно.У вас нет провайдера в иерархии useContext.

Это пример использования редукторов, которые я реализовал.

В Store.js для инициализации контекста ответа -

import {createContext} from 'react';
const Context = createContext();
export default Context;

В Reducers.js, логика наличия общей системы управления состоянием,

import React, {useReducer} from 'react';
import Context from './Store';

const initialState = {
 count: 0,
 someothervalue: 'hello'
}

function reducer(state, action) {
 const {count, ...otherValues} = state;
 switch(action.type) {
    case 'increment':
        return {count: count + 1, ...otherValues};
    case 'decrement':
        return (count > 0) ? {count: count - 1, ...otherValues} : state;
    default:
        return state;
 }
}

const ReducerProvider = (props) => {
 const [state, dispatch] = useReducer(reducer, initialState);
 return (<Context.Provider value={{state, dispatch}}>
    {props.children}
 </Context.Provider>)
}

export default ReducerProvider;

В App.js,

<ReducerProvider>
  ..... Your Code .....
</ReducerProvider>

В Component.js,

import Context from '../Store';
....
....
....
const {state, dispatch} = useContext(Context);
return (... your component logic)
2 голосов
/ 17 мая 2019

Прежде всего, вы не правильно используете логику Reducer для ловушки useContext. Сначала вы должны понять, что если у вас нет поставщика в иерархии, вы не сможете использовать контекст. Поскольку AppProvider отображается внутри приложения, вы не сможете использовать контекст в приложении.

Во-вторых, вы не должны хранить компоненты как теги в редукторе, при желании вы можете сохранить его ссылку

Таким образом, ваш код будет наконец выглядеть как

import React from 'react';
import { AppProvider, useAppValue } from './AppContext';
import FormLogin from './FormLogin';
import FormRegister from './FormRegister';

  const initialState = {
    page: FormLogin
  }

  const reducer = (state, action) => {
    switch (action.type) {
      case 'loadLogin':
        return {
          ...state,
          page: FormLogin
        };
      case 'loadRegister':
        return {
          ...state,
          page: FormRegister
        };
      default:
        return state;
    }
  };

const App = () => {
  let [{ page: Page }] = useAppValue();

  return (

      <div className="App">
         <Page />
      </div>
  );
}

export default (props) => (
      <AppProvider initialState={initialState} reducer={reducer}>
          <App {...props} />
      </AppProvider>
)

РЕДАКТИРОВАТЬ: Обязательно добавьте массив вокруг деконструкции вашей страницы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...