React Native SDR 实践

一、SDR简述

SDR(server driven rendering)服务器驱动渲染, 将组件的定制渲染移至后端, 重点是创建可以从后端完全控制和更改的组件,它可以极大地帮助公司解决以下问题:

1. 微型前端
2. 针对具有不同设计的受众
3. 有针对性的移动应用的 A/B Test
4. 不同应用程序版本的组件版本控制
5. 发布后在生产中编辑组件(动态更新,codepush、webview)
6. 修正了一些错误,但没有将新的应用程序版本发布到应用商店(动态更新,codepush、webview)

与Codepush不同的是, CodePush的功能非常广泛,远程配置主要用于原始值,并且可以解决由于热更进度导致的视图不能及时同步的问题 。同时SDR的实现过程也将会面临如下问题:

1. 安全更新我们的组件定义,同时保持向后兼容性。
2. 跨平台共享我们组件的类型定义。
3. 在运行时响应事件,例如单击按钮或用户输入。
4. 渲染在构建时没有现有实现的完全自定义组件。(尝试Lona格式)
5. 解析到生成组件过程的耗时时长

SDR所带来的优势与问题,基本可以满足我们在日常开发中较为轻量级的页面组件建设。如何搭建一个SDR容器, 使其使用方便、易扩展、拥有安全健壮性变的异常重要。
 

二、SDR构建分析

在RN中构建SDR容器前, 我们先来分析RN中的组件是如何构成的。先来看一个简单的例子

<View style={{ width: 100 }}>
    <Text style={{ fontSize: 10 }}>
        sdr
    </Text>
</View>

代码中, 定义了基本的View组件, 在View组件中定义Text组件, 并分别设置style属性。所以基本的组件大致包含以下属性:

1. 组件名称、类型

2. 组件属性(props、自定义props等)

3. 组件的children

 所以构建SDR的前提是, 我们需要定义一套 “规则” 来约束前端如何去创建组件、属性、及子组件等。所以上面组件映射成的协议, 我们大致可以定义为如下: 

{
    type: 'View',
    props: {
        style: {
            width: 100,
        }
	},
	children: [
		{
		    type: 'Text',
		    props: {
		        style: {
		            fontSize: 10,
		        }
			},
			children: 'sdr'
		}

	]
}

可以看到, 我们将组件定义为type, 属性定义为props, 子组件定义为children。作为type的映射, 我们需要提示定义好, 例如, type: 'View', 对应的是RN中的View组件, 所以sdr的Type协议如下:

sdrTypes: {
	Text: Text,
	View: View,
	Image: Image,
	Button: TouchableOpacity,
},

当规则定义好后, 接下来就需要针对props, children进行遍历解析, 在解析过程中, 由于组件是嵌套实现, 所以需要借助递归算法来逐步完成对 type, props, children的解析, 最终调用React.createElement方法既可以完成组件的创建。

三、属性的动态控制

协议声明中, 基本都是定义好的属性, 如果某个属性的值需要依靠前端来控制, 就需要利用占位符来定义, 前端用值进行匹配占位符, 对其进行替换。所以, 针对 props、 text、function我们可以定义如下规则:

prop:: 前端定义的props结构
text:: 前端定义的值结构
function:: 前端定义的方法结构

上面看起来比较抽象, 简单说就是定义占位符前缀, 标示当前的类型, 后面拼接具体的数值, 来看个例子, 例如我们要将Text组件中显示的 “sdr”, 通过前端定义, 那么组件渲染的规则如下:

{
    type: 'Text',
    props: {
        style: {
            fontSize: 10,
        }
	},
	children: '${text::userInfo.userName}'
}

 可以看到, Text组件的children 定义成了 “${text::userInfo.userName}”, 然后在解析children的过程中, 会匹配是否包含 “text::”,有, 则会取到前端定义的数据结构, 并拿到最终的值进行替换, 所以前端需要定义数据的结构体:

userInfo={{
	userName: 'sdr',
}}

这样, 在解析的过程中, 会取到userInfo下的userName的值, 对children进行替换, 最终就是 children: ‘sdr’ 。同样, props、function的定义也是如此。

四、使用

1. 配置声明

const ClientConfig = {
  sdrTypes: {
    Text: Text,
    View: View,
    Image: Image,
    Button: TouchableOpacity,
  },
  loading: false,
  error: false,
  renderError: () => {},
  renderLoading: () => {},
};

(1) sdrTypes声明了sdr模版与组件的映射关系

(2) loading、error、renderError、renderLoading声明了加载中、失败的状态及对应的视图显示

2.  Provider 提供基础的配置、SDRView 作为渲染组件, 根据提供的 sdr 模版生成对应的组件树, 模版中涉及到的占位符数据, 需要在SDRClient作为props传入

<Provider config={ClientConfig}>
  <SDRView
    sdrTemplate={sdrTemplate}
    test={testData}
    item={{
      info: {
        buttonName: 'btn',
      },
    }}
  />
</Provider>

3. sdrTemplate 模版可以从 Server 端 拉取, 设置到 SDRView 即可

五、总结 

从原理的概述, 到简单的实践, 基本实现了在 React Native 中使用 SDR 的渲染方式, 目前存在的问题如下:

支持多个 style 的解析, 例如后端模版定义默认的样式, 与前端进行合并

源码可参考 https://github.com/songxiaoliang/rn-sdr

发布了214 篇原创文章 · 获赞 371 · 访问量 92万+

猜你喜欢

转载自blog.csdn.net/u013718120/article/details/105030859