爲何咱們如此須要 Immutable Data

Immutable Data 的優勢

Immutable 意爲「不可變的」。在編程領域,Immutable Data 是指一種一旦建立就不能更改的數據結構。它的理念是:在賦值時,產生一個與原對象徹底同樣的新對象,指向不一樣的內存地址,互不影響。javascript

避免反作用

當咱們須要對一個對象進行修改時,直接在原對象上進行變動很方便,也很節省內存。可是在 JavaScript 中,對象都是引用類型,在按引用傳遞數據的場景中,會存在多個變量指向同一個內存地址的狀況,這樣會引起不可控的反作用:java

let a = { x: 1 };
let b = a;
b.x = 6;

a.x // 6
複製代碼

在一個複雜應用中,若是有多個代碼塊同時更改這個引用,就會產生競態。你須要關心這個對象會在哪一個對方被修改,你對它的修改會不會影響其餘代碼的運行。使用 Immutable Data 就不會產生這個問題——由於每當狀態更新時,都會產生一個新的對象:react

let a = { x: 1, y: 2 }; // 初始狀態
a = { ...a, x: 6 }; // 建立了一個新的對象,更新了 a 
複製代碼

狀態可追溯

因爲每次修改都會建立一個新對象,且對象不變,那麼變動的記錄就可以被保存下來,應用的狀態變得可控、可追溯。Redux Dev Tool 和 Git 這兩個可以實現「時間旅行」的工具就是秉承了 Immutable 的哲學。 git

git revert -- From Atlassian Git Tutorial

爲何 React.js 須要 Immutable Data

簡短答案:爲了讓 React 精準地重渲染 UI。github

自從 React.js 出現以來,社區中關於 Immutable 的討論成倍增長,因此爲何 React.js 須要 Immutable?編程

咱們知道,在 React 中,UI 是 state 的投影,state 的變動會引起 UI 的從新渲染。React 使用 Virtual DOM 來解決 UI 更新的問題——它會將新舊兩棵 Virtual DOM 樹進行比較,若是二者存在差別,則它會將這些差別來更新在真實的 DOM 上。redux

調用setState時,React 會以 shallowMerge 的方式將咱們傳入的對象與舊的 state 進行合併。shallowMerge 只會合併新舊 state 對象中第一層的內容,若是 state 中對象的引用未變,那麼 React 認爲這個對象先後沒有發生變化。數據結構

因此若是咱們以 mutable 的方式更改了 state 中的某個對象, React 會認爲該對象並無更新,那麼相對應的 UI 就不會被重渲染。而以 Immutable 的方式更新 state 就不會出現這個問題。具體例子以下:工具

function App() {
  const [list, setList] = useState([1, 2, 3]);

  const handleFirstClick = () => {
    list.push("new Item");
    setList(list);
  };

  const handleSecondClick = () => {
    setList([...list, "new item"]);
  };

  return (
    <div className="App"> <button onClick={handleFirstClick}>Add an item in mutable way</button> <button onClick={handleSecondClick}>Add an item in immutable way</button> <ItemList list={list} /> </div> ); } function ItemList({ list }) { return ( <ul> {list.map(item => { return <li>{item}</li>; })} </ul> ); } 複製代碼

咱們甚至能夠看到,在屢次點擊第一個按鈕後,點擊第二個按鈕時,列表會新增以前第一個按鈕產生的列表項。性能

至於如何解決屢次建立新對象以更新 state 帶來的性能問題,以及如何優雅地以 Immutable 的形式更新一個複雜深層淺套的 state,這又是另一個話題了,社區中的不少 Immutable 庫(如 Immutable.js)提供了很好的解決方案。


參考資料

相關文章
相關標籤/搜索