Dva最佳實踐 -- 探索嵌入式React應用
一. 嵌入式
1. 應用場景
作為前端開發,特別是企業級應用的開發,經常會遇到需要把你所開發的web應用嵌入到已經存在的系統中,這種時候如何不影響原系統正常運轉並嵌入成為了一個難題。典型的,在以前如果通過jQuery編寫web 元件的時候,這種嵌入問題並不是特別大的難題,只需要在網頁中正確引入第三方類庫的js,css。正常來說就能跑起來了。但是React的執行機制與以往不同,很多人特別是新手,如果都是通過create-react-app或者dva-cli來構建react專案,很多人可能只會讓專案在當前的開發環境跑起來和打包。特別明顯的就是,我帶過很多新入坑的同學,他們僅僅知道在命令列輸入npm start 或者npm run dev的時候就會能讓react應用掛載到id為root或者app的dom節點上。 如果問他們怎麼將這個應用掛載到別的系統中,如何實現時,肯定就會說在被整合的頁面裡面加一個id為root的div就好了,只要引入打包後的js和css,這個應用就能跑起來。
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(<App />, document.getElementById('root'));
使用久之後會給人一種錯覺:要讓React應用跑起來一定是頁面中已經存在一個id為root的元素,只要正確引入js和css,這個應用就會自動執行。
2. 封裝ReactDOM.render
所以在將React應用嵌入到其他系統的時候,往往忽略了我們其實可以用另一種方式,更好的嵌入。改造上述程式碼。
import React from 'react'; import ReactDOM from 'react-dom'; import App from './App'; (function(){ function ReactApp() { function render(selector) { ReactDOM.render(<App />, document.querySelector(selector)); } this.render = render; } return this.ReactApp = ReactApp; }.call(window)); // 這樣,對於外部呼叫者,即可以以面向物件的形式使用和呼叫這個應用。 var app = new ReactApp(); // 這能讓應用的呼叫者能更靈活的呼叫。 app.start('#root');
上面程式碼中將 react應用的入口檔案index.js 改寫成一個立即執行函式,函式的執行結果是向頂級變數window新增ReactApp屬性,該屬性的值是個ReactApp類。這個類的例項有一個render方法,用於控制 app 渲染的啟動。當我們這麼封裝React應用的入口檔案,是不是就會比往被嵌入的系統固定的增加一個id為 root的元素更靈活。同時可以通過給ReactApp類定義更復雜的建構函式,來給App元件傳遞外部定義的屬性。
二. dva應用的封裝嵌入
與簡單的React應用封裝不同,dva本身已經基於React + Redux + React-Router等經過一輪封裝。所以我們完全可以利用dva豐富的介面,經過封裝後為外部呼叫者提供更多介面應用在更復雜的應用場景。
來看看dva的原始碼
有沒有一種似曾相識的感覺。在我們使用dva方法的時候,返回的是dva-core的例項。先不探究dva-core方法做了什麼事情,在最後dva方法會給這個例項附加上 router方法和start方法分別用於路由註冊和應用啟動。
所以同樣的,我們一樣可以用第一章中使用的方法封裝dva應用,同時得益於dva物件本身封裝的一系列介面,我們甚至可以封裝並丟擲更多強大的介面給外部呼叫者實現更復雜的功能。
如上圖,甚至能給應用呼叫者(被嵌入平臺)提供新增的dispatch和getState介面,雖然這麼做並不安全(僅供參考)。 當然,接下來要做的事情已經涉及到平臺架構設計的問題,根據業務不同自行決定即可。
三. 結語
該篇文章僅提供一種React應用嵌入式開發的實現思路,如果你有更好的解決方案,希望能評論分享。非常感謝