Skip to content

Instantly share code, notes, and snippets.

@rikumi
Last active December 28, 2021 03:07
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rikumi/a04632ae679d9c11e2dd29cd7066aedb to your computer and use it in GitHub Desktop.
Save rikumi/a04632ae679d9c11e2dd29cd7066aedb to your computer and use it in GitHub Desktop.
Remax Boundary

Boundary 原生数据隔离层

由于 Remax 框架的实现,小程序 data 会扮演 VDOM 同步管道的作用,因此当同一个页面中存在大量 VDOM 节点,即使触发一个很小的状态变化,也要花很久才能完成渲染。这是因为小程序基础库会在每次数据更新时对全量数据进行 diff。

Boundary 组件是用来隔离那些存在大量数据却不需要频繁更新的容器,它会将容器内部的所有 VDOM 数据自动移入到小程序组件内部,不参与页面 setData,从而允许页面的数据更新保持高性能。

用法

直接在存在大量节点的层级上套一层 <Boundary>...</Boundary> 即可,不需要任何参数。

实现细节

Boundary 的想法来源于 Taro 的 CustomWrapper 和 Kbone 中的 <wx-view> 写法

最初我在 Remax Issues 中提了这个 Issue,详细描述了遇到的问题,后来被重定向到这个 Issue

后来在一次 Remax 源码阅读过程中,发现 Remax 的 App 把一部分 React 虚拟节点渲染到 Page 的实现方法正是我想要的,因此通过完全照搬这部分逻辑,解决了问题。实际上并不需要像上述 issue 那样把组件“编译成”小程序组件,只需要用 Remax 已经实现的 Portal 特性,把想要渲染到组件内部的节点嵌套在 Portal 内,让 React Reconciler 将这部分节点的更新派发给组件层级内的 Container 而不是页面 Container 即可。

如果要进一步理解实现的细节,可参考 Remax Runtime 的源码:

import { createPortal } from '@remax/runtime';
import React, { useEffect, useState } from 'react';
import NativeBoundary from './native-boundary';
const Boundary: React.FC = (props) => {
const { children } = props;
const [container, setContainer] = useState<any>();
useEffect(() => container?.applyUpdate());
return <>
<NativeBoundary {...{ 'bind:init': e => setContainer(e.detail.container) }} />
{container && createPortal(children, container)}
</>;
};
export default Boundary;
import React from 'react';
declare const NativeBoundary: React.ComponentType<{ 'bind:init': (container: any) => void }>;
export default NativeBoundary;
Component({
options: {
styleIsolation: 'shared',
},
data: {
root: {
children: [],
},
},
lifetimes: {
attached() {
const Container = getCurrentPages().slice(-1)[0].container.constructor;
this.container = new Container(this, 'root');
this.triggerEvent('init', { container: this.container });
},
detached() {
this.data.unregister && this.data.unregister();
},
},
});
{
"component": true
}
<import src="/base.wxml" />
<template is="REMAX_TPL" data="{{root: root}}" />
@watsonhaw5566
Copy link

兄弟,你们企鹅有用到remax了吗?

@rikumi
Copy link
Author

rikumi commented Dec 3, 2021

@watsonhaw5566 我负责的项目有用到,但细节上会有自己的改动。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment