mobx中的inject,observer遷移至react Hooks寫法

1、老的用法

mobx是一個使用十分普遍的狀態(tài)管理工具,在實際的開發(fā)過程中我們常常搭配react進行使用。在一些比較大的項目中,部分變量需要反復(fù)向下層組件進行傳遞,如果使用傳統(tǒng)的組件props進行實現(xiàn),層層包裹,未免過于繁瑣,react官方針對這種場景,推出了context來進行上下文跨組件傳遞。而mobx也立足于react的context實現(xiàn)了inject語法,通過簡潔的api,可以在任何想要使用全局狀態(tài)的地方注入變量。為了方便進行全局的狀態(tài)管理,往往設(shè)定一個全局的store,其中定義一些全局都會使用到的變量,進行狀態(tài)控制,比較典型的例子如下:

import React from 'react';
import { inject, observer } from 'mobx-react';
import comA from 'comA ';
import comB from 'comB';

@inject('globalStore')
@observer
class Test extends React.Component{
    render() {
        const PanelContent = {
            'comA': comA,
            'comB': comB
        }
        const ShowContent = PanelContent[this.props.globalStore.funcType];
        return (
            <React.Fragment>
                <ShowContent />
            </React.Fragment>
        )
    }
}

export default Test ;

這里使用decorator裝飾器語法,通過字符串的方式注入全局store,組件的this上將會添加屬性globalStore,通過store中的funcType的變量來控制顯示的組件,該變量變化時,渲染的組件也會根據(jù)條件變化(通過observer裝飾器實現(xiàn))。其外圍容器的寫法通常如下:

import React from 'react';
import { Provider, observer } from 'mobx-react';
import Test from 'Text';
import globalStorefrom './globalStore';

class parentCom extends React.Component {
    const Store = new globalStore({ funcType: 'comA'});
    return (
        <Provider globalStore={Store}>
          <Test />
        </Provider>
    )
};

export default parentCom;

其父組件通過mobx-react的provider包裹器來將全局的store作為參數(shù)傳入。哪怕嵌套多層,子組件也可直接通過添加inject裝飾器來使用全局store中的變量,就如Test。

2、hooks中的inject

react在最新的16.8中啟用了hooks語法,力推函數(shù)式組件,盡管官方表示class式的組件在后續(xù)版本中并不會廢棄,但是hooks是未來前端框架中組件的發(fā)展方向(最新的Vue也借鑒了react Hook的很多思路),我們需要大膽嘗試新鮮事物。
到mobx官網(wǎng)上發(fā)現(xiàn),幾乎所有的例子都是基于class組件來寫的,并沒有發(fā)現(xiàn)跟react hook搭配使用的內(nèi)容。。。最后在一個不起眼處,找到了一個鏈接,指向mobx-react的遷移文檔。官方操作如下:

import { MobXProviderContext } from 'mobx-react'
function useStores() {
  return React.useContext(MobXProviderContext)
}

自己定義一個react hook,讓后就可以在我們自己的組件中使用了:

function useUserData() {
  const { user, order } = useStores()
  return {
    username: user.name,
    orderId: order.id,
  }
}

const UserOrderInfo = observer(() => {
  // Do not destructure data!
  const data = useUserData()
  return (
    <div>
      {data.username} has order {data.orderId}
    </div>
  )
})

從官方例子中,我們可以發(fā)現(xiàn)可以棄用inject語法糖,直接通過自定義的useStores,我們就可以實現(xiàn)獲取外層provider的變量并且使用,注意此處不能使用解構(gòu)賦值,否則的話會導(dǎo)致無法實現(xiàn)變量的觀測(即變量改變,頁面顯示沒有同步),如果要實現(xiàn)觀測:

// use mobx-react@6.1.2 or `mobx-react-lite`
import { useObserver } from 'mobx-react'
function useUserData() {
  const { user, order } = useStores()
  return useObserver(() => ({
    username: user.name,
    orderId: order.id,
  }))
}

const UserOrderInfo = () => {
  // this works now just fine
  const { username, orderId } = useUserData()
  return (
    <div>
      {username} has order {orderId}
    </div>
  )
}

如果你還是想要自己手動實現(xiàn)inject方法,那么官方還給了一個簡單的inject組件實現(xiàn):

import { MobXProviderContext } from 'mobx-react'
function inject(selector, baseComponent) {
  const component = ownProps => {
    const store = React.useContext(MobXProviderContext)
    return useObserver(() => baseComponent(selector({ store, ownProps })))
  }
  component.displayName = baseComponent.name
  return component
}

回到我們自己的組件,如果第一部分中的組件,要通過函數(shù)式組件的方式,使用provider提供的全局store要怎么辦呢?

import React from 'react';
import { observer } from 'mobx-react';
import comA from 'comA ';
import comB from 'comB';
import { useStores } from '@utils/index';

function useStores(name) {
    return React.useContext(MobXProviderContext)[name];
}

const Test = () => {
    const store = useStores('flagStore');  //  手動傳入字符串,選擇要使用的內(nèi)容
        const PanelContent = {
            'comA': comA,
            'comB': comB
        }
    const ShowContent = PanelContent[store.funcType];
    return (
        <React.Fragment>
            <ShowContent />
        </React.Fragment>
    )
}

export default observer(Test );

官方例子中的useStores會返回所有在context中的內(nèi)容,也就是所有上級provider中傳遞的內(nèi)容,此處我們通過在自己的實現(xiàn)中傳入一個字符串來控制選取我們需要的內(nèi)容。
如有任何疑問,歡迎留言交流~
————————————————————————————————————
參考文獻:
mobx-react遷移官方文檔:
https://mobx-react.js.org/recipes-migration

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容