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

資訊專欄INFORMATION COLUMN

「譯」setState如何知道它該做什么?

OldPanda / 1261人閱讀

摘要:本文翻譯自原作者如果有任何版權(quán)問(wèn)題,請(qǐng)聯(lián)系當(dāng)你在組件中調(diào)用時(shí),你覺得會(huì)發(fā)生什么當(dāng)然,會(huì)用這條狀態(tài)重新渲染組件并且更新匹配到的,然后返回元素。如果你之前使用過(guò)一些渲染器比如說(shuō),你可能知道在頁(yè)面中使用超過(guò)一個(gè)渲染器是沒什么問(wèn)題的。

本文翻譯自:How Does setState Know What to Do?

原作者:Dan Abramov

如果有任何版權(quán)問(wèn)題,請(qǐng)聯(lián)系[email protected]

當(dāng)你在組件中調(diào)用setState時(shí),你覺得會(huì)發(fā)生什么?

import React from "react";
import ReactDOM from "react-dom";

class Button extends React.Component {
  constructor(props) {
    super(props);
    this.state = { clicked: false };
    this.handleClick = this.handleClick.bind(this);
  }
  handleClick() {
    this.setState({ clicked: true });
  }
  render() {
    if (this.state.clicked) {
      return 

Thanks

; } return ( ); } } ReactDOM.render(

當(dāng)然,React會(huì)用{ clicked: true} 這條狀態(tài)重新渲染組件并且更新匹配到的DOM,然后返回

Thanks

元素。

聽起來(lái)似乎簡(jiǎn)潔明了。但別急,React(或者說(shuō)React DOM)是怎么做的?

更新DOM聽起來(lái)像是React DOM的事兒,但別忘了我們調(diào)用的可是this.setState(),它是React的東西,可不是React DOM的。另外,我們的基類React.Component是被定義在React內(nèi)部。

所以問(wèn)題來(lái)了:React.Component內(nèi)部的setState怎么能去更新DOM呢?

事先聲明:就像我的其他博客,你不需要熟練掌握React。這篇博客是為那些想要看看面紗之后是什么東西的人準(zhǔn)備的。完全可選!

我們或許會(huì)認(rèn)為React.Component類已經(jīng)包含了DOM更新邏輯。

但如果這是事實(shí),那this.setState是如何工作在其他環(huán)境中呢?比如:在React Native App中的組件也能繼承React.Component,他們也能像上面一樣調(diào)用this.setState(),并且React Native工作在Android和iOS的原生視圖而不是DOM中。

你可能也對(duì)React Test Renderer 或 Shallow Renderer比較熟悉。這兩個(gè)測(cè)試渲染器讓你可以渲染一般的組件并且也能在他們中調(diào)用this.setState,但他們可都不使用DOM。

如果你之前使用過(guò)一些渲染器比如說(shuō)React ART,你可能知道在頁(yè)面中使用超過(guò)一個(gè)渲染器是沒什么問(wèn)題的。(比如:ART組件工作在React DOM 樹的內(nèi)部。)這會(huì)產(chǎn)生一個(gè)不可維持的全局標(biāo)志或變量。

所以React.Component以某種方式將state的更新委托為具體的平臺(tái)(譯者注:比如Android, iOS),在我們理解這是如何發(fā)生之前,讓我們對(duì)包是如何被分離和其原因挖得更深一點(diǎn)吧!

這有一個(gè)常見的錯(cuò)誤理解:React "引擎"在react包的內(nèi)部。這不是事實(shí)。

事實(shí)上,從 React 0.14開始對(duì)包進(jìn)行分割時(shí),React包就有意地僅導(dǎo)出關(guān)于如何定義組件的API了。React的大部分實(shí)現(xiàn)其實(shí)在“渲染器”中。

渲染器的其中一些例子包括:react-dom,react-dom/server,react-native,react-test-renderer,react-art(另外,你也可以構(gòu)建自己的)。

這就是為什么react包幫助很大而不管作用在什么平臺(tái)上。所有它導(dǎo)出的模塊,比如React.ComponentReact.createElement,React.Children[Hooks](https://reactjs.org/docs/hooks-intro.html),都是平臺(tái)無(wú)關(guān)的。無(wú)論你的代碼運(yùn)行在React DOM、React DOM Server、還是React Native,你的組件都可以以一種相同的方式導(dǎo)入并且使用它們。

與之相對(duì)的是,渲染器會(huì)暴露出平臺(tái)相關(guān)的接口,比如ReactDOM.render(),它會(huì)讓你可以把React掛載在DOM節(jié)點(diǎn)中。每個(gè)渲染器都提供像這樣的接口,但理想情況是:大多數(shù)組件都不需要從渲染器中導(dǎo)入任何東西。這能使它們更精簡(jiǎn)。

大多數(shù)人都認(rèn)為React“引擎”是位于每個(gè)獨(dú)立的渲染器中的。許多渲染器都包含一份相同的代碼—我們叫它“調(diào)節(jié)器”,為了表現(xiàn)的更好,遵循這個(gè)步驟 可以讓調(diào)節(jié)器的代碼和渲染器的代碼在打包時(shí)歸到一處。(拷貝代碼通常不是優(yōu)化“打包后文件”(bundle)體積的好辦法,但大多數(shù)React的使用者一次只需要一個(gè)渲染器,比如:react-dom(譯者注:因此可以忽略調(diào)節(jié)器的存在))

The takeaway here 是react包僅僅讓你知道如何使用React的特性而無(wú)需了解他們是如何被實(shí)現(xiàn)的。渲染器(react-dom,react-native等等)會(huì)提供React特性的實(shí)現(xiàn)和平臺(tái)相關(guān)的邏輯;一些關(guān)于調(diào)節(jié)器的代碼被分享出來(lái)了,但那只是多帶帶渲染器的實(shí)現(xiàn)細(xì)節(jié)而已。

現(xiàn)在我們知道了為什么reactreact-dom包需要為新特定更新代碼了。比如:當(dāng)React16.3新增了Context接口時(shí),React.createContext()方法會(huì)在React包中被暴露出來(lái)。

但是React.createContext()實(shí)際上不會(huì)實(shí)現(xiàn)具體的邏輯(譯者注:只定義接口,由其他渲染器來(lái)實(shí)現(xiàn)邏輯)。并且,在React DOM和React DOM Server上實(shí)現(xiàn)的邏輯也會(huì)有區(qū)別。所以createContext()會(huì)返回一些純粹的對(duì)象(定義如何實(shí)現(xiàn)):

// 一個(gè)簡(jiǎn)單例子
function createContext(defaultValue) {
  let context = {
    _currentValue: defaultValue,
    Provider: null,
    Consumer: null
  };
  context.Provider = {
    $$typeof: Symbol.for("react.provider"),
    _context: context
  };
  context.Consumer = {
    $$typeof: Symbol.for("react.context"),
    _context: context,
  };
  return context;
}

你會(huì)在某處代碼中使用>,那里就是決定著如何處理他們的渲染器。React DOM會(huì)用A方法追蹤context值,但React DOM Server或許會(huì)用另一個(gè)不同的方法實(shí)現(xiàn)。

所以如果你將react升級(jí)到16.3+,但沒有升級(jí)react-dom,你將使用一個(gè)還不知道ProviderConsumer類型的渲染器,這也就舊版的react-dom可能會(huì)報(bào)錯(cuò):fail saying these types are invalid的原因。

同樣的警告也會(huì)出現(xiàn)在React Native中,但是不同于React DOM,一個(gè)新的React版本不會(huì)立即產(chǎn)生一個(gè)對(duì)應(yīng)的React Native版本。他們(React Native)有自己的發(fā)布時(shí)間表。大概幾周后,渲染器代碼才會(huì)多帶帶更新到React Native庫(kù)中。這就是為什么新特性在React Native生效的時(shí)間會(huì)和React DOM不同。

Okay,那么現(xiàn)在我們知道了react包不包含任何好玩的東西,并且具體的實(shí)現(xiàn)都在像react-domreact-native這樣的渲染器中。但這并不能回答我們開頭提出的問(wèn)題。React.Component里的setState()是如何和對(duì)應(yīng)的渲染器通信的呢?

答案是每個(gè)渲染器都會(huì)在創(chuàng)建的類中添加一個(gè)特殊的東西,這個(gè)東西叫updater。它不是你添加的東西—恰恰相反,它是React DOM,React DOM Server 或者React Native在創(chuàng)建了一個(gè)類的實(shí)例后添加的:

// React DOM 中是這樣
const inst = new YourComponent();
inst.props = props;
inst.updater = ReactDOMUpdater;
// React DOM Server 中是這樣
const inst = new YourComponent();
inst.props = props;
inst.updater = ReactDOMServerUpdater;
// React Native 中是這樣
const inst = new YourComponent();
inst.props = props;
inst.updater = ReactNativeUpdater;

setState的實(shí)現(xiàn)就可以看出,它做的所有的工作就是把任務(wù)委托給在這個(gè)組件實(shí)例中創(chuàng)建的渲染器:

// 簡(jiǎn)單例子
setState(partialState, callback) {
  // 使用`updater`去和渲染器通信
  this.updater.enqueueSetState(this, partialState, callback);
}

React DOM Server 可能想忽略狀態(tài)更新并且警告你,然而React DOM和React Native將會(huì)讓調(diào)節(jié)器的拷貝部分去 處理它。

這就是盡管this.setState()被定義在React包中也可以更新DOM的原因。它調(diào)用被React DOM添加的this.updater并且讓React DOM來(lái)處理更新。

現(xiàn)在我們都比較了解“類”了,但“鉤子”(Hooks)呢?

當(dāng)人們第一次看到 鉤子接口的提案時(shí),他們常回想:useState是怎么知道該做什么呢?這一假設(shè)簡(jiǎn)直比對(duì)this.setState()的疑問(wèn)還要迷人。

但就像我們?nèi)缃窨吹降哪菢樱?b>setState()的實(shí)現(xiàn)一直以來(lái)都是模糊不清的。它除了傳遞調(diào)用給當(dāng)前的渲染器外什么都不做。所以,useState鉤子做的事也是如此。

這次不是updater,鉤子(Hooks)使用一個(gè)叫做“分配器”(dispatcher)的對(duì)象,當(dāng)你調(diào)用React.useState()、React.useEffect()或者其他自帶的鉤子時(shí),這些調(diào)用會(huì)被推送給當(dāng)前的分配器。

// In React (simplified a bit)
const React = {
  // Real property is hidden a bit deeper, see if you can find it!
  __currentDispatcher: null,

  useState(initialState) {
    return React.__currentDispatcher.useState(initialState);
  },

  useEffect(initialState) {
    return React.__currentDispatcher.useEffect(initialState);
  },
  // ...
};

多帶帶的渲染器會(huì)在渲染你的組件之前設(shè)置分配器(dispatcher)。

// In React DOM
const prevDispatcher = React.__currentDispatcher;
React.__currentDispatcher = ReactDOMDispatcher;let result;
try {
  result = YourComponent(props);
} finally {
  // Restore it back  React.__currentDispatcher = prevDispatcher;}

React DOM Server的實(shí)現(xiàn)在這里。由React DOM和React Native共享的調(diào)節(jié)器實(shí)現(xiàn)在這里。

這就是為什么像react-dom這樣的渲染器需要訪問(wèn)和你調(diào)用的鉤子所使用的react一樣的包。否則你的組件將找不到分配器!如果你有多個(gè)React的拷貝在相同的組件樹中,代碼可能不會(huì)正常工作。然而,這總是造成復(fù)雜的Bug,因此鉤子會(huì)在它耗光你的精力前強(qiáng)制你去解決包的副本問(wèn)題。

如果你不覺得這有什么,你可以在工具使用它們前精巧地覆蓋掉原先的分配器(__currentDispatcher的名字其實(shí)我自己編的但你可以在React倉(cāng)庫(kù)中找到它真正的名字)。比如:React DevTools會(huì)使用一個(gè)特殊的內(nèi)建分配器來(lái)通過(guò)捕獲JavaScript調(diào)用棧來(lái)反映(introspect)鉤子。不要在家里重復(fù)這個(gè)(Don’t repeat this at home.)(譯者注:可能是“不要在家里模仿某項(xiàng)實(shí)驗(yàn)”的衍生體??赡苁莻€(gè)笑話,但我get到)

這也意味著鉤子不是React固有的東西。如果在將來(lái)有很多類庫(kù)想要重用相同的基礎(chǔ)鉤子,理論上來(lái)說(shuō)分配器可能會(huì)被移到分離的包中并且被塑造成優(yōu)秀的接口—會(huì)有更少讓人望而生畏的名稱—暴露出來(lái)。在實(shí)際中,我們更偏向去避免過(guò)于倉(cāng)促地將某物抽象,直到我們的確需要這么做。

updater__currentDispatcher都是泛型程序設(shè)計(jì)(依賴注入/dependency injection)的絕佳實(shí)例。渲染器“注入”特性的實(shí)現(xiàn)。就像setState可以讓你的組件看起來(lái)簡(jiǎn)單明了。

當(dāng)你使用React時(shí),你不需要考慮它是如何工作的。我們期望React用戶去花費(fèi)更多的時(shí)間去考慮它們的應(yīng)用代碼而不是一些抽象的概念比如:依賴注入。但如果你曾好奇this.setState()useState()是怎么知道它們?cè)撟鍪裁吹模俏蚁M@篇文章將幫助到你。

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

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

相關(guān)文章

  • []React 的生命周期的使用場(chǎng)景

    摘要:譯的生命周期的使用場(chǎng)景原文鏈接作者翻譯上名這個(gè)圖片,就是組件的生命周期,從形成到銷毀的過(guò)程。這并不意味著沒有用。最常見的用例更新以響應(yīng)或更改。是否可以調(diào)用總結(jié)在理想的世界中,我們不會(huì)使用生命周期方法。 [譯]React 的生命周期的使用場(chǎng)景 showImg(https://segmentfault.com/img/bVLTCt?w=2000&h=800); 原文鏈接:React Lif...

    klinson 評(píng)論0 收藏0
  • React 常見的面試題(在 React 里面,你可以知道也可以不知道的事, 但是你會(huì)發(fā)現(xiàn)他們確實(shí)很

    摘要:為了使用它們,您可以向組件添加一個(gè)屬性,該屬性的值是一個(gè)回調(diào)函數(shù),它將接收底層的元素或組件的已掛接實(shí)例,作為其第一個(gè)參數(shù)。通常最好使用另一個(gè)生命周期方法,而不是依賴這個(gè)回調(diào)函數(shù),但是很高興知道它存在。 React 常見的面試題 (在 React 里面,你可以知道也可以不知道的事, 但是你會(huì)發(fā)現(xiàn)他們確實(shí)很有用) 根據(jù)記錄,問(wèn)這些問(wèn)題可能不是深入了解他們?cè)谑褂?React 方面的經(jīng)驗(yàn)的最...

    cppprimer 評(píng)論0 收藏0
  • 】React 組件的生命周期

    摘要:此篇文章我們將會(huì)繼續(xù)探索組件的特性,特別是生命周期。這些方法叫做組件的生命周期方法且會(huì)根據(jù)特定并可預(yù)測(cè)的順序被調(diào)用?;旧纤械慕M件的生命周期方法都可以被分割成四個(gè)階段初始化掛載階段更新階段卸載階段。 原文:https://medium.com/react-ecosystem/react-components-lifecycle-ce09239010df#.j7h6w8ccc 譯者序...

    Crazy_Coder 評(píng)論0 收藏0
  • 】Redux 還是 Mobx,讓我來(lái)解決你的困惑!

    摘要:我現(xiàn)在寫的這些是為了解決和這兩個(gè)狀態(tài)管理庫(kù)之間的困惑。這甚至是危險(xiǎn)的,因?yàn)檫@部分人將無(wú)法體驗(yàn)和這些庫(kù)所要解決的問(wèn)題。這肯定是要第一時(shí)間解決的問(wèn)題。函數(shù)式編程是不斷上升的范式,但對(duì)于大部分開發(fā)者來(lái)說(shuō)是新奇的。規(guī)模持續(xù)增長(zhǎng)的應(yīng) 原文地址:Redux or MobX: An attempt to dissolve the Confusion 原文作者:rwieruch 我在去年大量的使用...

    txgcwm 評(píng)論0 收藏0
  • 】React及React Fiber基本的設(shè)計(jì)理念

    摘要:基礎(chǔ)的理論概念這篇文章是我的一次嘗試,希望能夠形式化的介紹關(guān)于本身的一些理念模型。我對(duì)于此實(shí)際的理念模型是在每次的更新過(guò)程中返回下一個(gè)階段的狀態(tài)。的目標(biāo)是提升對(duì)在動(dòng)畫,布局以及手勢(shì)方面的友好度。我已經(jīng)邀請(qǐng)了團(tuán)隊(duì)的成員來(lái)對(duì)本文檔的準(zhǔn)確性進(jìn)行。 前言 本文主要是對(duì)收集到的一些官方或者其他平臺(tái)的文章進(jìn)行翻譯,中間可能穿插一些個(gè)人的理解,如有錯(cuò)誤疏漏之處,還望批評(píng)指正。筆者并未研究過(guò)源碼,只是...

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

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

0條評(píng)論

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