React實(shí)時(shí)預(yù)覽react-live源碼解析
引言
react-live
是一個(gè) react
的實(shí)時(shí)編輯器,可直接編輯 react
代碼,并實(shí)時(shí)預(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
:實(shí)時(shí)編輯環(huán)境的Provider
,Context.Provider
LiveEditor
:實(shí)時(shí)編輯上下文的編輯器LiveError
:實(shí)時(shí)編輯上下文的報(bào)錯(cuò)LivePreview
:實(shí)時(shí)編輯上下文的預(yù)覽LiveContext
:實(shí)時(shí)編輯的Context
withLive
:實(shí)時(shí)編輯上下文的HOC
文件結(jié)構(gòu)和組件拆分一目了然。
Provider
先看下 Provider
,它提供了以下內(nèi)容:
element
:實(shí)時(shí)編輯輸出的元素error
:當(dāng)前的報(bào)錯(cuò)信息code
:當(dāng)前編輯的代碼language
:代碼語言theme
:代碼編輯器主題disabled
:是否禁用onError
:報(bào)錯(cuò)的回調(diào)onChange
:代碼編輯時(shí)的回調(diào)
Provider
用來收集代碼變更,然后通過 transpileAsync
將代碼編譯生成組件實(shí)例:
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
進(jìn)行渲染,邏輯與非 noInline
模式下類似。
generateElement
實(shí)時(shí)預(yù)覽的核心部分就在這里了,它會將代碼先進(jìn)行編譯,然后執(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
能夠支持下述語法直接渲染:
直接寫一個(gè)匿名函數(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í)成本,如果寫多個(gè)函數(shù),多個(gè)組件,嵌套等情況下會讓人覺得語法很奇怪。
transform
就是將代碼通過 sucrase
進(jìn)行轉(zhuǎn)譯,處理 jsx
、class
這些語法,可以理解為通過 babel
轉(zhuǎn)譯。
早期的 react-live
通過 buble
進(jìn)行轉(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ù)進(jìn)行注入。如果對 new Function
不理解的可以看我之前一篇關(guān)于 JS
沙箱的文章。
errorBoundary
則是一個(gè)簡單的 HOC
,用來捕獲生成的組件運(yùn)行時(shí)的錯(cuò)誤信息,通過 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(shí)預(yù)覽的核心代碼了。下面再看下其它幾個(gè)組件,都比較簡單。
其他組件
LivePreview
會接受 Provider
中的 Element
,將其渲染。
LiveError
接受 Provider
中的 error
進(jìn)行渲染。
LiveEditor
則是接收 Provider
的 code
、language
、theme
、disabled
、onChange
,提供編輯功能。
它的編輯器則是通過 useEditable
編輯,Prism
進(jìn)行代碼高亮。
總結(jié)
上述便是 react-live
的核心代碼,內(nèi)容并不多,通過 sucrase
實(shí)時(shí)編譯代碼,然后通過 new Function
構(gòu)造函數(shù)注入 scope
來生成 element
實(shí)現(xiàn)實(shí)時(shí)預(yù)覽,設(shè)計(jì)上通過拆離 Editor
、Error
、Preview
三部分,可以讓使用者自由組合組件的位置、樣式。
以上就是React實(shí)時(shí)預(yù)覽react-live源碼解析的詳細(xì)內(nèi)容,更多關(guān)于react live實(shí)時(shí)預(yù)覽的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
ReactNative踩坑之配置調(diào)試端口的解決方法
本篇文章主要介紹了ReactNative踩坑之配置調(diào)試端口的解決方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-07-07React實(shí)現(xiàn)倒計(jì)時(shí)功能組件
這篇文章主要為大家詳細(xì)介紹了如何通過React實(shí)現(xiàn)一個(gè)倒計(jì)時(shí)功能組件,文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價(jià)值,感興趣的小伙伴可以了解下2023-09-09再次談?wù)揜eact.js實(shí)現(xiàn)原生js拖拽效果引起的一系列問題
React 起源于 Facebook 的內(nèi)部項(xiàng)目,因?yàn)樵摴緦κ袌錾纤?JavaScript MVC 框架,都不滿意,就決定自己寫一套,用來架設(shè) Instagram 的網(wǎng)站.本文給大家介紹React.js實(shí)現(xiàn)原生js拖拽效果,需要的朋友一起學(xué)習(xí)吧2016-04-04react-native-fs實(shí)現(xiàn)文件下載、文本存儲的示例代碼
本篇文章主要介紹了react-native-fs實(shí)現(xiàn)文件下載、文本存儲的示例代碼,具有一定的參考價(jià)值,有興趣的可以了解下2017-09-09React獲取Java后臺文件流并下載Excel文件流程解析
這篇文章主要介紹了React獲取Java后臺文件流下載Excel文件,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-06-06