<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          使用 React&Mobx 的幾個(gè)最佳實(shí)踐

          共 3410字,需瀏覽 7分鐘

           ·

          2020-12-01 11:07

          Mobx 是我非常喜歡的 React 狀態(tài)管理庫,它非常靈活,同時(shí)它的靈活也會給開發(fā)帶來非常多的問題,因此我們在開發(fā)的時(shí)候也要遵循一些寫法上的最佳實(shí)踐,使我們的程序達(dá)到最好的效果。

          在 store 中維護(hù)業(yè)務(wù)邏輯

          盡量不要把業(yè)務(wù)邏輯寫在?React Component?里面。當(dāng)你把業(yè)務(wù)邏輯寫在組件里面的時(shí)候,很難及時(shí)定位錯(cuò)誤的,因?yàn)闃I(yè)務(wù)邏輯分散在各種不同的組件里面,讓你很難來通過行為來定義到底是哪些代碼涉及的這個(gè)錯(cuò)誤,不同組件復(fù)用這些邏輯也很困難。

          最好在?stores?中把業(yè)務(wù)邏輯編寫成方法,并在你的?Component?中調(diào)用這些方法。

          只允許在 store 中修改屬性

          盡量不要在一個(gè)?Component?里直接修改一個(gè)?store?的屬性。只有?store?本身可以修改他自己的屬性。

          當(dāng)你要改變屬性的時(shí)候,請調(diào)用相應(yīng)的?store?方法。不然的話你的屬性修改會散落在各處不受控制,這是很難調(diào)試的。

          class?Store?{
          ??@observable?text;
          ??
          [email protected]
          ??handleSearch?=?value?=>?{
          ????this.text?=?value
          ??}
          }

          const?store?=?new?Store();

          @observer
          class?Home?extends?Component?{
          ??
          ??handleChanged?=?(event)?=>?{
          ????store.handleSearch(event.target.value);
          ??}
          ??
          ??render()?{
          ????return?(
          ??????<input
          ????????value={store.searchText}
          ????????onChange={this.handleChanged}
          ??????/>

          ????);
          ??}
          }

          所有屬性更改都用 action

          使用?action?后,可以清楚的看出哪些代碼可以更改可觀察的變量,并且方便調(diào)試工具給出更多的信息

          使用?transaction?可以將多個(gè)應(yīng)用狀態(tài)(Observable)的更新視為一次操作,并只觸發(fā)一次監(jiān)聽者(Reactions)的動作(UI更新、網(wǎng)絡(luò)請求等),避免多次重復(fù)渲染。action中封裝了transaction,多次改變@observable變量時(shí),只會重新渲染一次,提高了性能。

          class?Store?{
          ??@observable?name;
          ??@observable?age;

          ??@action
          ??change(name,age){
          ????this.name?=?name;
          ????this.age?=?age;
          ??}
          }

          從 store 中分離出 API 請求

          不要在你的?store?里調(diào)用?API?接口,這會讓它們很難測試,也讓代碼變的更復(fù)雜和耦合。額外建一個(gè)類,把?API?接口調(diào)用放進(jìn)去,并在?store?的構(gòu)造函數(shù)里實(shí)例化他們來使用。當(dāng)你編寫測試代碼時(shí),你可以很容易地模擬這些?api?并把你的模擬?api?實(shí)例傳給每一個(gè)?store

          class?UserService?{

          ??fetchUser?=?()?=>?axios.get('/api/user')
          }

          class?Store?{

          ??@observable?todos?=?[];

          ??constructor(userService)?{
          ????this.userService?=?userService;
          ??}

          ??fetchUser?=?async?()?=>?{
          ????const?todos?=?await?this.userService.fetchUser();

          ????runInAction(()?=>?{
          ??????this.todos?=?todos;
          ????});
          ??}
          }

          const?userService?=?new?UserService();
          const?store?=?new?Store(userService);

          對每一個(gè) component 都聲明 @observer

          @observer?可以用來將?React?組件轉(zhuǎn)變成響應(yīng)式組件。它用?mobx.autorun?包裝了組件的?render?函數(shù)以確保任何組件渲染中使用的數(shù)據(jù)變化時(shí)都可以強(qiáng)制刷新組件。

          給每一個(gè)?component?都標(biāo)注?@observer?,這可以使得他們可以隨著?store prop?的改變而更新。如果子組件沒有標(biāo)注?@observer?的話,就會導(dǎo)致其父?component?(有?@observer?)刷新。因此我們要盡可能的讓每個(gè)子?component?都標(biāo)注?@observer?,這可以減少不必要的重新渲染。

          不要緩存 observables 屬性

          Observer?組件只會追蹤在?render?方法中存取的數(shù)據(jù)。如果你從?observable?屬性中提取數(shù)據(jù)并將其緩存在組件里,這樣的數(shù)據(jù)是不會被追蹤的:

          class?Store?{
          ??@observable?name;
          ??@observable?age;
          }

          class?Home?extends?React.Component?{

          ??componentWillMount()?{
          ????//?錯(cuò)誤的,info?的更新不會被追蹤
          ????this.info?=?store.name?+?store.age
          ??}

          ??render()?{
          ????return?<div>{this.info}div>
          ??}
          }

          使用 @computed

          比如剛剛的例子,使用?@computed?屬性來處理一些涉及多個(gè)屬性的邏輯。使用?@computed?可以減少這樣的判斷類業(yè)務(wù)邏輯在組件里面出現(xiàn)的頻率。

          class?Store?{
          ??@observable?name;
          ??@observable?age;

          ??@computed?info?=?()?=>?{
          ????return?this.name?+?this.age;
          ??}
          }

          class?Home?extends?React.Component?{

          ??render()?{
          ????return?<div>{store.info}div>
          ??}
          }

          多編寫受控組件

          多編寫可控組件,這樣會大大降低你的測試復(fù)雜度,也讓你的組件易于管理。

          當(dāng)需要追蹤對象屬性時(shí)、使用 map

          MobX?可以做許多事,但是它無法將原始類型值轉(zhuǎn)變成?observable?(盡管可以用對象來包裝它們)。所以說值不是?observable,而對象的屬性才是。這意味著?@observer?實(shí)際上是對間接引用值作出反應(yīng)。所以如果像下面這樣初始化的話,Timer?組件是不會作出任何反應(yīng)的:

          ReactDom.render(<Timer?timerData={timerData.secondsPassed}?/>,?document.body)

          在這行代碼中,只是?secondsPassed?的當(dāng)前值傳遞給了?Timer,這個(gè)值是不可變值 (JS中的所有原始類型值都是不可變的)。這個(gè)值永遠(yuǎn)都不會改變,所以?Timer?也永遠(yuǎn)不會更新。?secondsPassed?屬性將來會改變,所以我們需要在組件內(nèi)訪問它。或者換句話說: 永遠(yuǎn)只傳遞擁有?observable?屬性的對象。

          如果你想追蹤對象中每個(gè)屬性的變更,可以使用?map

          observable.map(values?)?創(chuàng)建一個(gè)動態(tài)鍵的?observable?映射。如果你不但想對一個(gè)特定項(xiàng)的更改做出反應(yīng),而且對添加或刪除該項(xiàng)也做出反應(yīng)的話,那么?observable?映射會非常有用。

          class?Store?{
          [email protected]({secondsPassed:0});

          [email protected]
          ??change(value){
          ????this.timerData.set('secondsPassed',value);
          ??}
          }

          class?Home?extends?React.Component?{

          ??render()?{
          ????return?<div>{store.timerData.get('secondsPassed')}div>
          ??}
          }




          推薦閱讀




          我的公眾號能帶來什么價(jià)值?(文末有送書規(guī)則,一定要看)

          每個(gè)前端工程師都應(yīng)該了解的圖片知識(長文建議收藏)

          為什么現(xiàn)在面試總是面試造火箭?

          瀏覽 61
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  青青草网站在线 | 亚洲欧洲日本不卡视频在线观看 | 日本无套内射 | 伊人成人视屏 | 狠狠干狠狠色 |