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

时间:2019-05-17 04:56:45

标签: reactjs react-hooks react-context

我正在尝试第一次使用React钩子,并且我最终希望替换旧的上下文API。如何实现useContext挂钩来完成全局状态?

我一直在尝试遵循有关Medium,其他Stack溢出文章以及一些随机博客文章的教程。以下是我目前拥有的代码:

APP.JS

{
  props: ['value'],
  methods: {
    mEmit: function(EVT) {
      const VAL      = EVT.target.value;
      var   FILTERED = myFilterFunction(VAL);
      this.$emit('input', FILTERED);
      this.$forceUpdate();
    }
  }
}

APPCONTEXT.JS

  <input type="text" v-bind:value="value" v-on:input="mEmit($event)" />

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

我不断收到多个“ TypeError:无法读取未定义的属性'page'”错误。这是使用新的useContext钩子的不正确方法吗?

理想情况下,我希望每个表单都有一个链接,当单击该链接时,会将您切换到另一个表单。即,如果您在登录表单中但需要注册,它将更改为注册表单;如果您在注册表单中但已经拥有一个帐户,则会将您切换到登录表单。

2 个答案:

答案 0 :(得分:2)

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

第二,您不得将组件作为标签存储在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>
)

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

答案 1 :(得分:2)

useContext的使用是错误的。您在useContext的层次结构中没有任何Provider。

这是使用我暗示的减速器的示例方法。

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