簡體   English   中英

不可變地更新 state 中的對象 - 是否強制

[英]Updating Objects in state immutably - mandatory or not

瀏覽 react beta 文檔,其中討論了更新 state 中的對象。 我知道需要不可變地更新 state 對象,以便 React 可以找出已更改的內容並重新渲染。

這是示例中使用的原始 state:const [person, setPerson] = useState({ name: 'Niki de Saint Phalle', artwork: { title: 'Blue Nana', city: 'Hamburg', image: 'https: //i.imgur.com/Sd1AgUOm.jpg', } });

在嘗試更改藝術品的標題時,提到傳播 object 並僅更新所需的 object 屬性,如下所示:

請注意,注釋代碼是示例中共享的代碼,最后兩行是我正在試驗的代碼。

function handleTitleChange(e) {
    // setPerson({
    //   ...person,
    //   artwork: {
    //     ...person.artwork,
    //     title: e.target.value
    //   }
    // });
    person.artwork.title = e.target.value // I tried updating it directly
    setPerson({...person}) // trigger a re-render
  }

現在我嘗試的是直接更新 state 屬性,然后通過傳播 object 這個人來觸發重新渲染。

我在重新渲染時比較了突出顯示的組件。 這兩種情況都是一樣的。 我想就為什么我們需要特別關注對象的冗長傳播以及如果直接更新和觸發重新渲染可能存在的陷阱提出意見。

一些代碼示例將不勝感激

State 不變性不是強制性的,但通常更可取。 對於復雜對象,跟蹤嵌套對象的更改很重要。

因此,這是您的代碼可以導致的結果:

  1. useEffect 未觸發,因為它具有對象的嵌套屬性作為依賴項
  2. 由於參數引用未更改,因此不會重新呈現已記憶的組件

為什么會發生 - React 在其變更檢測策略中對非基元(字符串、boolean、數字)使用 ReferenceEquality 比較。 如果引用未更改 - 即使數據本身發生了變化,也不會執行重新渲染和 useEffects 以及其他類似的操作。

在您當前的“實驗”代碼中 - 您正在更改person object 的參考,但其中“藝術品”的參考未更改,藝術品發生變異,但參考保留:

 const {useState, useEffect, memo} = React; function App() { const [person, setPerson] = useState({ artwork: { title: "test" } }); function handleTitleChange(e) { person.artwork.title = e.target.value; setPerson({...person }); } useEffect(() => { console.log("Artwork changed: ", person.artwork); }, [person.artwork]); return ( <div className="App"> <input type="text" value={person.artwork.title} onChange={handleTitleChange} /> <pre>{JSON.stringify(person, null, 2)}</pre> <TestComponent artwork={person.artwork} /> <MemoComponent artwork={person.artwork} /> </div> ); } function TestComponent({artwork}) { useEffect(() => { console.log("Artwork changed in sub-component: ", artwork); }, [artwork]); return (<p>Artwork title: {artwork.title}</p>); }; const MemoComponent = memo(TestComponent); ReactDOM.createRoot(document.getElementById("root")).render(<App />);
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.development.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.development.js"></script> <div id="root"></div>

你可以在這里看到什么:

  1. App組件中的useEffect改變后不觸發

  2. memo組件中的 useEffect 和 UI 在更改后不會被觸發/更新

  3. 非備忘錄組件中的 useEffect 未被觸發,但組件本身使用新數據重新呈現。

暫無
暫無

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

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