Renderless 思想正在影响前端开发

本文由前端小伙伴@方长_beezen 原创。欢迎大家踊跃投稿。
原文链接:https://juejin.cn/post/7385752495535472655

前言

截止到 2024 年,跨端应用开发所需要考虑的兼容性,已经涵盖了框架、平台和设备类型等多个方面,例如:

  • 框架:如 React、Vue、Angular、Svelte、Ember 等。
  • 平台:如 鸿蒙、Android、iOS、小程序、快应用、H5 等。
  • 设备:如 PC、移动设备、车载设备等。

多元化的需求场景,对前端工程师的要求也是越来越高,他们必须掌握 2 种以上的编程语言或者开发框架,不然就很难胜任跨端应用开发的岗位。前端开发工程师的开发日常,也因此变得愈发复杂。

在如此严峻的前端大环境下,无渲染组件 (Renderless Components[1])的概念在开发者社区逐渐兴起,频繁出现在各类流行框架中。最早,由 React 社区提出,开发者可以通过将一个 render 函数作为 prop 传递给组件,这个函数可以接收需要的数据,并返回渲染的 UI 内容。后来,在 Vue 框架中提出了 slots 概念,组件内部真实需要渲染的 UI 内容,可以通过插槽的形式控制。现在,无渲染组件被视为一种新模式,其核心理念是将组件的逻辑与表现分离,达到高可复用的效果。换句话说,无渲染组件只关注组件的内部逻辑行为,而将 UI 表现内容交由调用组件来处理。

无渲染组件通过将组件逻辑行为抽象,我们可以更轻松地在各种不同的 UI 表现上下文中重用它,它的出现不仅减轻前端工程师的工作任务,也为跨端应用的开发提供了更多的可能性。

什么是无渲染组件?

无渲染组件(Renderless Components)是一种设计模式,其核心理念是将组件的逻辑和表现分离。具体来说,无渲染组件只关注业务逻辑和状态管理,而不关心具体的 UI 渲染实现。常见的无渲染组件实现方式如下:

Render Props

通过 render prop 属性将一个函数作为子组件传递,使得父组件可以完全控制 UI 渲染。

React 无渲染组件实现,如下:

import React from "react";class MouseTracker extends React.Component {constructor(props) {super(props);this.state = { x: 0, y: 0 };}// 组件内部逻辑,可复用handleMouseMove = (event) => {this.setState({x: event.clientX,y: event.clientY,});};render() {// this.props.render 渲染子组件return (<div onMouseMove={this.handleMouseMove}>{this.props.render(this.state)}</div>);}
}

在父组件调用时,(x,y) 属性值由无渲染组件提供,UI 渲染则可以自定义控制:

<MouseTracker render={ ({ x, y }) => (
<h1>The mouse position is ({x}, {y})</h1>
) } />

Scoped Slots

Scoped Slots 是一种允许父组件完全控制子组件渲染内容的模式,通过 Scoped Slots 向父子组件双向传递数据和方法,而父组件则负责具体的 UI 渲染。

Vue 无渲染组件实现,如下:

<template><slot :mouse="mouse"></slot>
</template><script>export default {data() {return {mouse: { x: 0, y: 0 },};},mounted() {window.addEventListener("mousemove", this.handleMouseMove);},methods: {handleMouseMove(event) {this.mouse = { x: event.clientX, y: event.clientY };},},};
</script>

在父组件调用时,(x,y) 属性值由无渲染组件提供,UI 渲染则可以自定义控制。

<template><MouseTracker v-slot="{ mouse }"><h1>The mouse position is ({{ mouse.x }}, {{ mouse.y }})</h1></MouseTracker>
</template><script>import MouseTracker from "./MouseTracker.vue";export default {components: {MouseTracker,},};
</script>

无渲染组件 vs 传统组件

除了上面提到的 render props 和 slots 之外,还有很多其他类似的无渲染组件应用场景。我们不需要关注怎样实现才算是无渲染组件,它只是一种思想,用于将传统组件的逻辑和表现进行分离,从而达到高可复用的一种状态。例如 React 中 HOC(高阶组件)、现在主流的 React Hooks 和 Vue Composition API 等方式,都为实现无渲染组件提供了有利条件。值得一提,Renderless 设计模式特别适合跨端应用的开发,将包含各端应用的特性兼容代码提取到 UI 层特性层实现。

下面是无渲染组件对比传统组件的特性对照表:

特点无渲染组件传统组件
逻辑与表现的分离1、只包含业务逻辑,不包含具体的 UI 渲染。 2、渲染由父组件或使用它的组件决定。 3、适合复用复杂的逻辑而不关心具体的 UI 表现。1、包含业务逻辑和 UI 渲染。 2、组件本身决定如何渲染 UI。 3、适合封装独立的功能模块,包含逻辑和展示。
复用性高度复用性,逻辑可以在不同的 UI 实现中复用复用性较低,逻辑和 UI 紧耦合。
灵活性更加灵活,父组件可以完全控制渲染方式和样式。灵活性较低,UI 表现固定。
测试难度1、测试相对简单,只需测试逻辑部分。 2、不涉及 UI 渲染,测试范围更集中1、测试较复杂,需要测试逻辑和 UI 渲染。 2、需要关注组件的整体行为,包括展示和交互.

无渲染组件的优势在于逻辑与表现分离,实现了高复用性和极大灵活性。它允许父组件可以自定义渲染方式和样式,增强了组件的组合能力,使开发更高效、代码更简洁。同时,无渲染组件还简化了测试过程,保障了应用的稳定性。

无渲染组件 vs 公共函数

在日常项目开发中,我们会将项目中的公共逻辑封装为纯函数,以实现代码复用,它们一般不会涉及具体的 UI 渲染和组件的生命周期管理。虽然,无渲染组件也是类似的设计思想。但是,它会利用框架提供的状态管理和数据流特性,将实现更高级的组件功能复用。总而言之,无渲染组件更专注于将组件的逻辑与 UI 分离,不仅仅只考虑公共能力的抽象。

通过无渲染组件的设计思想,我们可以显著地减少开发工作量,同时最大限度地复用组件逻辑,保障模块功能的完整性稳定性

下面的两张图,进一步展示了无渲染组件和传统公共函数在设计思想上的异同之处:

在这里插入图片描述

无渲染组件库

目前,采用无渲染组件思想设计的优秀组件库有 TinyVue[2],它目标兼容 Vue、Vue3、React、Angular、Solid 等框架,覆盖 PC 端和 Mobile 端。
在这里插入图片描述

TinyVue 充分采用了无渲染组件的设计思想,将可复用的逻辑行为抽象到 renderless 模块中,每一个组件的 UI 表现又单独抽象到 PC 模块和 Mobile 模块,实现了跨端、跨版本的高可重用性。

下面是 TinyVue 官方发布的组件架构图:

在这里插入图片描述
在这里插入图片描述

TinyVue 组件库可以在不同终端、不同技术栈的场景下使用,得益于其底层强大的兼容封装能力,暴露给用户使用的 API 接口基本相同,极大地降低了跨端应用中的学习和迁移成本。

最后

Renderless 设计模式的崛起标志着前端开发进入了更加灵活和高效的时代。通过将组件的逻辑与 UI 表现分离,Renderless 组件不仅提升了代码的复用性和可维护性,还为开发者在多平台、多技术栈下的应用开发提供了更多可能性。随着这一设计模式的逐步普及和应用,我们可以期待未来跨端开发将更加轻松和高效。

参考资料

  • Vue renderless components[3]
  • Understanding Renderless Components in Vue[4]
  • 从 0 到 1 实现 OpenTiny 组件库跨框架技术[5]
  • OpenTiny[6]

参考资料
[1]Renderless Components: https://www.patterns.dev/vue/renderless-components/

[2]TinyVue: https://github.com/opentiny/tiny-vue

[3]Vue renderless components: https://www.patterns.dev/vue/renderless-components/

[4]Understanding Renderless Components in Vue: https://www.telerik.com/blogs/understanding-renderless-components-vue

[5]从 0 到 1 实现 OpenTiny 组件库跨框架技术: https://www.cnblogs.com/huaweiyun/p/17776415.html

[6]OpenTiny: https://github.com/opentiny/tiny-vue/blob/dev/README.zh-CN.md

关于OpenTiny

OpenTiny 是一套企业级 Web 前端开发解决方案,提供跨端、跨框架、跨版本的 TinyVue 组件库,包含基于 Angular+TypeScript 的 TinyNG 组件库,拥有灵活扩展的低代码引擎 TinyEngine,具备主题配置系统TinyTheme / 中后台模板 TinyPro/ TinyCLI 命令行等丰富的效率提升工具,可帮助开发者高效开发 Web 应用。

欢迎加入 OpenTiny 开源社区。添加微信小助手:opentiny-official 一起参与交流前端技术~
OpenTiny 官网:https://opentiny.design/
OpenTiny 代码仓库:https://github.com/opentiny/
TinyVue 源码:https://github.com/opentiny/tiny-vue
TinyEngine 源码: https://github.com/opentiny/tiny-engine
欢迎进入代码仓库 Star🌟TinyEngine、TinyVue、TinyNG、TinyCLI~ 如果你也想要共建,可以进入代码仓库,找到 good first issue标签,一起参与开源贡献~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/369270.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

「ETL趋势」分区支持PostgreSQL、Greenplum、Gauss200, 定时任务支持Kettle

FineDataLink作为一款市场上的顶尖ETL工具&#xff0c;集实时数据同步、ELT/ETL数据处理、数据服务和系统管理于一体的数据集成工具&#xff0c;进行了新的维护迭代。本文把FDL4.1.9最新功能作了介绍&#xff0c;方便大家对比&#xff1a;&#xff08;产品更新详情&#xff1a;…

MYSQL篇二:数据库的操作

文章目录 1. 创建数据库1.1 查看数据库列表1.2 创建与删除数据库 2. 数据的编码问题3. 字符集和校验规则3.1 查看系统默认字符集以及校验规则3.2 查看数据库支持的字符集3.3 查看数据库支持的字符集校验规则3.4 校验规则对数据库的影响 4. 操纵数据库4.1 查看当前是哪一个数据库…

安装docker compose与elasticsearch,kibana

1.docker compose安装 1.1是否已安装docker docker -v 1.2安装docker compose curl -SL https://github.com/docker/compose/releases/download/v2.18.0/docker-compose-linux-x86_64 -o /usr/local/bin/docker-composeps:如果网络太慢可直接在博客中下载附属文件 下载后修…

【二】Ubuntu24虚拟机在Mac OS的VMware Fusion下无法联网问题

文章目录 1.环境背景2. 需求背景3. 解决方法3.1 在mac的终端查看虚拟机NAT网络3.2 查看unbuntu节点2的网络配置3.3 问题定位与解决3.3.1 检查是否有冲突3.3.2 冲突解决方法 4. 总结4.1 NAT 网关的原理4.2 VMware Fusion 的 NAT 模式4.3 为什么网关冲突会引起问题4.4 理解配置冲…

python作业一

1. #A.方法一 num int(input("请输入要打印的层数:")) for n in range(1, num1):s ""for i in range(1, n1):s f"{i}" " "print(s) #方法二&#xff1a; iint(input("i:")) for i in range(1,i1):s""for j i…

JavaSE (Java基础):面向对象(下)

8.7 多态 什么是多态&#xff1f; 即同一方法可以根据发送对象的不同而采用多种不同的方式。 一个对象的实际类型是确定的&#xff0c;但可以指向对象的引用的类型有很多。在句话我是这样理解的&#xff1a; 在实例中使用方法都是根据他最开始将类实例化最左边的类型来定的&…

uni-app 自定义支付密码键盘

1.新建组件 payKeyboard .vue <template><view class"page-total" v-show"isShow"><view class"key-list"><view class"list" v-for"(item,index) in keyList" :class"{special:item.keyCode190…

文件操作及部分文件函数的介绍学习(上)

目录 前言 1.为什么要要使用文件&#xff1f; 2.什么是文件&#xff1f; 2.1程序文件 2.2数据文件 2.3文件名 4.文件的打开和关闭 4.1 流和标准流 4.1.1流 4.1.2标准流 4.2文件指针 4.3文件的打开和关闭 结语 前言 Hello&#xff0c;亲爱的小伙伴们&#xff0c;作…

游戏AI的创造思路-技术基础-计算机视觉

让游戏的AI具备“眼睛”和“视觉”&#xff0c;就是通过计算机视觉的方法进行的。现在&#xff0c;越来越多的游戏&#xff0c;特别是动捕类游戏都在使用这个方法。当然&#xff0c;计算机视觉不仅仅用于游戏&#xff0c;越来越多的应用使用到这个技术 目录 1. 定义 2. 发展历…

电气-伺服(6)脉冲控制

一、脉冲模式原理&#xff1a; 运动控制器输出脉冲信号给伺服驱动器 伺服驱动器工作于位置模式 伺服驱动器内部要完成三闭环&#xff08;位置闭环 、速度闭环、电流环&#xff09; 脉冲和伺服控制环&#xff1a;脉冲的个数作用于位置环。脉冲的频率作用于速度环 二、脉冲的两…

【高性能服务器】select模型

&#x1f525;博客主页&#xff1a; 我要成为C领域大神&#x1f3a5;系列专栏&#xff1a;【C核心编程】 【计算机网络】 【Linux编程】 【操作系统】 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 本博客致力于知识分享&#xff0c;与更多的人进行学习交流 IO多路复用就是复用…

Debug-017-elementUI-el-cascader组件首次选择选项不触发表单的自定义校验

前情提要&#xff1a; 今天维护一个表单校验的时候发现一件事情&#xff0c;就是在表单中使用了 el-cascader组件&#xff0c;希望根据接口返回数据去动态校验一下这里面的选项&#xff0c;符合逻辑就通过自定义的表单校验&#xff0c;不符合就在这一项的下面标红提示。做的时候…

Java后端每日面试题(day1)

目录 JavaWeb三大组件依赖注入的方式Autowire和Resurce有什么区别&#xff1f;Spring Boot的优点Spring IoC是什么&#xff1f;说说Spring Aop的优点Component和Bean的区别自定义注解时使用的RetentionPolicy枚举类有哪些值&#xff1f;如何理解Spring的SPI机制&#xff1f;Spr…

初阶数据结构二叉树练习系列(1)

这个系列的文章将带大家一起刷题&#xff0c;并且总结思路 温馨提示&#xff1a;本篇文章里的练习题仅适合刚学完二叉树的小白使用 相同的树 思路 情况分析&#xff1a;第一种情况&#xff1a;两棵树都为空 → 返回true 第二种情况&am…

七、MyBatis-Plus高级用法:最优化持久层开发-个人版

七、MyBatis-Plus高级用法&#xff1a;最优化持久层开发 目录 文章目录 七、MyBatis-Plus高级用法&#xff1a;最优化持久层开发目录 一、MyBatis-Plus快速入门1.1 简介1.2 快速入门回顾复习 二、MyBatis-Plus核心功能2.1 基于Mapper接口CRUDInsert方法Delete方法Update方法Se…

Elasticsearch中的post_filter后置过滤器技术

Hi~&#xff01;这里是奋斗的小羊&#xff0c;很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~~ &#x1f4a5;&#x1f4a5;个人主页&#xff1a;奋斗的小羊 &#x1f4a5;&#x1f4a5;所属专栏&#xff1a;C语言 &#x1f680;本系列文章为个人学习…

数据结构笔记第3篇:双向链表

1、双向链表的结构 注意&#xff1a;这里的 "带头" 跟前面我们说的 "头结点" 是两个概念&#xff0c;实际前面的在单链表阶段称呼不严谨&#xff0c;但是为了同学们更好的理解就直接称为单链表的头结点。 带头链表里的头结点&#xff0c;实际为 "哨兵…

数字IC设计-VCS和Verdi的使用

#学习记录# 前言&#xff1a;本文以一个简单的计数器来说明vcs和verdi的使用 1 代码文件 1.1 计数器代码 //Engineer&#xff1a;Mr-pn-junction module counter(input clk,input rst,output reg [5:0] count); always(posedge clk or negedge rst)beginif(!rst)coun…

自研直播系统-直播系统实战

文章目录 1 流媒体基础本文教程下载地址1.1 流媒体1.2 流式传输方式1.2.1 顺序流式传输1.2.2 实时流式传输 1.3 流媒体传输协议1.3.1 rtmp协议1.3.2 HLS协议1.3.3 RTSP协议1.3.4 视频流的对比 1.4 视频编码(codec)1.5 分辨率的规范分辨率簡介&#xff1a;1.5.2 分辨率單位 1.6 …

递归(三)—— 初识暴力递归之“字符串的全部子序列”

题目1 &#xff1a; 打印一个字符串的全部子序列 题目分析&#xff1a; 解法1&#xff1a;非递归方法 我们通过一个实例来理解题意&#xff0c;假设字符串str “abc”&#xff0c;那么它的子序列都有那些呢&#xff1f;" ", “a”&#xff0c; “b”&#xff0c;…