国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

理解 React 輕量狀態管理庫 Unstated

Profeel / 453人閱讀

摘要:返回,用來包裹頂層組件,向應用中注入狀態管理實例,可做數據的初始化。方法返回創建的狀態管理實例,作為參數傳遞給調用的函數,函數拿到實例,操作或顯示數據。用來實現一個狀態管理類。為中的狀態管理實例數據。

個人網站: https://www.neroht.com

在React寫應用的時候,難免遇到跨組件通信的問題。現在已經有很多的解決方案。

React本身的Context

Redux結合React-redux

Mobx結合mobx-react

React 的新的Context api本質上并不是React或者Mbox這種狀態管理工具的替代品,充其量只是對React
自身狀態管理短板的補充。而Redux和Mbox這兩個庫本身并不是為React設計的,對于一些小型的React應用
比較重。

基本概念

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

Container:狀態管理類,內部使用state存儲狀態,通過setState實現狀態的更新,api設計與React的組件基本一致。

Provider:返回Provider,用來包裹頂層組件,向應用中注入狀態管理實例,可做數據的初始化。

Subscribe:本質上是Consumer,獲取狀態管理實例,在Container實例更新狀態的時候強制更新視圖。

簡單的例子

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

維護狀態

首先,共享狀態需要有個狀態管理的地方,與Redux的Reducer不同的是,Unstated是通過一個繼承自Container實例:

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

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

共享狀態

來看一下要顯示數字的Child1組件,利用Subscribe與CounterContainer建立聯系。

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

再來看一下要控制數字加減的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內部返回的是StateContext.Consumer,通過to這個prop關聯到CounterContainer實例,
使用renderProps模式渲染視圖,Subscribe之內調用的函數的參數就是訂閱的那個狀態管理實例。
Child1Child2通過Subscribe訂閱共同的狀態管理實例CounterContainer,所以Child2可以調用
CounterContainer之內的increment和decrement方法來更新狀態,而Child1會根據更新來顯示數據。

看一下父組件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向組件的上下文中注入狀態管理實例。
這里,可以不注入實例。不注入的話,Subscribe內部就不能拿到注入的實例去初始化數據,也就是給狀態一個默認值,比如上邊我給的是123。

也可以注入多個實例:


   {/*Components*}

那么,在Subscribe的時候可以拿到多個實例。


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

弄明白原理之前需要先明白Unstated提供的三個API之間的關系。我根據自己的理解,畫了一張圖:

來梳理一下整個流程:

創建狀態管理類繼承自Container

生成上下文,new一個狀態管理的實例,給出默認值,注入Provider

Subscribe訂閱狀態管理類。內部通過_createInstances方法來初始化狀態管理實例并訂閱該實例,具體過程如下:

從上下文中獲取狀態管理實例,如果獲取到了,那它直接去初始化數據,如果沒有獲取到

那么就用to中傳入的狀態管理類來初始化實例。

將自身的更新視圖的函數onUpdate通過訂閱到狀態管理實例,來實現實例內部setState的時候,調用onUpdate更新視圖。

_createInstances方法返回創建的狀態管理實例,作為參數傳遞給renderProps調用的函數,函數拿到實例,操作或顯示數據。

Container

用來實現一個狀態管理類。可以理解為redux中action和reducer的結合。概念相似,但實現不同。來看一下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();
      }
      // 返回一個新的state
      this.state = Object.assign({}, this.state, nextState);
      // 執行listener,也就是Subscribe的onUpdate函數,用來強制刷新視圖
      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這三個方法。

state來存放數據,listeners是一個數組,存放更新視圖的函數。

subscribe會將更新的函數(Subscribe組件內的onUpdate)放入linsteners。

setState和react的setState相似。執行時,會根據變動返回一個新的state,

同時循環listeners調用其中的更新函數。達到更新頁面的效果。

unsubscribe用來取消訂閱。

Provider

Provider本質上返回的是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}
          
        );
      }}
    
  );
}

它自己接收一個inject屬性,經過處理后,將它作為context的值傳入到上下文環境中。
可以看出,傳入的值為一個map,使用Container類作為鍵,Container類的實例作為值。
Subscribe會接收這個map,優先使用它來實例化Container類,初始化數據

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

Subscribe

簡單來說就是連接組件與狀態管理類的一座橋梁,可以想象成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兩個方法。StateContext.Consumer接收Provider傳遞過來的map,
與props接收的to一并傳給_createInstances。

onUpdate:沒有做什么其他事情,只是利用setState更新視圖,返回一個promise。它存在的意義是在訂閱的時候,
作為參數傳入Container類的subscribe,擴充Container類的listeners數組,隨后在Container類setState改變狀態以后,
循環listeners的每一項就是這個onUpdate方法,它執行,就會更新視圖。

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

 
   {
     counter => {
       return 
} }
總結

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

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

純粹極簡的react狀態管理組件unstated

Unstated淺析

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/103345.html

相關文章

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

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

    DobbyKim 評論0 收藏0
  • React組件設計實踐總結05 - 狀態管理

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

    ideaa 評論0 收藏0
  • [源碼閱讀]純粹極簡的react狀態管理組件unstated

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

    FrancisSoung 評論0 收藏0
  • React 新 Context API 在前端狀態管理的實踐

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

    wing324 評論0 收藏0
  • 一個治愈 JavaScript 疲勞的學習計劃

    摘要:只是抱怨事物的狀態并沒有什么卵用,我打算給你一個實實在在的一步一步征服生態圈的學習計劃。好消息是,這剛好是本學習計劃關注的問題。比如,一個不錯的出發點是的課。是一個由創建和開源的庫。我個人推薦的初學者課程。而個人項目是嘗試新技術的完美時機。 本文轉載自:眾成翻譯譯者:網絡埋伏紀事鏈接:http://www.zcfy.cc/article/1617原文:https://medium.fr...

    jhhfft 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<