網站首頁 編程語言 正文
引言
react-live
是一個 react
的實時編輯器,可直接編輯 react
代碼,并實時預覽。可以看下官方的預覽圖:
本文針對的源碼版本
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
源碼解讀
輸入內容
先看下導出內容,包括:
-
Editor
:編輯器 -
LiveProvider
:實時編輯環境的Provider
,Context.Provider
-
LiveEditor
:實時編輯上下文的編輯器 -
LiveError
:實時編輯上下文的報錯 -
LivePreview
:實時編輯上下文的預覽 -
LiveContext
:實時編輯的Context
-
withLive
:實時編輯上下文的HOC
文件結構和組件拆分一目了然。
Provider
先看下 Provider
,它提供了以下內容:
-
element
:實時編輯輸出的元素 -
error
:當前的報錯信息 -
code
:當前編輯的代碼 -
language
:代碼語言 -
theme
:代碼編輯器主題 -
disabled
:是否禁用 -
onError
:報錯的回調 -
onChange
:代碼編輯時的回調
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
模式下調用 render
進行渲染,邏輯與非 noInline
模式下類似。
generateElement
實時預覽的核心部分就在這里了,它會將代碼先進行編譯,然后執行代碼,取得返回值。
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); };
代碼如上,它會先去掉頭尾空白,然后去掉結尾的分號,這一步是為了下一步的 return
拼接能夠正常返回。通過 return
拼接讓 react-live
能夠支持下述語法直接渲染:
直接寫一個匿名函數:
() => <h3>So functional. Much wow!</h3>;
直接寫 jsx
:
<h3>Hello World!</h3>
單 class
組件:
class Comp extends React.Component { render() { return <center>component</center>; } }
不過也導致了一定的學習成本,如果寫多個函數,多個組件,嵌套等情況下會讓人覺得語法很奇怪。
transform
就是將代碼通過 sucrase
進行轉譯,處理 jsx
、class
這些語法,可以理解為通過 babel
轉譯。
早期的 react-live
通過 buble
進行轉譯,能夠支持 jsx
注釋,現在由于 sucrase
不支持 jsx
注釋,所以新版無法使用 jsx
注釋來控制 jsx
渲染引擎。
/** @jsx mdx */ // 新版上述注釋會失效
隨后將轉譯的代碼通過 evalCode
轉換為 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
來構造函數,scope
就是在這里作為參數進行注入。如果對 new Function
不理解的可以看我之前一篇關于 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
能夠實時預覽的核心代碼了。下面再看下其它幾個組件,都比較簡單。
其他組件
LivePreview
會接受 Provider
中的 Element
,將其渲染。
LiveError
接受 Provider
中的 error
進行渲染。
LiveEditor
則是接收 Provider
的 code
、language
、theme
、disabled
、onChange
,提供編輯功能。
它的編輯器則是通過 useEditable
編輯,Prism
進行代碼高亮。
總結
上述便是 react-live
的核心代碼,內容并不多,通過 sucrase
實時編譯代碼,然后通過 new Function
構造函數注入 scope
來生成 element
實現實時預覽,設計上通過拆離 Editor
、Error
、Preview
三部分,可以讓使用者自由組合組件的位置、樣式。
原文鏈接:https://juejin.cn/post/7131221062569689125
相關推薦
- 2022-11-27 深入了解Linux的文件權限_linux shell
- 2023-11-16 python list列表拼接
- 2022-06-02 Nginx虛擬主機的配置步驟過程全解_nginx
- 2023-10-16 向前端傳遞Long類型數據時發生精度缺失解決辦法
- 2022-05-14 實現AJAX異步調用和局部刷新的基本步驟_AJAX相關
- 2023-01-15 PyQt5+QtChart實現繪制曲線圖_python
- 2022-07-14 如何修改numpy?array的數據類型_python
- 2022-03-30 ASP.NET?Core使用JWT自定義角色并實現策略授權需要的接口_實用技巧
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支