经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » JS/JS库/框架 » React » 查看文章
React实时预览react-live源码解析
来源:jb51  时间:2022/8/15 15:40:54  对本文有异议

引言

react-live 是一个 react 的实时编辑器,可直接编辑 react 代码,并实时预览。可以看下官方的预览图:

本文针对的源码版本

  1. src
  2. ├── components
  3. ├── Editor
  4. └── index.js
  5. └── Live
  6. ├── LiveContext.js
  7. ├── LiveEditor.js
  8. ├── LiveError.js
  9. ├── LivePreview.js
  10. ├── LiveProvider.js
  11. └── LiveProvider.test.js
  12. ├── constants
  13. └── theme.js
  14. ├── hoc
  15. └── withLive.js
  16. ├── index.js
  17. └── utils
  18. ├── test
  19. ├── errorBoundary.test.js
  20. ├── renderer.js
  21. └── transpile.test.js
  22. └── transpile
  23. ├── errorBoundary.js
  24. ├── evalCode.js
  25. ├── index.js
  26. └── transform.js

源码解读

输入内容

先看下导出内容,包括:

  • Editor:编辑器
  • LiveProvider:实时编辑环境的 ProviderContext.Provider
  • LiveEditor:实时编辑上下文的编辑器
  • LiveError:实时编辑上下文的报错
  • LivePreview:实时编辑上下文的预览
  • LiveContext:实时编辑的 Context
  • withLive:实时编辑上下文的 HOC

文件结构和组件拆分一目了然。

Provider

先看下 Provider,它提供了以下内容:

  • element:实时编辑输出的元素
  • error:当前的报错信息
  • code:当前编辑的代码
  • language:代码语言
  • theme:代码编辑器主题
  • disabled:是否禁用
  • onError:报错的回调
  • onChange:代码编辑时的回调

Provider 用来收集代码变更,然后通过 transpileAsync 将代码编译生成组件实例:

  1. function transpileAsync(newCode) {
  2. const errorCallback = error => {
  3. setState({ error: error.toString(), element: undefined });
  4. };
  5. try {
  6. const transformResult = transformCode ? transformCode(newCode) : newCode;
  7. return Promise.resolve(transformResult)
  8. .then(transformedCode => {
  9. const renderElement = element => setState({ error: undefined, element });
  10. // Transpilation arguments
  11. const input = {
  12. code: transformedCode,
  13. scope
  14. };
  15. if (noInline) {
  16. setState({ error: undefined, element: null }); // Reset output for async (no inline) evaluation
  17. renderElementAsync(input, renderElement, errorCallback);
  18. } else {
  19. renderElement(generateElement(input, errorCallback));
  20. }
  21. })
  22. .catch(errorCallback);
  23. } catch (e) {
  24. errorCallback(e);
  25. return Promise.resolve();
  26. }
  27. }

renderElementAsync 可以先无视,主要是用于 noInline 模式下调用 render 进行渲染,逻辑与非 noInline 模式下类似。

generateElement

实时预览的核心部分就在这里了,它会将代码先进行编译,然后执行代码,取得返回值。

  1. const generateElement = ({ code = '', scope = {} }, errorCallback) => {
  2. // NOTE: Remove trailing semicolon to get an actual expression.
  3. const codeTrimmed = code.trim().replace(/;$/, '');
  4. // NOTE: Workaround for classes and arrow functions.
  5. const transformed = transform(`return (${codeTrimmed})`).trim();
  6. return errorBoundary(evalCode(transformed, { React, ...scope }), errorCallback);
  7. };

代码如上,它会先去掉头尾空白,然后去掉结尾的分号,这一步是为了下一步的 return 拼接能够正常返回。通过 return 拼接让 react-live 能够支持下述语法直接渲染:

直接写一个匿名函数:

  1. () => <h3>So functional. Much wow!</h3>;

直接写 jsx

  1. <h3>Hello World!</h3>

class 组件:

  1. class Comp extends React.Component {
  2. render() {
  3. return <center>component</center>;
  4. }
  5. }

不过也导致了一定的学习成本,如果写多个函数,多个组件,嵌套等情况下会让人觉得语法很奇怪。

transform 就是将代码通过 sucrase 进行转译,处理 jsxclass 这些语法,可以理解为通过 babel 转译。

早期的 react-live 通过 buble 进行转译,能够支持 jsx 注释,现在由于 sucrase 不支持 jsx 注释,所以新版无法使用 jsx 注释来控制 jsx 渲染引擎。

  1. /** @jsx mdx */
  2. // 新版上述注释会失效

随后将转译的代码通过 evalCode 转换为 React element,此处会将 scopeReact 传入 evalCode 中。

  1. const evalCode = (code, scope) => {
  2. const scopeKeys = Object.keys(scope);
  3. const scopeValues = scopeKeys.map(key => scope[key]);
  4. return new Function(...scopeKeys, code)(...scopeValues);
  5. };

evalCode 中使用 new Function 来构造函数,scope 就是在这里作为参数进行注入。如果对 new Function 不理解的可以看我之前一篇关于 JS 沙箱的文章。

errorBoundary 则是一个简单的 HOC,用来捕获生成的组件运行时的错误信息,通过 errorCallback 抛出。

  1. const errorBoundary = (Element, errorCallback) => {
  2. return class ErrorBoundary extends Component {
  3. componentDidCatch(error) {
  4. errorCallback(error);
  5. }
  6. render() {
  7. return typeof Element === 'function' ? <Element /> : React.isValidElement(Element) ? Element : null;
  8. }
  9. };
  10. };

上面就是 react-live 能够实时预览的核心代码了。下面再看下其它几个组件,都比较简单。

其他组件

LivePreview 会接受 Provider 中的 Element,将其渲染。

LiveError 接受 Provider 中的 error 进行渲染。

LiveEditor 则是接收 ProvidercodelanguagethemedisabledonChange,提供编辑功能。

它的编辑器则是通过 useEditable 编辑,Prism 进行代码高亮。

总结

上述便是 react-live 的核心代码,内容并不多,通过 sucrase 实时编译代码,然后通过 new Function 构造函数注入 scope 来生成 element 实现实时预览,设计上通过拆离 EditorErrorPreview 三部分,可以让使用者自由组合组件的位置、样式。

以上就是React实时预览react-live源码解析的详细内容,更多关于react live实时预览的资料请关注w3xue其它相关文章!

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号