store變化了而頁面取不到值——mobx會對什麼作出反應

delete1111111111111發表於2020-12-16

1、mobx怎麼對可觀察物件作出反應

MobX 通常會對你期望的東西做出反應。 這意味著在90%的場景下,mobx “都可以工作”。 然而,在某些時候,你會遇到一個情況,它可能不會像你所期望的那樣工作。 在這個時候理解 MobX 如何確定對什麼有反應就顯得尤為重要。

MobX 會對在 追蹤函式執行 過程讀取現存的可觀察屬性做出反應。
  • “讀取” 是物件屬性的間接引用,可以用過 . (例如 user.name) 或者 [] (例如 user['name']) 的形式完成。
  • “追蹤函式” 是 computed 表示式、observer 元件的 render() 方法和 whenreaction 和 autorun 的第一個入參函式。
  • “過程(during)” 意味著只追蹤那些在函式執行時被讀取的 observable 。這些值是否由追蹤函式直接或間接使用並不重要。

換句話說,MobX 不會對其作出反應:

  • 從 observable 獲取的值,但是在追蹤函式之外
  • 在非同步呼叫的程式碼塊中讀取的 observable
  • MobX 追蹤屬性訪問,而不是值

假設你有如下的 observable 資料結構(預設情況下 observable 會遞回應用,所以本示例中的所有欄位都是可觀察的)。

https://www.flipsnack.com/nkg53/1732.html
https://www.flipsnack.com/nkg53/786.html
https://www.flipsnack.com/nkg53/4408.html
https://www.flipsnack.com/45rl7/7560.html
https://www.flipsnack.com/45rl7/9777.html
https://www.flipsnack.com/45rl7/5645.html
https://www.flipsnack.com/0bqad/7025.html
https://www.flipsnack.com/0bqad/7110.html
https://www.flipsnack.com/0bqad/3308.html
https://www.flipsnack.com/55t1d/8325.html
https://www.flipsnack.com/55t1d/4387.html
https://www.flipsnack.com/55t1d/9153.html
https://www.flipsnack.com/cp7pc/4215.html
https://www.flipsnack.com/cp7pc/1886.html
https://www.flipsnack.com/cp7pc/6692.html
https://www.flipsnack.com/cpppc/5092.html
https://www.flipsnack.com/cpppc/5055.html
https://www.flipsnack.com/cpppc/6149.html
https://www.flipsnack.com/1xetu/224.html
https://www.flipsnack.com/1xetu/2235.html
https://www.flipsnack.com/1xetu/986.html
https://www.flipsnack.com/0g3br/4990.html
https://www.flipsnack.com/0g3br/2974.html
https://www.flipsnack.com/0g3br/5591.html
https://www.flipsnack.com/hhdbr/3915.html
https://www.flipsnack.com/hhdbr/1581.html
https://www.flipsnack.com/hhdbr/1388.html
https://www.flipsnack.com/725pw/3216.html
https://www.flipsnack.com/725pw/7345.html
https://www.flipsnack.com/725pw/3277.html
https://www.flipsnack.com/qhw8p/8983.html
https://www.flipsnack.com/qhw8p/8004.html
https://www.flipsnack.com/qhw8p/6575.html
https://www.flipsnack.com/pjl2s/5432.html
https://www.flipsnack.com/pjl2s/136.html
https://www.flipsnack.com/pjl2s/9924.html
https://www.flipsnack.com/n6qqg/4356.html
https://www.flipsnack.com/n6qqg/7055.html
https://www.flipsnack.com/n6qqg/5260.html
https://www.flipsnack.com/c658n/8073.html
https://www.flipsnack.com/c658n/6329.html
https://www.flipsnack.com/c658n/1767.html
https://www.flipsnack.com/ewb2p/5619.html
https://www.flipsnack.com/ewb2p/4363.html
https://www.flipsnack.com/ewb2p/5676.html
https://www.flipsnack.com/yh835/607.html
https://www.flipsnack.com/yh835/6649.html
https://www.flipsnack.com/yh835/6682.html
https://www.flipsnack.com/xbps1/3738.html
https://www.flipsnack.com/xbps1/4605.html
https://www.flipsnack.com/xbps1/6362.html
https://www.flipsnack.com/vggc4/5900.html
https://www.flipsnack.com/vggc4/2725.html
https://www.flipsnack.com/vggc4/7800.html
https://www.flipsnack.com/utt8r/2581.html
https://www.flipsnack.com/utt8r/2815.html
https://www.flipsnack.com/utt8r/4319.html
https://www.flipsnack.com/rdyqh/6852.html
https://www.flipsnack.com/rdyqh/8790.html
https://www.flipsnack.com/rdyqh/4524.html
https://www.flipsnack.com/4islb/5056.html
https://www.flipsnack.com/4islb/2530.html
https://www.flipsnack.com/4islb/6716.html
https://www.flipsnack.com/x8h06/6374.html
https://www.flipsnack.com/x8h06/928.html
https://www.flipsnack.com/x8h06/722.html
https://www.flipsnack.com/srkfh/774.html
https://www.flipsnack.com/srkfh/6374.html
https://www.flipsnack.com/srkfh/7148.html
https://www.flipsnack.com/n8ntr/8699.html
https://www.flipsnack.com/n8ntr/5071.html
https://www.flipsnack.com/n8ntr/6660.html
https://www.flipsnack.com/hxe5n/8368.html
https://www.flipsnack.com/hxe5n/6308.html
https://www.flipsnack.com/hxe5n/6172.html
https://www.flipsnack.com/fxhr4/355.html
https://www.flipsnack.com/fxhr4/8935.html
https://www.flipsnack.com/fxhr4/5711.html
https://www.flipsnack.com/8l730/7728.html
https://www.flipsnack.com/8l730/2139.html
https://www.flipsnack.com/8l730/5602.html
https://www.flipsnack.com/5rzn3/9290.html
https://www.flipsnack.com/5rzn3/186.html
https://www.flipsnack.com/5rzn3/6341.html
https://www.flipsnack.com/0821e/4462.html
https://www.flipsnack.com/0821e/8121.html
https://www.flipsnack.com/0821e/6534.html
https://www.flipsnack.com/uwsda/5531.html
https://www.flipsnack.com/uwsda/9364.html
https://www.flipsnack.com/uwsda/8045.html
https://www.flipsnack.com/pfvrk/3299.html
https://www.flipsnack.com/pfvrk/4917.html
https://www.flipsnack.com/pfvrk/7127.html
https://www.flipsnack.com/kwy5u/5954.html
https://www.flipsnack.com/kwy5u/1119.html
https://www.flipsnack.com/kwy5u/6756.html
https://www.flipsnack.com/dlpiq/6215.html
https://www.flipsnack.com/dlpiq/5232.html
https://www.flipsnack.com/dlpiq/9647.html
https://www.flipsnack.com/72sw0/5320.html
https://www.flipsnack.com/72sw0/6735.html
https://www.flipsnack.com/72sw0/9701.html
https://www.flipsnack.com/p6opa/5286.html
https://www.flipsnack.com/p6opa/7218.html
https://www.flipsnack.com/p6opa/1917.html
https://www.flipsnack.com/wtjvx/7793.html
https://www.flipsnack.com/wtjvx/4657.html
https://www.flipsnack.com/wtjvx/1233.html
https://www.flipsnack.com/rbla7/7814.html
https://www.flipsnack.com/rbla7/9046.html
https://www.flipsnack.com/rbla7/6296.html
https://www.flipsnack.com/mtopi/2742.html
https://www.flipsnack.com/mtopi/8276.html
https://www.flipsnack.com/mtopi/9309.html
https://www.flipsnack.com/qxinz/2513.html
https://www.flipsnack.com/qxinz/6426.html
https://www.flipsnack.com/qxinz/2999.html
https://www.flipsnack.com/n3862/2342.html
https://www.flipsnack.com/n3862/9681.html
https://www.flipsnack.com/n3862/3961.html
https://www.flipsnack.com/hrzjy/6883.html
https://www.flipsnack.com/hrzjy/9376.html
https://www.flipsnack.com/hrzjy/2742.html
https://www.flipsnack.com/ca2x8/6069.html
https://www.flipsnack.com/ca2x8/7483.html
https://www.flipsnack.com/ca2x8/2079.html
https://www.flipsnack.com/6r5cj/9037.html
https://www.flipsnack.com/6r5cj/2749.html
https://www.flipsnack.com/6r5cj/3935.html
https://www.flipsnack.com/5ll0e/4231.html
https://www.flipsnack.com/5ll0e/6100.html
https://www.flipsnack.com/5ll0e/6155.html
https://www.flipsnack.com/03ofo/1749.html
https://www.flipsnack.com/03ofo/7957.html
https://www.flipsnack.com/03ofo/5741.html
https://www.flipsnack.com/urfqk/7819.html
https://www.flipsnack.com/urfqk/5485.html
https://www.flipsnack.com/urfqk/4954.html
https://www.flipsnack.com/p8i4u/4725.html
https://www.flipsnack.com/p8i4u/4521.html
https://www.flipsnack.com/p8i4u/3047.html
https://www.flipsnack.com/hbzxk/8925.html
https://www.flipsnack.com/hbzxk/7967.html
https://www.flipsnack.com/hbzxk/6076.html
https://www.flipsnack.com/1qucm/9078.html
https://www.flipsnack.com/1qucm/6378.html
https://www.flipsnack.com/1qucm/2249.html
https://www.flipsnack.com/x1atb/3004.html
https://www.flipsnack.com/x1atb/6666.html
https://www.flipsnack.com/x1atb/1866.html
https://www.flipsnack.com/tepaz/4532.html
https://www.flipsnack.com/tepaz/7137.html
https://www.flipsnack.com/tepaz/1467.html
https://www.flipsnack.com/ovroa/1999.html
https://www.flipsnack.com/ovroa/986.html
https://www.flipsnack.com/ovroa/2650.html
https://www.flipsnack.com/ojkgk/182.html
https://www.flipsnack.com/ojkgk/4031.html
https://www.flipsnack.com/ojkgk/6003.html
https://www.flipsnack.com/kuzw7/2630.html
https://www.flipsnack.com/kuzw7/3831.html
https://www.flipsnack.com/kuzw7/2753.html
https://www.flipsnack.com/g6eew/5258.html
https://www.flipsnack.com/g6eew/1547.html
https://www.flipsnack.com/g6eew/3599.html
https://www.flipsnack.com/bohs6/6950.html
https://www.flipsnack.com/bohs6/6080.html
https://www.flipsnack.com/bohs6/9781.html
https://www.flipsnack.com/60w8v/3497.html
https://www.flipsnack.com/60w8v/3034.html
https://www.flipsnack.com/60w8v/7055.html
https://www.flipsnack.com/1jzn5/8756.html
https://www.flipsnack.com/1jzn5/8612.html
https://www.flipsnack.com/1jzn5/793.html
https://www.flipsnack.com/zi2an/7651.html
https://www.flipsnack.com/zi2an/9101.html
https://www.flipsnack.com/zi2an/451.html
https://www.flipsnack.com/u05ox/5382.html
https://www.flipsnack.com/u05ox/9115.html
https://www.flipsnack.com/u05ox/7840.html
https://www.flipsnack.com/vnyf7/5962.html
https://www.flipsnack.com/vnyf7/2852.html
https://www.flipsnack.com/vnyf7/2546.html
https://www.flipsnack.com/q50ti/9831.html
https://www.flipsnack.com/q50ti/7676.html
https://www.flipsnack.com/q50ti/4523.html
https://www.flipsnack.com/ln37s/9721.html
https://www.flipsnack.com/ln37s/2304.html
https://www.flipsnack.com/ln37s/4126.html
https://www.flipsnack.com/5syiz/7314.html
https://www.flipsnack.com/5syiz/7775.html
https://www.flipsnack.com/5syiz/4954.html
https://www.flipsnack.com/z0n2n/686.html
https://www.flipsnack.com/z0n2n/191.html
https://www.flipsnack.com/z0n2n/1196.html
https://www.flipsnack.com/xzqo4/2614.html
https://www.flipsnack.com/xzqo4/7287.html
https://www.flipsnack.com/xzqo4/5964.html
https://www.flipsnack.com/tc55t/6309.html
https://www.flipsnack.com/tc55t/6133.html
https://www.flipsnack.com/tc55t/4858.html
https://www.flipsnack.com/vsbzh/1601.html
https://www.flipsnack.com/vsbzh/6493.html
https://www.flipsnack.com/vsbzh/4177.html
https://www.flipsnack.com/sy1jk/1585.html
https://www.flipsnack.com/sy1jk/3445.html
https://www.flipsnack.com/sy1jk/1515.html
https://www.flipsnack.com/obhz8/4671.html
https://www.flipsnack.com/obhz8/7976.html
https://www.flipsnack.com/obhz8/5777.html
https://www.flipsnack.com/jskej/6218.html
https://www.flipsnack.com/jskej/9541.html
https://www.flipsnack.com/jskej/8387.html
https://www.flipsnack.com/f4zv7/4308.html
https://www.flipsnack.com/f4zv7/6009.html
https://www.flipsnack.com/f4zv7/3712.html
https://www.flipsnack.com/bgecw/6342.html
https://www.flipsnack.com/bgecw/5803.html
https://www.flipsnack.com/bgecw/2206.html
https://www.flipsnack.com/5yhq6/9107.html
https://www.flipsnack.com/5yhq6/9709.html
https://www.flipsnack.com/5yhq6/4463.html
https://www.flipsnack.com/1aw7v/7417.html
https://www.flipsnack.com/1aw7v/5828.html
https://www.flipsnack.com/1aw7v/3552.html
https://www.flipsnack.com/wszm5/1474.html
https://www.flipsnack.com/wszm5/9848.html
https://www.flipsnack.com/wszm5/8750.html
https://www.flipsnack.com/0wslm/6399.html
https://www.flipsnack.com/0wslm/1967.html
https://www.flipsnack.com/0wslm/7338.html
https://www.flipsnack.com/w871b/1247.html
https://www.flipsnack.com/w871b/5365.html
https://www.flipsnack.com/w871b/403.html
https://www.flipsnack.com/17d26/1409.html
https://www.flipsnack.com/17d26/1814.html
https://www.flipsnack.com/17d26/6905.html
https://www.flipsnack.com/4d61n/7478.html
https://www.flipsnack.com/4d61n/5430.html
https://www.flipsnack.com/4d61n/8204.html
https://www.flipsnack.com/0olic/5137.html
https://www.flipsnack.com/0olic/434.html
https://www.flipsnack.com/0olic/7710.html
https://www.flipsnack.com/84rrf/9913.html
https://www.flipsnack.com/84rrf/6007.html
https://www.flipsnack.com/84rrf/2887.html
https://www.flipsnack.com/4h673/2211.html
https://www.flipsnack.com/4h673/9281.html
https://www.flipsnack.com/4h673/9430.html
https://www.flipsnack.com/zyane/7696.html
https://www.flipsnack.com/zyane/2090.html
https://www.flipsnack.com/zyane/146.html
https://www.flipsnack.com/vbp32/6245.html
https://www.flipsnack.com/vbp32/2846.html
https://www.flipsnack.com/vbp32/5489.html
https://www.flipsnack.com/qssid/8612.html
https://www.flipsnack.com/qssid/8539.html
https://www.flipsnack.com/qssid/2716.html
https://www.flipsnack.com/q55gz/5634.html
https://www.flipsnack.com/q55gz/7494.html
https://www.flipsnack.com/q55gz/9305.html
https://www.flipsnack.com/ncwz2/695.html
https://www.flipsnack.com/ncwz2/1433.html
https://www.flipsnack.com/ncwz2/6534.html
https://www.flipsnack.com/khoj5/3643.html
https://www.flipsnack.com/khoj5/7993.html
https://www.flipsnack.com/khoj5/4627.html
https://www.flipsnack.com/aezt6/3340.html
https://www.flipsnack.com/aezt6/4962.html
https://www.flipsnack.com/aezt6/1203.html
https://www.flipsnack.com/6jqda/6205.html
https://www.flipsnack.com/6jqda/1334.html
https://www.flipsnack.com/6jqda/7905.html
https://www.flipsnack.com/ntb34/7622.html
https://www.flipsnack.com/ntb34/4201.html
https://www.flipsnack.com/ntb34/6710.html
https://www.flipsnack.com/0f6p7/7717.html
https://www.flipsnack.com/0f6p7/2080.html
https://www.flipsnack.com/0f6p7/8799.html
https://www.flipsnack.com/r1481/6859.html
https://www.flipsnack.com/r1481/7864.html
https://www.flipsnack.com/r1481/1108.html
https://www.flipsnack.com/qvlxx/995.html
https://www.flipsnack.com/qvlxx/8993.html
https://www.flipsnack.com/qvlxx/1950.html
https://www.flipsnack.com/pilw6/9855.html
https://www.flipsnack.com/pilw6/203.html
https://www.flipsnack.com/pilw6/1515.html

`let message = observable({
    title: "Foo",
    author: {
        name: "Michel"
    },
    likes: [
        "John", "Sara"
    ]
})` Copy

在記憶體中看起來像下面這樣。 綠色框表示可觀察屬性。 請注意, 本身是不可觀察的!
image.png
現在 MobX 基本上所做的是記錄你在函式中使用的是哪個箭頭。之後,只要這些箭頭中的其中一個改變了(它們開始引用別的東西了),它就會重新執行。

2、沒有封裝成observer 元件

容器元件

import Change from './Change';
import Father from './Father';

const Main = (props: any) => {
  return (
    <div>
      <Father></Father>
      <Change></Change>
    </div>
  )
}

export default Main;

Father元件

import { inject } from 'mobx-react';
import React from 'react';
import Store from '../../store/store';

interface IProps {
  store?: Store;
}

const Father = (props: IProps) => {
  const { store } = props;
  const { message } = store as Store;

  return <div>
    <div>title: {message.title}</div>
    <div>author: {message.author.name}</div>
    <div>likes: {message.likes[0]}</div>
  </div>
}

export default inject('store')(Father);

Change元件

import { Divider } from 'antd';
import { inject, observer } from 'mobx-react';
import React from 'react';
import Store from '../../store/store';

interface IProps {
  store?: Store;
}

const Change = (props: IProps) => {
  const { store } = props;

  const { setName, setTitle, setLikes } = store as Store;

  return <div>
    <button onClick={() => setTitle('spin')}>改變title</button>
    <button onClick={() => setName('tom')}>改變name</button>
    <button onClick={() => setLikes('john')}>改變likes</button>
  </div>
}

export default inject('store')(observer(Change));

store

import { observable, action } from 'mobx';

class Store {
  @observable message = {
    title: 'Bar',
    author: {
      name: 'Susan'
    },
    likes: ['Michel']
  }

  @action
  setTitle = (title: string) => {
    this.message.title = title;
  }
  
  @action
  setName = (name: string) => {
    this.message.author.name = name;
  }

  @action
  setLikes = (target: string) => {
    this.message.likes[0] = target;
  }
}

export default Store;

當點選改變title、name、likes按鈕時,store中觀察物件message的屬性值改變了,但是Father元件並沒有重新渲染。因為Father元件並不是observer元件,只有封裝成observer元件,mobx才會對render函式(函式元件理解為return返回的ReactNode)中讀取現存的可觀察屬性做出反應。

因此,只需要將Father元件封裝成observer元件就可以解決

export default inject('store')(Father);
改後
export default inject('store')(observer(Father));

3、MobX 只會為資料是直接通過 render 存取的 observer 元件進行資料追蹤

Father元件

const Father = (props: IProps) => {
  const { store } = props;
  const { message } = store as Store;

  return <div>
    <div>title: {message.title}</div>
    <Child title={() => <div>{message.author.name}</div>}></Child>
    <div>likes: {message.likes[0]}</div>
  </div>
}

export default inject('store')(observer(Father));

Child元件

interface IProps {
  title: () => React.ReactNode;
}

const Child = (props: IProps) => {
  const { title } = props;

  return <div>{title()}</div>
}

export default Child;

當改變storemessage.author.name時,頁面並不會重新渲染。因為div實際上不是由 Father(有追蹤的渲染) 渲染的,而是 Child。 所以要確保 Child 的 title 可以正確對新的 message.author.name 作出反應,Child 應該也是一個 observer

如果 Child 來源於外部庫的話,這通常不在你的掌控之中。在這種場景下,你可以用自己的無狀態 observer 元件來包裹 div 解決此問題,或通過利用 <Observer>元件:

// 將Child改成observer元件
const Child = (props: IProps) => {
  const { title } = props;

  return <div>{title()}</div>
}

export default observer(Child);

另外一種方法可以使用 mobx-react 內建的 Observer 元件,它不接受引數,只需要單個的 render 函式作為子節點:

const Father = (props: IProps) => {
  const { store } = props;
  const { message } = store as Store;

  return <div>
    <div>title: {message.title}</div>
    <Child title={() => <Observer>{() => <div>{message.author.name}</div>}</Observer>}></Child>
    <div>likes: {message.likes[0]}</div>
  </div>
}

4、在本地欄位中快取 observable

一個常見的錯誤就是把間接引用的 observable 儲存到本地變數,然後認為元件會作出反應。舉例來說:

@inject('store')
@observer
class Father extends React.Component<IProps, any> {
  author: { name: string; } | undefined;
  likes: string[] | undefined;
  title: string | undefined;

  constructor(props: IProps) {
    super(props);
    this.title = props.store?.message.title;
    this.author = props.store?.message.author;
    this.likes = props.store?.message.likes;
    console.log('title: ' ,this.title, 'author: ' ,this.author, 'likes: ', this.likes)
  }

  render() {
    return <div>
      <div>title: {this.title}</div>
      <div>name: {this.author?.name}</div>
      <div>likes: {this.likes && this.likes[0]}</div>
    </div>
  }
}

export default Father;

元件會對authorlikes做出反應,不會對title做出反應,因為this.title = props.store?.message.title;是賦值,而this.author = props.store?.message.author;是賦引用,這個引用也是一個observable物件
image.png

換成函式元件

const Father = (props: IProps) => {
  const { store } = props;
  const { message } = store as Store;

  const title = message.title;
  const author = message.author;
  const likes = message.likes;

  return <div>
    <div>title: {title}</div>
    <Child title={() => <Observer>{() => <div>{author.name}</div>}</Observer>}></Child>
    <div>likes: {likes[0]}</div>
  </div>
}

export default inject('store')(observer(Father));

發現元件即會對authorlikes做出反應,也會對title做出反應

相關文章