reactjs - useReducer 和 useContext Dispatch 在 onClick 函数中不起作用

标签 reactjs dispatch use-context use-reducer

我不会向您介绍更广泛的背景,因为它非常简单。使用 React hooks,这里的第一个调度会自动触发并且工作得很好,但第二个则不然。 Context 是从另一个文件导入的,所以我认为这是一个(小写)上下文问题,但我不知道如何修复它?

const Component = props => {
  const [, dispatch] = useContext(Context);

  useEffect(() => {
    document.title = state.title;
    // eslint-disable-next-line react-hooks/exhaustive-deps
  });

  // this works
  dispatch({ type: "UPDATE_TITLE", payload: "Not Click!" });

  function onAddClick() {
    // this doesn't work
    dispatch({ type: "UPDATE_TITLE", payload: "CLICKED!" });
  }

  return (
    <div>
      <AddButton onClick={onAddClick} />
    </div>
  );
};

这是父级。

const Reducer = (state, action) => {
  switch (action.type) {
    case "UPDATE_TITLE":
      state["title"] = action.payload;
      return state;
    default:
      return state;
  }
};

const initialState = {
  title: "My Title"
};

export const Context = createContext(initialState);

const App = () => {
  const [state, dispatch] = useReducer(Reducer, initialState);

  return (
    <Context.Provider value={[state, dispatch]}>
      <Component />
    </Context.Provider>
  );
};

export default App;

在这两种情况下,控制台日志都会在正确的 reducer 情况下触发,但只有标记为“此有效”的那个才会真正正确更新状态,另一种则默默地失败。


已修复:https://codesandbox.io/s/cranky-wescoff-9epf9?file=/src/App.js

最佳答案

我不知道你想通过将 dispatch 放置在 control env 之外来实现什么目的(例如 eventuseEffect ):-

// this works
dispatch({ type: "UPDATE_TITLE", payload: "Not Click!" });
// but it will run in infinite loop tho (no changes can be made then)

所以修复应该是:-

  1. Reducer中,确保不要完全改变您的状态:-
const Reducer = (state, action) => {
  switch (action.type) {
    case "UPDATE_TITLE":
      // Don't do this
      // let newState = state;
      // newState["page"]["title"] = action.payload;
      // console.log("updating", newState, newState.page.title);
      // return newState;

      // Do this instead
      return {
        ...state,
        page: {
          ...state.page,
          title: action.payload
        }
      };
    default:
      return state;
  }
};
  • not Click!dispatch 放置在 eventfunction 中,或者在这种情况下更好, useEffect 因为您想在渲染的组件中应用它一次
  • const Demo = props => {
      const [state, dispatch] = useContext(Context);
    
      useEffect(() => {
        document.title = state.title;
        // eslint-disable-next-line react-hooks/exhaustive-deps
    
        // this works (should be here)
        dispatch({ type: "UPDATE_TITLE", payload: "Not Click!" });
      }, []); // run it once when render
    
      // this works but, (should not be here tho - cause it will run non-stop)
      // dispatch({ type: "UPDATE_TITLE", payload: "Not Click!" });
    
      function onAddClick() {
        // this will work now
        dispatch({ type: "UPDATE_TITLE", payload: "CLICKED!" });
      }
    
      return (
        <div>
          <button onClick={onAddClick}>Click Me!</button>
          <p>State now: {state.title}</p>
        </div>
      );
    };
    

    你可以尝试引用这个sandbox并看看它是如何工作的。

    编辑和更新sandbox

    关于reactjs - useReducer 和 useContext Dispatch 在 onClick 函数中不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64938820/

    相关文章:

    reactjs - 是否可以获得 props.children 的 ref ?

    javascript - 在 React 中使用类名、ID 和数据属性时的最佳实践是什么

    ios - 执行 NSURLRequest 和响应委托(delegate)与使用 dispatch_async 有什么区别?

    Java 线程——Swing 事件调度线程中的永久循环

    javascript - 上下文 API 中的 React useState 值始终使用初始值而不是更新值

    javascript - 在网格元素内垂直居中文本

    javascript - 在 React 中使用自定义函数

    ios - 在重复的 for 循环中对 dispatch_group_leave() 的不平衡调用

    javascript - 状态不随 useContext 改变

    javascript - 如何修复我的 React 上下文以呈现 useEffect 并重新加载表数据