简体   繁体   English

useContext 中的调度在 handleClick 上不起作用

[英]Dispatch in useContext not working on handleClick

I am trying to do a simple dispatch to the reducer, however I am not sure on why it's not updating or triggering changes to the context state.我正在尝试对减速器进行简单的调度,但是我不确定它为什么不更新或触发对上下文 state 的更改。

Below is my Provider code along with it's custom hook.下面是我的 Provider 代码及其自定义钩子。

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

export const SET_SHOW = "SET_SHOW";

interface SetShow {
    type: typeof SET_SHOW;
    show: boolean;
}

type AppActionTypes = SetShow;

interface AppState {
    show: boolean;
}

interface ContextType {
    state: AppState;
    dispatch: Dispatch<AppActionTypes>;
}


const INITIAL_STATE = {
    show: false
}

const AppContext = createContext<ContextType>(
    { 
        state: INITIAL_STATE, 
        dispatch: () => null 
    }
);

const AppReducer = (state: AppState, action: AppActionTypes) => {
    switch(action.type){
        case SET_SHOW: {
            return {
                show: action.show
            }
        }
        default:
            throw new Error("Action is invalid");
    }
};

export const AppProvider: FC = (props: ReactNode) => {
    const initialState = INITIAL_STATE;
    const [ state, dispatch ] = useReducer(AppReducer, initialState);

    return <AppContext.Provider value={{state, dispatch }} {...props} />;
};

export const useProvider = (): ContextType => {
    const context = useContext(AppContext);

    if(!context){
        throw new Error("useProvider must be used within AppContext");
    }

    const {state, dispatch} = context;

    return { 
        state, dispatch
    };
};

And below is my app component下面是我的应用程序组件

import React, { FC } from 'react';
import './App.css';
import { AppProvider, useProvider, SET_SHOW } from './hooks/useProvider';


const App: FC = (): JSX.Element => {
  const { state, dispatch } = useProvider();

  const handleClick = () =>{
    dispatch({
      type: SET_SHOW,
      show: !state.show
    });
    console.log(state.show);
  };

  return (
    <AppProvider>
      <div className="App">
          { state.show && "Hello World!" }
          <button onClick={handleClick}>
            Show message!
          </button>
      </div>
    </AppProvider>
  );
};

export default App;

I already tried putting an breakpoints on the reducer but somehow it still doesn't trigger the dispatch call.我已经尝试在减速器上放置一个断点,但不知何故它仍然没有触发调度调用。

There are 2 problems here.这里有2个问题。

  1. The AppProvider should be a parent of App . AppProvider应该是App的父级。 This way it can fully access the context.这样它就可以完全访问上下文。
const rootElement = document.getElementById("root");
render(
  <AppProvider>
    <App />
  </AppProvider>,
  rootElement
);
  1. dispatch is changing the state async so console.log just after dispatch logs the old value. dispatch正在更改 state 异步,因此dispatch后的console.log记录旧值。 You should "watch" the change using useEffect .您应该使用useEffect “观察”变化。
React.useEffect(() => {
  console.log("effect", state.show);
}, [state.show]);

A working demo: https://codesandbox.io/s/peaceful-blackwell-ohd0y?file=/src/index.tsx工作演示: https://codesandbox.io/s/peaceful-blackwell-ohd0y?file=/src/index.tsx

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM