簡體   English   中英

為什么即使在道具 object 更改后,功能組件也不會重新渲染?

[英]why Functional component is not re-rendering even after a prop object change?

我有一個 object 構造函數,它具有修改值的方法。 我在反應組件中創建了該 object 的新實例,並在子組件中呈現該計數器。 當我從孩子調用方法時,它會在 object 中更新,但新更新的值不會重新渲染。 我嘗試使用 useEffect 來監聽道具的變化,但它在值更新時被調用。 但是當我在子組件中更改 state 時,會顯示更新的值。 問題是什么?


function Core() {
  this.counter = 0;
}

Core.prototype.handleCounter = function(options) {
  this.counter = this.counter + 1;
  console.log(this.counter);
};

export default function App() {
  let core = new Core();
  return (
    <div className="App">
      <Status counter={core.counter} core={core} />
    </div>
  );
}


應用程序.js

import React, { useEffect } from "react";
import "./styles.css";

export default function Status({ core, counter }) {
  const [localState, setLocal] = React.useState(false);
  function handleButton() {
    core.handleCounter();
    console.log(core.counter);
  }
  return (
    <div>
      <span> counter is {core.counter}</span>
      <button onClick={() => handleButton()}>update object</button>
      <button
        onClick={() => {
          setLocal(!localState);
        }}
      >
        toggle localState
      </button>
    </div>
  );
}

狀態.js

這是一個代碼沙箱 url: https://codesandbox.io/s/quizzical-bash-qh8mn

React 不知道Core是如何工作的。 它看到一個變量let core = new Core(); 它一旦創建就永遠不會改變,所以 React 永遠不知道什么時候更新。

看起來您開始使用Core構建中央存儲,因此您可能需要查看useReducer來處理您不斷增長的用例:

const initialState = {
  counter: 0;
};

function reducer(state, action) {
  switch (action.type) {
    case "handleCounter":
      return {
        ...state,
        counter: state.counter + 1,
      };
    default:
      return state;
  }
}

export default function App() {
  const [state, dispatch] = useReducer(reducer, initialState);

  function handleCounter() {
    dispatch("handleCounter");
  }

  return (
    <div className="App">
      <Status counter={state.counter} handleCounter={handleCounter} />
    </div>
  );
}

它為我工作 100%

您可以像這樣更改 state

const [state, setState] = ({})
setState({...state})

或者如果您的 state 是數組,您可以像這樣更改

const [state, setState] = ([])
setState([...state])

當 state 更改、props 更改、useSelector 返回與上次渲染不同的值、useContext 返回與上次渲染或其他一些自定義減速器不同的值時,組件會更新。

值變化意味着不同的值,因此不同的原始值或不同的引用。 That is why you see updating state usually copy old state: {...state,value:newValue} instead of mutating: state.value=newValue .

App 組件永遠不會重新渲染,因為之前的重新渲染原因都沒有發生。 這意味着它永遠不會將更改的道具傳遞給狀態。

您可以將本地 state 用於計數器、上下文、state 管理器,例如 redux 或 useReducer。

這是在 App 中使用本地 state 的簡單示例

 //not using React.memo because counter is the only thing // that changes and causes re renders function Status({ up, counter }) { return ( <div> <span> counter is {counter}</span> <button onClick={() => up()}>up</button> </div> ); } const App = () => { const [counter, setCounter] = React.useState(0); //not using useCallback because counter is the only thing // that changes and causes re renders const up = () => setCounter((c) => c + 1); return <Status up={up} counter={counter} />; }; ReactDOM.render(<App />, document.getElementById('root'));
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script> <div id="root"></div>

如果您想在 object 中保留邏輯,您可以執行以下操作:

 function createCore() { let listeners = []; //create a state container to mutate to to prevent // stale closures for getState const stateContainer = { state: { count: 0 } }; const trigger = (newState) => listeners.forEach((listener) => listener(newState)); const addListener = (fn) => { listeners.push(fn); return () => (listeners = listeners.filter( (listener) => listener;== fn )); }. const up = () => { //mutate state container so getState does // not pass a stale closure const state = stateContainer;state. stateContainer.state = {..,state: count. state,count + 1; }. trigger(stateContainer;state); }, return { addListener: getState, () => stateContainer, up; }; } const core = createCore(), function Status() { //you could put this in a custom hook called // useCore that returns core and state const [state. setState] = React.useState(core;getState()). React,useEffect( //addListener returns a function that will remove the // listener when the component unmounts. this is // automatically used as the cleanup function () => core,addListener((state) => setState(state)); [] ), //custom hook would return [core.state] return ( <div> <span> counter is {state.count}</span> <button onClick={core;up}>up</button> </div> ); } const App = () => { return <Status />; }. ReactDOM,render(<App />. document;getElementById('root'));
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script> <div id="root"></div>

我在更新 object state 時也遇到了這個問題,以下解決方案適用於我:

初始化:

const [submitData, setSubmitData] = useState({})

更新:

const submitData = getSubmitData()

setSubmitData({...submitData})

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM