摘要:要實施這個方案,最大問題就是接口約定。討論地址是精讀做了什么如果你想?yún)⑴c討論,請點擊這里,每周都有新的主題,周末或周一發(fā)布。前端精讀幫你篩選靠譜的內(nèi)容。
1 引言
setState 是 React 框架最常用的命令,它是用來更新狀態(tài)的,這也是 React 框架劃時代的功能。
但是 setState 函數(shù)是 react 包導(dǎo)出的,他們又是如何與 react-dom react-native react-art 這些包結(jié)合的呢?
通過 how-does-setstate-know-what-to-do 這篇文章,可以解開這個秘密。
2 概述setState 函數(shù)是在 React.Component 組件中調(diào)用的,所以最自然的聯(lián)想是,更新 DOM 的邏輯在 react 包中實現(xiàn)。
但是 react 卻可以和 react-dom react-native react-art 這些包打配合,甚至與 react-dom/server 配合在服務(wù)端運行,那可以肯定 react 包中不含有 DOM 更新邏輯。
所以可以推斷,平臺相關(guān)的 UI 更新邏輯分布在平臺相關(guān)的包里,react 包只做了代理。
React 引擎不在 react 包里從 react 0.14 版本之后,引擎代碼就從 react 包中抽離了,react 包僅僅做通用接口抽象。
也就是說,react 包定義了標(biāo)準(zhǔn)的狀態(tài)驅(qū)動模型的 API,而 react-dom react-native react-art 這些包是在各自平臺的具體實現(xiàn)。
各平臺具體的渲染引擎實現(xiàn)被稱為 reconciler,通過這個鏈接可以看到 react-dom react-native react-art 這三個包的 reconciler 實現(xiàn)。
這說明了 react 包僅告訴你 React 擁有哪些語法,而并不關(guān)心如何實現(xiàn)他們,所以我們需要結(jié)合 react 包與 react-xxx 一起使用。
對于 context,react 包僅僅會做如下定義:
// A bit simplified 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; }
具體用到時,由 react-dom 和 react-native 決定用何種方式實現(xiàn) MyContext.Provider 這個 API。
這也說明了,如果你不同步升級 react 與 react-dom 版本的話,就可能碰到這樣的報錯:fail saying these types are invalid,原因是 API 定義與實現(xiàn)不匹配。
setState 怎么調(diào)用平臺實現(xiàn)每個平臺對 UI 更新邏輯的實現(xiàn),會封裝在 updater 函數(shù)里,所以不同平臺代碼會為組件添加各自的 updater 實現(xiàn):
// Inside React DOM const inst = new YourComponent(); inst.props = props; inst.updater = ReactDOMUpdater; // Inside React DOM Server const inst = new YourComponent(); inst.props = props; inst.updater = ReactDOMServerUpdater; // Inside React Native const inst = new YourComponent(); inst.props = props; inst.updater = ReactNativeUpdater;
不同于 props, updater 無法被直接調(diào)用,因為這個 API 是由 react 引擎在 setState 時調(diào)用的:
// A bit simplified setState(partialState, callback) { // Use the `updater` field to talk back to the renderer! this.updater.enqueueSetState(this, partialState, callback); }
關(guān)系可以這么描述:react -> setState -> updater <- react-dom 等。
HooksHooks 的原理與 setState 類似,當(dāng)調(diào)用 useState 或 useEffect 時,其內(nèi)部調(diào)用如下:
// 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); } // ... };
ReactDOM 提供了 __currentDispatcher(簡化的說法):
// In React DOM const prevDispatcher = React.__currentDispatcher; React.__currentDispatcher = ReactDOMDispatcher; let result; try { result = YourComponent(props); } finally { // Restore it back React.__currentDispatcher = prevDispatcher; }
可以看到,Hooks 的原理與 setState 基本一致,但需要注意 react 與 react-dom 之間傳遞了 dispatch,雖然你看不到。但這個 dispatch 必須對應(yīng)到唯一的 React 實例,這就是為什么 Hooks 不允許同時加載多個 React 實例的原因。
和 updater 一樣,dispatch 也可以被各平臺實現(xiàn)重寫,比如 react-debug-hooks 就重寫了 dispatcher。
由于需要同時實現(xiàn) readContext, useCallback, useContext, useEffect, useImperativeMethods, useLayoutEffect, useMemo, useReducer, useRef, useState,工程量比較浩大,建議了解基本架構(gòu)就足夠了,除非你要深入?yún)⑴c React 生態(tài)建設(shè)。
3 精讀與其他 React 分析文章不同,本文并沒有過于刨根問題的上來就剖析 reconciler 實現(xiàn),而是問了一個最基本的疑問:為什么 setState 來自 react 包,但實現(xiàn)卻在 react-dom 里?React 是如何實現(xiàn)這個 magic 的?
通過這個疑問,我們了解了 React 更上層的抽象能力,如何用一個包制定規(guī)范,用 N 包去實現(xiàn)它。
接口的力量在日常編程中,接口也擁有的強大力量,下面舉幾個例子。
UI 組件跨三端的接口由于 RN、Weex、Flux 的某些不足,越來越多的人選擇 “一個思想三端實現(xiàn)” 的方式做跨三端的 UI 組件,這樣既兼顧了性能,又可以照顧到平臺差異性,對不同平臺組件細(xì)節(jié)做定制優(yōu)化。
要實施這個方案,最大問題就是接口約定。一定要保證三套實現(xiàn)遵循同一套 API 接口,業(yè)務(wù)代碼才可以實現(xiàn) “針對任意一個平臺編寫,自動移植到其他平臺”。
比較常用的做法是,通過一套統(tǒng)一的 API 文件約束,固定組件的輸入輸出,不同平臺的組件做平臺具體實現(xiàn)。這個思想和 React 如出一轍。
當(dāng)然 RN 這些框架本身也是同一接口在不同平臺實現(xiàn)的典型,只是做的不夠徹底,JS 與 Native 的通信導(dǎo)致了性能不如源生。通用數(shù)據(jù)查詢服務(wù)
通用數(shù)據(jù)查詢服務(wù)也比較流行,通過磨平各數(shù)據(jù)庫語法,讓用戶通過一套 SQL 查詢各種類型數(shù)據(jù)庫的數(shù)據(jù)。
這個方案中,一套通用的查詢語法就類似 React 定義的 API,執(zhí)行階段會轉(zhuǎn)化為各數(shù)據(jù)庫平臺的 SQL 方言。
小程序融合方案現(xiàn)在這種方案很火。通過基于 template 或者 jsx 的語法,一鍵發(fā)布到各平臺小程序應(yīng)用。
這種方案一定會抽象一套通用語法,甚至幾乎等價與 react 與 react-dom 的關(guān)系:所有符合規(guī)范的語法,轉(zhuǎn)化為各小程序平臺的實現(xiàn)。
4 總結(jié)這種分平臺實現(xiàn)方案與跨平臺方案還是有很大區(qū)別的,像 JAVA 虛擬機本質(zhì)還是一套實現(xiàn)方案。而分平臺的實現(xiàn)可以帶來最原生的性能與體驗,同樣收到的約束也最大,應(yīng)該其 API 應(yīng)該是所有平臺支持的一個子集。
另外,這種方案不僅可以用于 一套規(guī)范,不同平臺的實現(xiàn),甚至可以用在 “同一平臺的實現(xiàn)”。
無論是公司還是開源節(jié)界,都有許多重復(fù)的輪子或者平臺,如果通過技術(shù)委員會約定一套平臺的實現(xiàn)規(guī)范,大家都遵循這個規(guī)范開發(fā)平臺,那未來就比較好做收斂,或者說收斂的第一步都是先統(tǒng)一 API 規(guī)范。
留下一個思考題:還有沒有利用 setState 規(guī)范與實現(xiàn)分離的思想案例?歡迎留下你的答案。
討論地址是:精讀《setState 做了什么》 · Issue #122 · dt-fe/weekly
如果你想?yún)⑴c討論,請點擊這里,每周都有新的主題,周末或周一發(fā)布。前端精讀 - 幫你篩選靠譜的內(nèi)容。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/100759.html
摘要:更容易將組件的與狀態(tài)分離。也就是只提供狀態(tài)處理方法,不會持久化狀態(tài)。大體思路是利用共享一份數(shù)據(jù),作為的數(shù)據(jù)源。精讀帶來的約定函數(shù)必須以命名開頭,因為這樣才方便做檢查,防止用判斷包裹語句。前端精讀幫你篩選靠譜的內(nèi)容。 1 引言 React Hooks 是 React 16.7.0-alpha 版本推出的新特性,想嘗試的同學(xué)安裝此版本即可。 React Hooks 要解決的問題是狀態(tài)共享,...
摘要:今天我們就來解讀一下的源碼。比較有意思,將定時器以方式提供出來,并且提供了方法。實現(xiàn)方式是,在組件內(nèi)部維護(hù)一個定時器,實現(xiàn)了組件更新銷毀時的計時器更新銷毀操作,可以認(rèn)為這種定時器的生命周期綁定了組件的生命周期,不用擔(dān)心銷毀和更新的問題。 1. 引言 React PowerPlug 是利用 render props 進(jìn)行更好狀態(tài)管理的工具庫。 React 項目中,一般一個文件就是一個類,...
摘要:精讀源碼一共行,我們分析一下其精妙的方式。更多討論討論地址是精讀新用法如果你想?yún)⑴c討論,請點擊這里,每周都有新的主題,周末或周一發(fā)布。前端精讀幫你篩選靠譜的內(nèi)容。 1 引言 很高興這一期的話題是由 epitath 的作者 grsabreu 提供的。 前端發(fā)展了 20 多年,隨著發(fā)展中國家越來越多的互聯(lián)網(wǎng)從業(yè)者涌入,現(xiàn)在前端知識玲瑯滿足,概念、庫也越來越多。雖然內(nèi)容越來越多,但作為個體的...
摘要:可以看到,這樣不僅沒有占用組件自己的,也不需要手寫回調(diào)函數(shù)進(jìn)行處理,這些處理都壓縮成了一行。效果通過拿到周期才執(zhí)行的回調(diào)函數(shù)。實現(xiàn)等價于的回調(diào)僅執(zhí)行一次時,因此直接把回調(diào)函數(shù)拋出來即可。 1 引言 上周的 精讀《React Hooks》 已經(jīng)實現(xiàn)了對 React Hooks 的基本認(rèn)知,也許你也看了 React Hooks 基本實現(xiàn)剖析(就是數(shù)組),但理解實現(xiàn)原理就可以用好了嗎?學(xué)的是...
摘要:未來可能成為官方之一。討論地址是精讀組件如果你想?yún)⑴c討論,請點擊這里,每周都有新的主題,周末或周一發(fā)布。前端精讀幫你篩選靠譜的內(nèi)容。 1. 引言 為什么要了解 Function 寫法的組件呢?因為它正在變得越來越重要。 那么 React 中 Function Component 與 Class Component 有何不同? how-are-function-components-di...
閱讀 931·2021-11-08 13:22
閱讀 2856·2021-09-29 09:45
閱讀 2835·2021-09-09 11:52
閱讀 2269·2019-08-30 13:20
閱讀 3751·2019-08-29 13:28
閱讀 1372·2019-08-29 12:32
閱讀 2732·2019-08-29 11:10
閱讀 1653·2019-08-26 13:34