React 遠(yuǎn)程動態(tài)組件實(shí)踐示例詳解
背景
想象有這樣一個場景:A 團(tuán)隊(duì)開發(fā)了一套組件庫,B 和 C 團(tuán)隊(duì)都在各自的業(yè)務(wù)項(xiàng)目中使用了該組件庫。現(xiàn)在 A 團(tuán)隊(duì)需要對某個組件進(jìn)行更新(比如修改顏色),按照以往的做法,A 團(tuán)隊(duì)需要先發(fā)布一個新的版本,然后其他兩個團(tuán)隊(duì)各自更新業(yè)務(wù)項(xiàng)目中所依賴的組件庫的版本后發(fā)布上線。
有沒有更快速的方法呢?比如能否做到只更新組件庫,其他依賴它的項(xiàng)目可以自動獲取到其最新的版本,即實(shí)現(xiàn)遠(yuǎn)程動態(tài)組件。答案是有的,Webpack 5 新增的 Module Federation 就可以實(shí)現(xiàn)這個需求,但是今天我們要討論的是另外一種方法。
遠(yuǎn)程動態(tài)組件實(shí)現(xiàn)
遠(yuǎn)程動態(tài)組件庫
遠(yuǎn)程動態(tài)組件庫項(xiàng)目結(jié)構(gòu)如下所示:
.
├── babel.config.js
├── package.json
├── rollup.config.js
└── src
├── Button.js
├── Text.js
我們簡單實(shí)現(xiàn)了兩個組件 Button 和 Text:
import React from 'react'
export default ({children}) => {
return <button style={{color: 'blue'}}>{children}</button>
}
import React from 'react'
export default ({children}) => {
return <span style={{color: 'blue'}}>{children}</span>
}
我們使用 rollup 對其進(jìn)行打包,之所以用 rollup 是因?yàn)槠浯虬鰜淼拇a非常簡潔,方便我們查看,rollup 配置為:
import babel from 'rollup-plugin-babel'
import fs from 'fs'
const components = fs.readdirSync('./src')
export default components.map((filename) => {
return {
input: `./src/${filename}`,
output: {
file: `dist/${filename}`,
format: 'cjs',
},
plugins: [babel()],
}
})
打包后的結(jié)果如下所示:
. ├── dist │ └── Button.js │ └── Text.js
其中 Button.js 如下所示:
'use strict'
var React = require('react')
function _interopDefaultLegacy(e) {
return e && typeof e === 'object' && 'default' in e ? e : {default: e}
}
var React__default = /*#__PURE__*/ _interopDefaultLegacy(React)
var Button = function (_ref) {
var children = _ref.children
return /*#__PURE__*/ React__default['default'].createElement(
'button',
{
style: {
color: 'blue',
},
},
children
)
}
module.exports = Button
然后我們使用 http-server 在 dist 目錄下開啟一個靜態(tài)文件服務(wù),則可以通過 http://localhost:8080/Button.js 獲取到打包后的代碼。
遠(yuǎn)程組件庫介紹完畢,接下來介紹業(yè)務(wù)項(xiàng)目中如何使用。
接入遠(yuǎn)程組件庫
我們使用 create-react-app 創(chuàng)建一個 React 應(yīng)用,并新增一個 DynamicComponent 組件:
const DynamicComponent = ({name, children, ...props}) => {
const Component = useMemo(() => {
return React.lazy(async () => fetchComponent(name))
}, [name])
return (
<Suspense
fallback={
<div style={{alignItems: 'center', justifyContent: 'center', flex: 1}}>
<span style={{fontSize: 50}}>Loading...</span>
</div>
}>
<Component {...props}>{children}</Component>
</Suspense>
)
}
export default React.memo(DynamicComponent)
這里使用到了 React 中的 Suspense 組件和 React.lazy 方法,關(guān)于他們的用法這里不做過多解釋,整個 DynamicComponent 組件的含義是遠(yuǎn)程加載目標(biāo)組件,這個過程該組件會渲染傳入 Suspense 參數(shù) fallback 之中的內(nèi)容,最后會使用加載成功的組件進(jìn)行替換。接下來看看 fetchComponent 是如何實(shí)現(xiàn)的:
const fetchComponent = async (name) => {
const text = await fetch(
`http://127.0.0.1:8080/${name}.js?ts=${Date.now()}`
).then((a) => {
if (!a.ok) {
throw new Error('Network response was not ok')
}
return a.text()
})
const module = getParsedModule(text, name)
return {default: module.exports}
}
該方法會發(fā)起網(wǎng)絡(luò)請求得到組件的代碼,并交給 getParsedModule 去解析,最后得到模塊返回。我們來看一下 getParsedModule 是怎么實(shí)現(xiàn)的:
const packages = {
react: React,
}
const getParsedModule = (code) => {
let module = {
exports: {},
}
const require = (name) => {
return packages[name]
}
Function('require, exports, module', code)(require, module.exports, module)
return module
}
這里使用 Function 來運(yùn)行傳入的代碼,因?yàn)榇虬h(yuǎn)程組件的時候并沒有將 react 庫打包進(jìn)去,所以這里需要實(shí)現(xiàn) require 這個方法。
我們結(jié)合之前打包得到的 Button.js 來看這段代碼,它其實(shí)同下面這個代碼是等價(jià)的:
const packages = {
react: React,
}
const getParsedModule = (code, moduleName) => {
let module = {
exports: {},
}
const require = (name) => {
return packages[name]
}
;((require, exports, module) => {
'use strict'
var React = require('react')
function _interopDefaultLegacy(e) {
return e && typeof e === 'object' && 'default' in e ? e : {default: e}
}
var React__default = /*#__PURE__*/ _interopDefaultLegacy(React)
var Button = function (_ref) {
var children = _ref.children
return /*#__PURE__*/ React__default['default'].createElement(
'button',
{
style: {
color: 'blue',
},
},
children
)
}
module.exports = Button
})(require, module.exports, module)
return module
}
最后我們可以按照如下方式來使用 DynamicComponent 組件:
import DynamicComponent from './DynamicComponent'
function App() {
return (
<div>
<DynamicComponent name='Button'>Click Me</DynamicComponent>
<DynamicComponent name='Text'>Remote Component</DynamicComponent>
</div>
)
}
export default App
現(xiàn)在我們嘗試修改遠(yuǎn)程動態(tài)組件庫中的組件,重新打包后就可以馬上看到修改后的效果了。
總結(jié)
本文介紹了一種實(shí)現(xiàn)遠(yuǎn)程動態(tài)組件的方式,不過比較簡陋,事實(shí)上我們還有很多優(yōu)化的空間。比如按照現(xiàn)在的實(shí)現(xiàn)方式,如果頁面上面使用了兩個 Button,會發(fā)起兩次請求,這顯然不合理。針對這個問題,我們可以通過提前加載以及模塊緩存的方式來解決。
以上就是React 遠(yuǎn)程動態(tài)組件實(shí)踐示例詳解的詳細(xì)內(nèi)容,更多關(guān)于React 遠(yuǎn)程動態(tài)組件的資料請關(guān)注腳本之家其它相關(guān)文章!
- 解決React報(bào)錯Expected an assignment or function call and instead saw an expression
- React報(bào)錯信息之Expected?an?assignment?or?function?call?and?instead?saw?an?expression
- VueJs中的shallowRef與shallowReactive函數(shù)使用比較
- Project?Reactor?響應(yīng)式范式編程
- react?定位組件源碼解析
- 通過示例源碼解讀React首次渲染流程
- react?express實(shí)現(xiàn)webssh?demo解析
相關(guān)文章
一文詳解ReactNative狀態(tài)管理rematch使用
這篇文章主要為大家介紹了ReactNative狀態(tài)管理rematch使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03
React使用高階組件與Hooks實(shí)現(xiàn)權(quán)限攔截教程詳細(xì)分析
高階組件就是接受一個組件作為參數(shù)并返回一個新組件(功能增強(qiáng)的組件)的函數(shù)。這里需要注意高階組件是一個函數(shù),并不是組件,這一點(diǎn)一定要注意,本文給大家分享React高階組件使用小結(jié),一起看看吧2023-01-01
詳解React-Native全球化多語言切換工具庫react-native-i18n
這篇文章主要介紹了詳解React-Native全球化語言切換工具庫react-native-i18n,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-11-11
react的嚴(yán)格模式和解決react useEffect執(zhí)行兩次問題
文章總結(jié):本文詳細(xì)探討了React中useEffect執(zhí)行兩次的問題,主要?dú)w因于React的嚴(yán)格模式,嚴(yán)格模式在開發(fā)模式下會故意重復(fù)調(diào)用一些生命周期方法,以幫助開發(fā)者發(fā)現(xiàn)潛在的問題,包括不安全的生命周期、過時的ref API、廢棄的findDOMNode方法、意外的副作用等2025-01-01
Ant Design與Ant Design pro入門使用教程
Ant Design 是一個服務(wù)于企業(yè)級產(chǎn)品的設(shè)計(jì)體系,組件庫是它的 React 實(shí)現(xiàn),antd 被發(fā)布為一個 npm 包方便開發(fā)者安裝并使用,這篇文章主要介紹了Ant Design與Ant Design pro入門,需要的朋友可以參考下2023-12-12
react?umi?刷新或關(guān)閉瀏覽器時清除localStorage方式
這篇文章主要介紹了react?umi?刷新或關(guān)閉瀏覽器時清除localStorage方式,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-10-10
詳解React中父子組件數(shù)據(jù)傳遞和修改的方式及原理
這篇文章主要為大家詳細(xì)介紹了React中父子組件數(shù)據(jù)傳遞和修改的方式及原理,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-04-04

