React useContext 钩子如何用于控制应用程序和条件渲染?

How can the React useContext hook be used to control application and conditional rendering?

我是第一次尝试使用 React hooks,我想最终替换旧的上下文 API。我如何实现 useContext 挂钩来完成全局状态?

我一直在尝试关注 Medium 上的许多教程、其他 Stack overflow 帖子和一些随机博客帖子。下面是我目前的代码:

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);

这两个表单组件基本上是虚拟组件,其中包含最少的 JSX。

我不断收到多个 "TypeError: Cannot read property 'page' of undefined" 错误。这是使用新的 useContext 挂钩的不正确方法吗?

理想情况下,我希望每个表单都有一个 link,当您单击它时,您会变成另一个表单。即如果您在登录表单但需要注册,它会更改为注册表单,如果您在注册表单但已经有一个帐户,它会将您跳转到登录表单。

首先,您没有正确使用useContext hook 的Reducer Logic。您必须首先了解,除非您在层次结构中有提供者,否则您将无法使用上下文。由于 AppProvider 是在应用程序内部呈现的,因此您将无法在应用程序中使用上下文。

其次,你不能将组件作为标签存储在reducer中,如果你愿意,你可以存储它的引用

所以你的代码最终看起来像

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>
)

编辑:确保在您的页面解构周围添加数组。

useContext的使用错误。您在 useContext 的层次结构中没有任何提供者。

这是我已经实现的使用 reducer 的示例方法。

在 Store.js 中,初始化 React 上下文 -

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)