成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

理解 React 輕量狀態(tài)管理庫 Unstated

Profeel / 462人閱讀

摘要:返回,用來包裹頂層組件,向應(yīng)用中注入狀態(tài)管理實(shí)例,可做數(shù)據(jù)的初始化。方法返回創(chuàng)建的狀態(tài)管理實(shí)例,作為參數(shù)傳遞給調(diào)用的函數(shù),函數(shù)拿到實(shí)例,操作或顯示數(shù)據(jù)。用來實(shí)現(xiàn)一個(gè)狀態(tài)管理類。為中的狀態(tài)管理實(shí)例數(shù)據(jù)。

個(gè)人網(wǎng)站: https://www.neroht.com

在React寫應(yīng)用的時(shí)候,難免遇到跨組件通信的問題。現(xiàn)在已經(jīng)有很多的解決方案。

React本身的Context

Redux結(jié)合React-redux

Mobx結(jié)合mobx-react

React 的新的Context api本質(zhì)上并不是React或者M(jìn)box這種狀態(tài)管理工具的替代品,充其量只是對(duì)React
自身狀態(tài)管理短板的補(bǔ)充。而Redux和Mbox這兩個(gè)庫本身并不是為React設(shè)計(jì)的,對(duì)于一些小型的React應(yīng)用
比較重。

基本概念

Unstated是基于context API,也就是使用React.createContext()來創(chuàng)建一個(gè)StateContext來傳遞狀態(tài)的庫

Container:狀態(tài)管理類,內(nèi)部使用state存儲(chǔ)狀態(tài),通過setState實(shí)現(xiàn)狀態(tài)的更新,api設(shè)計(jì)與React的組件基本一致。

Provider:返回Provider,用來包裹頂層組件,向應(yīng)用中注入狀態(tài)管理實(shí)例,可做數(shù)據(jù)的初始化。

Subscribe:本質(zhì)上是Consumer,獲取狀態(tài)管理實(shí)例,在Container實(shí)例更新狀態(tài)的時(shí)候強(qiáng)制更新視圖。

簡(jiǎn)單的例子

我們拿最通用的計(jì)數(shù)器的例子來看unstated如何使用,先明確一下結(jié)構(gòu):Parent作為父組件包含兩個(gè)子組件:Child1和Child2。
Child1展示數(shù)字,Child2操作數(shù)字的加減。然后,Parent組件的外層會(huì)包裹一個(gè)根組件。

維護(hù)狀態(tài)

首先,共享狀態(tài)需要有個(gè)狀態(tài)管理的地方,與Redux的Reducer不同的是,Unstated是通過一個(gè)繼承自Container實(shí)例:

import { Container } from "unstated";

class CounterContainer extends Container {
  constructor(initCount) {
    super(...arguments);
    this.state = {count: initCount || 0};
  }

  increment = () => {
    this.setState({ count: this.state.count + 1 });
  }

  decrement = () => {
    this.setState({ count: this.state.count - 1 });
  }
}

export default CounterContainer

看上去是不是很熟悉?像一個(gè)React組件類。CounterContainer繼承自Unstated暴露出來的Container類,利用state存儲(chǔ)數(shù)據(jù),setState維護(hù)狀態(tài),
并且setState與React的setState用法一致,可傳入函數(shù)。返回的是一個(gè)promise。

共享狀態(tài)

來看一下要顯示數(shù)字的Child1組件,利用Subscribe與CounterContainer建立聯(lián)系。

import React from "react"
import { Subscribe } from "unstated"
import CounterContainer from "./store/Counter"
class Child1 extends React.Component {
  render() {
    return 
      {
        counter => {
          return 
{counter.state.count}
} }
} } export default Child1

再來看一下要控制數(shù)字加減的Child2組件:

import React from "react"
import { Button } from "antd"
import { Subscribe } from "unstated"
import CounterContainer from "./store/Counter"
class Child2 extends React.Component {
  render() {
    return 
      {
        counter => {
          return 
} }
} } export default Child2

Subscribe內(nèi)部返回的是StateContext.Consumer,通過to這個(gè)prop關(guān)聯(lián)到CounterContainer實(shí)例,
使用renderProps模式渲染視圖,Subscribe之內(nèi)調(diào)用的函數(shù)的參數(shù)就是訂閱的那個(gè)狀態(tài)管理實(shí)例。
Child1Child2通過Subscribe訂閱共同的狀態(tài)管理實(shí)例CounterContainer,所以Child2可以調(diào)用
CounterContainer之內(nèi)的increment和decrement方法來更新狀態(tài),而Child1會(huì)根據(jù)更新來顯示數(shù)據(jù)。

看一下父組件Parent

import React from "react"
import { Provider } from "unstated"
import Child1 from "./Child1"
import Child2 from "./Child2"
import CounterContainer from "./store/Counter"

const counter = new CounterContainer(123)

class Parent extends React.Component {
  render() {
    return 
      父組件
      
      
    
  }
}

export default Parent

Provider返回的是StateContext.Provider,Parent通過Provider向組件的上下文中注入狀態(tài)管理實(shí)例。
這里,可以不注入實(shí)例。不注入的話,Subscribe內(nèi)部就不能拿到注入的實(shí)例去初始化數(shù)據(jù),也就是給狀態(tài)一個(gè)默認(rèn)值,比如上邊我給的是123。

也可以注入多個(gè)實(shí)例:


   {/*Components*}

那么,在Subscribe的時(shí)候可以拿到多個(gè)實(shí)例。


  {count1, count2) => {}
分析原理

弄明白原理之前需要先明白Unstated提供的三個(gè)API之間的關(guān)系。我根據(jù)自己的理解,畫了一張圖:

來梳理一下整個(gè)流程:

創(chuàng)建狀態(tài)管理類繼承自Container

生成上下文,new一個(gè)狀態(tài)管理的實(shí)例,給出默認(rèn)值,注入Provider

Subscribe訂閱狀態(tài)管理類。內(nèi)部通過_createInstances方法來初始化狀態(tài)管理實(shí)例并訂閱該實(shí)例,具體過程如下:

從上下文中獲取狀態(tài)管理實(shí)例,如果獲取到了,那它直接去初始化數(shù)據(jù),如果沒有獲取到

那么就用to中傳入的狀態(tài)管理類來初始化實(shí)例。

將自身的更新視圖的函數(shù)onUpdate通過訂閱到狀態(tài)管理實(shí)例,來實(shí)現(xiàn)實(shí)例內(nèi)部setState的時(shí)候,調(diào)用onUpdate更新視圖。

_createInstances方法返回創(chuàng)建的狀態(tài)管理實(shí)例,作為參數(shù)傳遞給renderProps調(diào)用的函數(shù),函數(shù)拿到實(shí)例,操作或顯示數(shù)據(jù)。

Container

用來實(shí)現(xiàn)一個(gè)狀態(tài)管理類。可以理解為redux中action和reducer的結(jié)合。概念相似,但實(shí)現(xiàn)不同。來看一下Container的源碼

export class Container {
  constructor() {
    CONTAINER_DEBUG_CALLBACKS.forEach(cb => cb(this));
    this.state = null;
    this.listeners = [];
  }

  setState(updater, callback) {
    return Promise.resolve().then(() => {
      let nextState = null;
      if (typeof updater === "function") {
        nextState = updater(this.state);
      } else {
        nextState = updater;
      }

      if (nextState === null) {
        callback && callback();
      }
      // 返回一個(gè)新的state
      this.state = Object.assign({}, this.state, nextState);
      // 執(zhí)行l(wèi)istener,也就是Subscribe的onUpdate函數(shù),用來強(qiáng)制刷新視圖
      const promises = this.listeners.map(listener => listener());

      return Promise.all(promises).then(() => {
        if (callback) {
          return callback();
        }
      });
    });
  }

  subscribe(fn) {
    this.listeners.push(fn);
  }

  unsubscribe(fn) {
    this.listeners = this.listeners.filter(f => f !== fn);
  }
}

Container包含了state、listeners,以及setState、subscribe、unsubscribe這三個(gè)方法。

state來存放數(shù)據(jù),listeners是一個(gè)數(shù)組,存放更新視圖的函數(shù)。

subscribe會(huì)將更新的函數(shù)(Subscribe組件內(nèi)的onUpdate)放入linsteners。

setState和react的setState相似。執(zhí)行時(shí),會(huì)根據(jù)變動(dòng)返回一個(gè)新的state,

同時(shí)循環(huán)listeners調(diào)用其中的更新函數(shù)。達(dá)到更新頁面的效果。

unsubscribe用來取消訂閱。

Provider

Provider本質(zhì)上返回的是StateContext.Provider。

export function Provider(ProviderProps) {
  return (
    
      {parentMap => {
        let childMap = new Map(parentMap);

        if (props.inject) {
          props.inject.forEach(instance => {
            childMap.set(instance.constructor, instance);
          });
        }

        return (
          
            {props.children}
          
        );
      }}
    
  );
}

它自己接收一個(gè)inject屬性,經(jīng)過處理后,將它作為context的值傳入到上下文環(huán)境中。
可以看出,傳入的值為一個(gè)map,使用Container類作為鍵,Container類的實(shí)例作為值。
Subscribe會(huì)接收這個(gè)map,優(yōu)先使用它來實(shí)例化Container類,初始化數(shù)據(jù)。

可能有人注意到了Provider不是直接返回的StateContext.Provider,而是套了一層
StateContext.Consumer。這樣做的目的是Provider之內(nèi)還可以嵌套Provider。
內(nèi)層Provider的value可以繼承自外層。

Subscribe

簡(jiǎn)單來說就是連接組件與狀態(tài)管理類的一座橋梁,可以想象成react-redux中connect的作用

class Subscribe extends React.Component {
  constructor(props) {
    super(props);
    this.state = {};
    this.instances = [];
    this.unmounted = false;
  }

  componentWillUnmount() {
    this.unmounted = true;
    this.unsubscribe();
  }

  unsubscribe() {
    this.instances.forEach((container) => {
      container.unsubscribe(this.onUpdate);
    });
  }

  onUpdate = () => new Promise((resolve) => {
    if (!this.unmounted) {
      this.setState(DUMMY_STATE, resolve);
    } else {
      resolve();
    }
  })

  _createInstances(map, containers) {
    this.unsubscribe();

    if (map === null) {
      throw new Error("You must wrap your  components with a ");
    }

    const safeMap = map;
    const instances = containers.map((ContainerItem) => {
      let instance;

      if (
        typeof ContainerItem === "object" &&
        ContainerItem instanceof Container
      ) {
        instance = ContainerItem;
      } else {
        instance = safeMap.get(ContainerItem);

        if (!instance) {
          instance = new ContainerItem();
          safeMap.set(ContainerItem, instance);
        }
      }

      instance.unsubscribe(this.onUpdate);
      instance.subscribe(this.onUpdate);

      return instance;
    });

    this.instances = instances;
    return instances;
  }

  render() {
    return (
      
        {
          map => this.props.children.apply(
            null,
            this._createInstances(map, this.props.to),
          )
        }
      
    );
  }
}

這里比較重要的是_createInstances與onUpdate兩個(gè)方法。StateContext.Consumer接收Provider傳遞過來的map,
與props接收的to一并傳給_createInstances。

onUpdate:沒有做什么其他事情,只是利用setState更新視圖,返回一個(gè)promise。它存在的意義是在訂閱的時(shí)候,
作為參數(shù)傳入Container類的subscribe,擴(kuò)充Container類的listeners數(shù)組,隨后在Container類setState改變狀態(tài)以后,
循環(huán)listeners的每一項(xiàng)就是這個(gè)onUpdate方法,它執(zhí)行,就會(huì)更新視圖。

_createInstances: map為provider中inject的狀態(tài)管理實(shí)例數(shù)據(jù)。如果inject了,那么就用map來實(shí)例化數(shù)據(jù),
否則用this.props.to的狀態(tài)管理類來實(shí)例化。之后調(diào)用instance.subscribe方法(也就是Container中的subscribe),
傳入自身的onUpdate,實(shí)現(xiàn)訂閱。它存在的意義是實(shí)例化Container類并將自身的onUpdate訂閱到Container類實(shí)例,
最終返回這個(gè)Container類的實(shí)例,作為this.props.children的參數(shù)并進(jìn)行調(diào)用,所以在組件內(nèi)部可以進(jìn)行類似這樣的操作:

 
   {
     counter => {
       return 
} }
總結(jié)

Unstated上手很容易,理解源碼也不難。重點(diǎn)在于理解發(fā)布(Container類),Subscribe組件實(shí)現(xiàn)訂閱的思路。
其API的設(shè)計(jì)貼合React的設(shè)計(jì)理念。也就是想要改變UI必須setState。另外可以不用像Redux一樣寫很多樣板代碼。

理解源碼的過程中受到了下面兩篇文章的啟發(fā),衷心感謝:

純粹極簡(jiǎn)的react狀態(tài)管理組件unstated

Unstated淺析

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/103345.html

相關(guān)文章

  • 前端每周清單第 50 期: AngularJS and Long Term Support, Web

    摘要:在該版本發(fā)布之后,開發(fā)團(tuán)隊(duì)并不會(huì)繼續(xù)發(fā)布新的特性,而會(huì)著眼于進(jìn)行重大的錯(cuò)誤修復(fù)。發(fā)布每六個(gè)星期,團(tuán)隊(duì)就會(huì)創(chuàng)建新的分支作為發(fā)布通道,本文即是對(duì)新近發(fā)布的版本進(jìn)行簡(jiǎn)要介紹。 showImg(https://segmentfault.com/img/remote/1460000013229009); 前端每周清單專注前端領(lǐng)域內(nèi)容,以對(duì)外文資料的搜集為主,幫助開發(fā)者了解一周前端熱點(diǎn);分為新聞熱...

    DobbyKim 評(píng)論0 收藏0
  • React組件設(shè)計(jì)實(shí)踐總結(jié)05 - 狀態(tài)管理

    摘要:要求通過要求數(shù)據(jù)變更函數(shù)使用裝飾或放在函數(shù)中,目的就是讓狀態(tài)的變更根據(jù)可預(yù)測(cè)性單向數(shù)據(jù)流。同一份數(shù)據(jù)需要響應(yīng)到多個(gè)視圖,且被多個(gè)視圖進(jìn)行變更需要維護(hù)全局狀態(tài),并在他們變動(dòng)時(shí)響應(yīng)到視圖數(shù)據(jù)流變得復(fù)雜,組件本身已經(jīng)無法駕馭。今天是 520,這是本系列最后一篇文章,主要涵蓋 React 狀態(tài)管理的相關(guān)方案。 前幾篇文章在掘金首發(fā)基本石沉大海, 沒什么閱讀量. 可能是文章篇幅太長了?掘金值太低了? ...

    ideaa 評(píng)論0 收藏0
  • [源碼閱讀]純粹極簡(jiǎn)的react狀態(tài)管理組件unstated

    摘要:此處繼承了上面的可以注入現(xiàn)成的狀態(tài)管理實(shí)例,添加到之中。返回值寫成的意義簡(jiǎn)單一句話概括,這么寫可以避免改變導(dǎo)致子組件的重復(fù)渲染。就是創(chuàng)建狀態(tài)管理組件時(shí)默認(rèn)傳遞的監(jiān)聽函數(shù),用的是的更新一個(gè)空對(duì)象。返回值寫成的意義。 簡(jiǎn)介 unstated是一個(gè)極簡(jiǎn)的狀態(tài)管理組件 看它的簡(jiǎn)介:State so simple, it goes without saying 對(duì)比 對(duì)比redux: 更加靈活...

    FrancisSoung 評(píng)論0 收藏0
  • React 新 Context API 在前端狀態(tài)管理的實(shí)踐

    摘要:本文轉(zhuǎn)載至今日頭條技術(shù)博客眾所周知,的單向數(shù)據(jù)流模式導(dǎo)致狀態(tài)只能一級(jí)一級(jí)的由父組件傳遞到子組件,在大中型應(yīng)用中較為繁瑣不好管理,通常我們需要使用來幫助我們進(jìn)行管理,然而隨著的發(fā)布,新成為了新的選擇。 本文轉(zhuǎn)載至:今日頭條技術(shù)博客showImg(https://segmentfault.com/img/bVbiNJO?w=900&h=383);眾所周知,React的單向數(shù)據(jù)流模式導(dǎo)致狀態(tài)...

    wing324 評(píng)論0 收藏0
  • 一個(gè)治愈 JavaScript 疲勞的學(xué)習(xí)計(jì)劃

    摘要:只是抱怨事物的狀態(tài)并沒有什么卵用,我打算給你一個(gè)實(shí)實(shí)在在的一步一步征服生態(tài)圈的學(xué)習(xí)計(jì)劃。好消息是,這剛好是本學(xué)習(xí)計(jì)劃關(guān)注的問題。比如,一個(gè)不錯(cuò)的出發(fā)點(diǎn)是的課。是一個(gè)由創(chuàng)建和開源的庫。我個(gè)人推薦的初學(xué)者課程。而個(gè)人項(xiàng)目是嘗試新技術(shù)的完美時(shí)機(jī)。 本文轉(zhuǎn)載自:眾成翻譯譯者:網(wǎng)絡(luò)埋伏紀(jì)事鏈接:http://www.zcfy.cc/article/1617原文:https://medium.fr...

    jhhfft 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<