[英]functional component is not re-rendering after state change in React
[英]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.