React实时预览react-live源码解析

目录
  • 引言
  • 源码解读
    • 输入内容
    • Provider
    • generateElement
    • 其他组件
  • 总结

引言

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:实时编辑环境的 ProviderContext.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 进行转译,处理 jsxclass 这些语法,可以理解为通过 babel 转译。

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

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

随后将转译的代码通过 evalCode 转换为 React element,此处会将 scopeReact 传入 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 则是接收 ProvidercodelanguagethemedisabledonChange,提供编辑功能。

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

总结

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

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

(0)

相关推荐

  • 使用react-activation实现keepAlive支持返回传参

    目录 介绍 代码 1.安装react-activation 2.给路由增加meta 3.根组件中渲染 4.跳转指定页面的时候才缓存 5.抽离逻辑到自定义hooks 6. 从详情页返回列表页的时候,控制列表页是否刷新,即返回传参 使用: 相关文档 介绍 这个项目是一个商城的后台管理系统,用umi2.0搭建,状态管理使用dva,想要实现类似vue keep-alive的效果. 具体表现为: 从列表页A跳转A的详情页,列表页A缓存 详情页没做任何操作,跳回列表页A,列表页A不刷新,列表页A页码不变 详

  • React-Route6实现keep-alive效果

    目录 一.基于react-route6  useOutlet实现 二.代码呈现 代码分析 isKeepPath useKeepOutlets location element useContext<any>(KeepAliveContext) isKeep Object.entries key hidden matchPath(location.pathname, pathname)} KeepAliveLayout FC keepElements dropByCacheKey other P

  • react-router-dom v6 通过outlet实现keepAlive 功能的实现

    本文主要介绍了react-router-dom v6 通过outlet实现keepAlive 功能的实现,具体如下: keepAlive代码: import React, { useRef, useEffect, useReducer, useMemo, memo } from 'react' import { TransitionGroup, CSSTransition } from 'react-transition-group' import { useLocation } from 'r

  • React实时预览react-live源码解析

    目录 引言 源码解读 输入内容 Provider generateElement 其他组件 总结 引言 react-live 是一个 react 的实时编辑器,可直接编辑 react 代码,并实时预览.可以看下官方的预览图: 本文针对的源码版本 src ├── components │ ├── Editor │ │ └── index.js │ └── Live │ ├── LiveContext.js │ ├── LiveEditor.js │ ├── LiveError.js │ ├── L

  • 基于Jquery制作图片文字排版预览效果附源码下载

    基于jQuery图文排版图片预览特效.这是一款基于jQuery+CSS3实现的鼠标点击图片弹出画廊切换特效. 效果图如下所示,怎么样感兴趣吗,感兴趣的朋友继续往下学习哦. 效果演示    源码下载 html代码: <div id="fullscreen"> <div id="fullscreen-inner"> <div id="fullscreen-inner-left" class="fullscree

  • jsoneditor二次封装实时预览json编辑器组件react版

    目录 前言 设计思路 正文 jsoneditor的使用 结合react进行二次封装 前言 做为一名前端开发人员,掌握vue/react/angular等框架已经是必不可少的技能了,我们都知道,vue或react等MVVM框架提倡组件化开发,这样一方面可以提高组件复用性和可扩展性,另一方面也带来了项目开发的灵活性和可维护,方便多人开发协作.接下来文章将介绍如何使用react,开发一个自定义json编辑器组件.我们这里使用了jsoneditor这个第三方库,官方地址: jsoneditor 通过实现

  • react diff算法源码解析

    React中Diff算法又称为调和算法,对应函数名为reconcileChildren,它的主要作用是标记更新过程中那些元素发生了变化,这些变化包括新增.移动.删除.过程发生在beginWork阶段,只有非初次渲染才会Diff. 以前看过一些文章将Diff算法表述为两颗Fiber树的比较,这是不正确的,实际的Diff过程是一组现有的Fiber节点和新的由JSX生成的ReactElement的比较,然后生成新的Fiber节点的过程,这个过程中也会尝试复用现有Fiber节点. 节点Diff又分为两种

  • React事件机制源码解析

    React v17里事件机制有了比较大的改动,想来和v16差别还是比较大的. 本文浅析的React版本为17.0.1,使用ReactDOM.render创建应用,不含优先级相关. 原理简述 React中事件分为委托事件(DelegatedEvent)和不需要委托事件(NonDelegatedEvent),委托事件在fiberRoot创建的时候,就会在root节点的DOM元素上绑定几乎所有事件的处理函数,而不需要委托事件只会将处理函数绑定在DOM元素本身. 同时,React将事件分为3种类型--d

  • React Fiber构建completeWork源码解析

    目录 引言 一. completeUnitOfWork 二. completeWork createInstance createElement appendAllChildren 三. Effect useEffect resolveDispatcher mountEffectImpl pushEffect 四. rootFiber-Effect 引言 之前我们介绍了beginWork,react使用的是深度优先遍历算法,整个fiber的构建都遵循此算法. 这也意味着,并不是所有节点begin

  • Thinkphp5+plupload实现的图片上传功能示例【支持实时预览】

    本文实例讲述了Thinkphp5+plupload实现支持实时预览的图片上传功能.分享给大家供大家参考,具体如下: 今天和大家分享一个国外的图片上传插件,这个插件支持分片上传大文件.其中著名的七牛云平台的jssdk就使用了puupload插件,可见这个插件还是相当牛叉的. 这个插件不仅仅支持图片上传,还支持大多数文件的上传,例如视频文件,音频文件,word文件等等,而且大文件都采用分片上传的机制. Plupload有以下功能和特点: 1.拥有多种上传方式:HTML5.flash.silverli

  • JS实现上传图片实时预览功能

    前段时间在网络上找的代码,修改了一部分用在了项目里.原博客地址找不到了,如果原作者看到的话留言我,将于第一时间删除. //js本地图片预览,兼容ie[6-9].火狐.Chrome17+.Opera11+.Maxthon3 function PreviewImage(fileObj) { //创建dom元素 var divPreviewId = 'divPreview_' + fileObj.name; var imgPreviewId = 'imgHeadPhoto_' + fileObj.na

  • Android camera实时预览 实时处理,人脸识别示例

    Android camera实时预览 实时处理,面部认证. 预览操作是网友共享的代码,我在继承SurfaceView 的CameraSurfaceView 中加入了帧监听事件,每次预览监听前五个数据帧,在处理做一个面部识别. 先看目录关系 自定义控件CameraSurfaceView.java 自定义接口方法CameraInterface.java CameraActivity预览界面. CameraSurfaceView.Java package com.centaur.camera.prev

  • js实现Select头像选择实时预览代码

    本文实例讲述了js实现Select头像选择实时预览代码.分享给大家供大家参考.具体如下: 这里演示js实现Select头像选择,实时预览效果,在留言或评论的时候,让用户简易的选择头像,以前最常见的方式是使用单选框,当然使用其它的形式也可以,比如今天这个Select,下拉选框选择头像,也是不错的体验. 运行效果截图如下: 在线演示地址如下: http://demo.jb51.net/js/2015/js-select-ico-pic-view-codes/ 具体代码如下: <!DOCTYPE ht

随机推荐