【问题标题】:Using useReducer and useContext, the component is not rerendered when an action is dispatched. How to trigger the rerender?使用 useReducer 和 useContext,当一个动作被调度时,组件不会被重新渲染。如何触发重新渲染?
【发布时间】:2021-08-16 08:13:42
【问题描述】:

我是 React 的初学者,我正在研究如何一起使用 useReducer 和 useContext。 我正在处理的一个非常简单的研究示例只是一个名为 Greeting 的组件,它接收从 StateContext 传递的状态,它显示来自 Main.js 的用户(Mike)的名称,并且它有一个应该将操作发送到的按钮把名字改成约翰。 问题是当按钮被点击时,没有任何反应,并且问候组件中的名称保持不变。 我注意到 Greeting 组件内的 console.log 不会在动作 changeName 被调度后被触发,这意味着我相信 Greeting 组件不会被重新渲染。 为什么问候不重新呈现并显示更新的名称

这是主要组件:

import React, { useReducer } from 'react';
import { BrowserRouter, Switch, Route } from 'react-router-dom';

// components
import StateContext from './components/StateContext';
import DispatchContext from './components/DispatchContext';
import Greeting from './components/Greeting';

function reducer(state, action) {
  switch (action.type) {
    case 'changeName':
      const newState = state;
      newState.name = action.name;
      return newState;
    default:
      return;
  }
}

function App() {
  const [state, dispatch] = useReducer(reducer, {
    name: 'Mike',
  });
  console.log('name', state.name);
  return (
    <BrowserRouter>
      <Switch>
        <StateContext.Provider value={state}>
          <DispatchContext.Provider value={dispatch}> 
            <Route path="/greeting">
              <Greeting />
            </Route>
          </DispatchContext.Provider>
        </StateContext.Provider>
      </Switch>
    </BrowserRouter>
  );
}

export default App;

这是问候组件:

import React, { useContext } from 'react';
import StateContext from './StateContext';
import DispatchContext from './DispatchContext';

const Greeting = () => {
  const state = useContext(StateContext);
  const appDispatch = useContext(DispatchContext);
  console.log('inside greeting component', state.name)

  return (
    <>
      <div>{state.name}</div>
      <button onClick={() => appDispatch({ type: 'changeName', name: 'John' })}>
        Change Name
      </button>
    </>
  );
};

export default Greeting;
 

DispatchContext:

import { createContext } from 'react';

const DispatchContext = createContext();

export default DispatchContext;

StateContext:

import { createContext } from 'react'

const StateContext = createContext()

export default StateContext

【问题讨论】:

    标签: javascript reactjs react-hooks


    【解决方案1】:

    问题

    这里的问题是状态对象突变。

    function reducer(state, action) {
      switch (action.type) {
        case 'changeName':
          const newState = state;      // <-- newState is reference to state
          newState.name = action.name; // <-- mutation!!
          return newState;             // <-- same state reference
        default:
          return;
      }
    }
    

    当你改变那个状态对象并返回它时,它仍然是对前一个状态的引用,所以 React 不会重新渲染它。

    解决方案

    返回一个新的状态对象。将之前的状态浅复制到一个新的状态对象中然后更新嵌套属性。如果状态更新嵌套更深,那么您还需要浅拷贝任何更新的嵌套状态。不要忘记在默认情况下返回当前状态对象。

    function reducer(state, action) {
      switch (action.type) {
        case 'changeName':
          return {
            ...state,
            name: action.name
          };
    
        default:
          return state;
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2021-09-24
      • 1970-01-01
      • 1970-01-01
      • 2020-02-13
      • 2020-06-12
      • 2021-12-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-17
      相关资源
      最近更新 更多