React實時預(yù)覽react-live源碼解析
引言
react-live 是一個 react 的實時編輯器,可直接編輯 react 代碼,并實時預(yù)覽。可以看下官方的預(yù)覽圖:

src
├── components
│ ├── Editor
│ │ └── index.js
│ └── Live
│ ├── LiveContext.js
│ ├── LiveEditor.js
│ ├── LiveError.js
│ ├── LivePreview.js
│ ├── LiveProvider.js
│ └── LiveProvider.test.js
├── constants
│ └── theme.js
├── hoc
│ └── withLive.js
├── index.js
└── utils
├── test
│ ├── errorBoundary.test.js
│ ├── renderer.js
│ └── transpile.test.js
└── transpile
├── errorBoundary.js
├── evalCode.js
├── index.js
└── transform.js
源碼解讀
輸入內(nèi)容
先看下導(dǎo)出內(nèi)容,包括:
Editor:編輯器LiveProvider:實時編輯環(huán)境的Provider,Context.ProviderLiveEditor:實時編輯上下文的編輯器LiveError:實時編輯上下文的報錯LivePreview:實時編輯上下文的預(yù)覽LiveContext:實時編輯的ContextwithLive:實時編輯上下文的HOC
文件結(jié)構(gòu)和組件拆分一目了然。
Provider
先看下 Provider,它提供了以下內(nèi)容:
element:實時編輯輸出的元素error:當(dāng)前的報錯信息code:當(dāng)前編輯的代碼language:代碼語言theme:代碼編輯器主題disabled:是否禁用onError:報錯的回調(diào)onChange:代碼編輯時的回調(diào)
Provider 用來收集代碼變更,然后通過 transpileAsync 將代碼編譯生成組件實例:
function transpileAsync(newCode) {
const errorCallback = error => {
setState({ error: error.toString(), element: undefined });
};
try {
const transformResult = transformCode ? transformCode(newCode) : newCode;
return Promise.resolve(transformResult)
.then(transformedCode => {
const renderElement = element => setState({ error: undefined, element });
// Transpilation arguments
const input = {
code: transformedCode,
scope
};
if (noInline) {
setState({ error: undefined, element: null }); // Reset output for async (no inline) evaluation
renderElementAsync(input, renderElement, errorCallback);
} else {
renderElement(generateElement(input, errorCallback));
}
})
.catch(errorCallback);
} catch (e) {
errorCallback(e);
return Promise.resolve();
}
}
renderElementAsync 可以先無視,主要是用于 noInline 模式下調(diào)用 render 進行渲染,邏輯與非 noInline 模式下類似。
generateElement
實時預(yù)覽的核心部分就在這里了,它會將代碼先進行編譯,然后執(zhí)行代碼,取得返回值。
const generateElement = ({ code = '', scope = {} }, errorCallback) => {
// NOTE: Remove trailing semicolon to get an actual expression.
const codeTrimmed = code.trim().replace(/;$/, '');
// NOTE: Workaround for classes and arrow functions.
const transformed = transform(`return (${codeTrimmed})`).trim();
return errorBoundary(evalCode(transformed, { React, ...scope }), errorCallback);
};
代碼如上,它會先去掉頭尾空白,然后去掉結(jié)尾的分號,這一步是為了下一步的 return 拼接能夠正常返回。通過 return 拼接讓 react-live 能夠支持下述語法直接渲染:
直接寫一個匿名函數(shù):
() => <h3>So functional. Much wow!</h3>;
直接寫 jsx:
<h3>Hello World!</h3>
單 class 組件:
class Comp extends React.Component {
render() {
return <center>component</center>;
}
}
不過也導(dǎo)致了一定的學(xué)習(xí)成本,如果寫多個函數(shù),多個組件,嵌套等情況下會讓人覺得語法很奇怪。
transform 就是將代碼通過 sucrase 進行轉(zhuǎn)譯,處理 jsx、class 這些語法,可以理解為通過 babel 轉(zhuǎn)譯。
早期的 react-live 通過 buble 進行轉(zhuǎn)譯,能夠支持 jsx 注釋,現(xiàn)在由于 sucrase 不支持 jsx 注釋,所以新版無法使用 jsx 注釋來控制 jsx 渲染引擎。
/** @jsx mdx */ // 新版上述注釋會失效
隨后將轉(zhuǎn)譯的代碼通過 evalCode 轉(zhuǎn)換為 React element,此處會將 scope 和 React 傳入 evalCode 中。
const evalCode = (code, scope) => {
const scopeKeys = Object.keys(scope);
const scopeValues = scopeKeys.map(key => scope[key]);
return new Function(...scopeKeys, code)(...scopeValues);
};
evalCode 中使用 new Function 來構(gòu)造函數(shù),scope 就是在這里作為參數(shù)進行注入。如果對 new Function 不理解的可以看我之前一篇關(guān)于 JS 沙箱的文章。
errorBoundary 則是一個簡單的 HOC,用來捕獲生成的組件運行時的錯誤信息,通過 errorCallback 拋出。
const errorBoundary = (Element, errorCallback) => {
return class ErrorBoundary extends Component {
componentDidCatch(error) {
errorCallback(error);
}
render() {
return typeof Element === 'function' ? <Element /> : React.isValidElement(Element) ? Element : null;
}
};
};
上面就是 react-live 能夠?qū)崟r預(yù)覽的核心代碼了。下面再看下其它幾個組件,都比較簡單。
其他組件
LivePreview 會接受 Provider 中的 Element,將其渲染。
LiveError 接受 Provider 中的 error 進行渲染。
LiveEditor 則是接收 Provider 的 code、language、theme、disabled、onChange,提供編輯功能。
它的編輯器則是通過 useEditable 編輯,Prism 進行代碼高亮。
總結(jié)
上述便是 react-live 的核心代碼,內(nèi)容并不多,通過 sucrase 實時編譯代碼,然后通過 new Function 構(gòu)造函數(shù)注入 scope 來生成 element 實現(xiàn)實時預(yù)覽,設(shè)計上通過拆離 Editor、Error、Preview 三部分,可以讓使用者自由組合組件的位置、樣式。
以上就是React實時預(yù)覽react-live源碼解析的詳細(xì)內(nèi)容,更多關(guān)于react live實時預(yù)覽的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
React 項目中動態(tài)設(shè)置環(huán)境變量
本文主要介紹了React 項目中動態(tài)設(shè)置環(huán)境變量,本文將介紹兩種常用的方法,使用 dotenv 庫和通過命令行參數(shù)傳遞環(huán)境變量,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-04-04
React使用Hooks從服務(wù)端獲取數(shù)據(jù)的完整指南
本文將從基礎(chǔ)到高級用法,詳細(xì)介紹如何在 React 項目中優(yōu)雅地使用 Hooks 進行服務(wù)端數(shù)據(jù)獲取,涵蓋錯誤處理、加載狀態(tài)、性能優(yōu)化等核心場景,并提供可直接復(fù)用的代碼模板,需要的朋友可以參考下2025-03-03
antd?table動態(tài)修改表格高度的實現(xiàn)
本文主要介紹了antd?table動態(tài)修改表格高度的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-07-07
在Create React App中啟用Sass和Less的方法示例
這篇文章主要介紹了在Create React App中啟用Sass和Less的方法示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-01-01
React中的useMemo 和 useEffect 執(zhí)行順序
在 React 組件的渲染過程中,useMemo 和 useEffect 的執(zhí)行順序是不同的,本文給大家介紹React中的useMemo 和 useEffect 哪個先執(zhí)行,感興趣的朋友一起看看吧2025-01-01

