一、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 的解析, 例如后端模版定义默认的样式, 与前端进行合并