首页 / 文章

Flutter与React Native:只有在实际使用中才会显现的抉择

一篇客观对比 Flutter 与 React Native 的文章,摒弃了性能测试的争论,重点探讨了应用发展过程中渲染、语言、状态管理、列表功能以及生态系统等方面的差异。

发布者:REACTAPP.TOP阅读约 8 分钟1792 词

来源: Flutter vs React Native: The Real Differences Start After “Hello World”

Flutter和React Native承诺的是同样的好处:只需编写一套代码,即可同时发布到Android和iOS平台,无需再维护两个独立的原生应用。从理论上讲,两者的宣传点完全一致,对于应用的首屏界面而言确实也是如此。在任一框架中创建按钮、渲染列表、实现导航功能或展示API响应都十分简单。但真正影响项目发展的差异并不体现在这些基础功能上,而是当应用发展到需要自定义UI、动画效果、状态管理、原生集成以及长期维护时才会显现出来。本文旨在比较演示之后开始出现的差异,帮助你根据各框架在大型项目中的表现来做出选择,而非仅依据其渲染“Hello World”的速度。

初印象被刻意设计得相似

这两种框架都能让你快速构建可运行的应用。你可以创建界面、添加导航功能、调用 API、渲染列表以及处理用户输入,而无需维护两个独立的原生代码库。正是这种提升效率的优势,使得团队最初会选择跨平台工具。无论选择哪种框架,简单的界面看起来几乎没什么区别。而当应用变得复杂时,两种开发理念的差异就会显现出来,因此真正的对比应体现在复杂的场景中,而非初始模板上。

Flutter 以组件为核心

Flutter最显著的特点是,你所能接触到的几乎所有元素都是小部件。屏幕、按钮、它们周围的间距以及排列这些元素的布局都属于小部件,就连那些不会在屏幕上绘制任何可见内容的结构也是小部件。在这里,一个列式布局会将标签、一些间距以及按钮堆叠在一起,每个组成部分都是嵌套在结构树中的独立小部件。

Column(
  children: [
    Text('Welcome'),
    SizedBox(height: 16),
    ElevatedButton(
      onPressed: () {},
      child: Text('Continue'),
    ),
  ],
)

一旦采用这种模型,构建用户界面就会变得极为一致:通过将小型组件组合成更大的组件,这些较大的组件最终会构成完整的屏幕。而 React Native 采取了不同的方式——它使用用 JavaScript 或 TypeScript 编写的 React 组件来描述界面,因此其思维模式本质上与构建 React 应用相同,对于那些已经熟悉 React 的人来说会显得非常自然。这两种模型并没有绝对的优劣之分,它们只是引导人们从不同的角度思考界面构建方式,究竟哪种方式“正确”则很大程度上取决于团队现有的思维习惯。

渲染机制以及你对界面的控制程度

Flutter的渲染方式正是使其成为高度定制化界面理想选择的原因。当设计需求超出标准平台界面的范畴时,Flutter提供了丰富的组件库以及各种绘图原语,让用户能够组合这些元素来打造几乎任何想要的视觉效果。自定义卡片、动画、过渡效果、加载器、图表、交互元素、独特布局以及极具艺术感的界面,全都可以在同一个组件系统中实现。

React Native同样能够构建高度定制化的界面,但其实现方式有所不同,因为它传统上是通过运行时架构来使用平台自身的原生组件。这里需要明确一点:随着新架构的引入,现代React Native已经发生了显著变化,因此“JavaScript通过桥接与原生代码通信”这种旧有的简化描述已无法准确反映当前版本的实际工作原理,基于此的比较也已经过时。关键并不在于某个框架无法实现某种界面——两者都能做到。区别在于它们实现该界面的路径,以及日常使用中的体验差异。

Dart与JavaScript及TypeScript的对比

在开始编写任何用户界面之前,一个重要的差异就显现出来了:语言。Flutter基于Dart构建;而React Native则在大多数正式项目中使用JavaScript或TypeScript。Dart是一种强类型语言,专为与Flutter搭配而设计,一旦熟悉之后,它就会显得是编写应用代码的理想选择。一些类型声明的样子如下。

final String name = 'Ankit';
final int age = 25;

这种静态类型特性使得更大的代码库更易于理解,因为编译器能在程序运行之前就捕获各类错误。React Native团队通常会选用TypeScript,以便在JavaScript环境中获得同样的好处。

const name: string = 'Ankit';
const age: number = 25;

TypeScript在保持与JavaScript生态系统兼容的同时提供了强大的类型支持,这对于已经投入JavaScript开发的组织而言具有显著优势。那些拥有成熟React开发团队的公司往往能更顺利地引入React Native,因为开发者可以沿用现有的概念、工具和开发习惯。而对于那些深度使用Dart的团队,Flutter则提供了一个专注且独立的开发环境。这种选择意味着要在现有生态系统的广泛性与专用生态系统的完整性之间做出权衡。

状态管理不再如此简单

状态是早期简洁性消散最快的地方。小型应用只有寥寥几项状态;而生产级应用则会积累大量状态,包括身份验证状态、用户资料数据、购物车内容、API加载状态、分页功能、搜索筛选条件、通知信息、主题偏好设置、本地存储数据、表单状态以及实时更新内容。当如此多的问题同时存在时,仅靠框架已无法解决问题,还需要相应的架构以及建立在之上的精心设计的状态管理策略。

这两种生态系统都提供了多种选择。在 Flutter 方面,有 Provider、Riverpod、BLoC、Cubit、GetX 等;在 React Native 方面,则有 Redux、Zustand、MobX、Context API 以及更多方案。仅通过统计插件数量很难判断优劣。决定应用可维护性的关键在于团队是否能够持续地构建并优化应用的状态结构。即便框架能带来出色的 UI 性能,但如果底层状态架构薄弱,依然会导致应用难以维护。无论使用哪种框架来渲染界面,保持大型 React 应用架构一致性的相同原则在这里同样适用。

性能并非衡量标准

在各类对比中,性能是最常被提及的话题。文章们常常依据人工设计的基准测试来判定某个框架比另一个更快,但实际应用并非这样的基准测试。一个生产级应用通常会涉及网络请求、大量数据列表、图片、动画、地图、本地存储、后台任务、推送通知、网页视图、分析功能、原生SDK以及第三方插件,而这些元素每一项都可能影响性能表现。

构建不佳的 Flutter 应用可能会运行缓慢,构建不佳的 React Native 应用也是如此。不必要的重新编译、过度的渲染、过大的图片、效率低下的列表处理、耗时的计算、粗心的内存使用方式以及设计糟糕的网络流程,都会导致应用变慢,而这些都与框架的名称无关。更重要的问题是该应用的架构在处理特定工作负载时的表现如何,而非哪个框架能在抽象的竞速中胜出。如果不清楚正在开发什么应用,“哪个更快”这个问题的答案几乎毫无意义。

列表让问题更加具体

想象一个拥有数千种产品的电子商务应用。在任何框架中,都将所有产品加载到内存中并同时渲染都是错误的做法。Flutter 的解决方案是采用按需构建的方式,在项目滚动到视口时才生成相应内容。

ListView.builder(
  itemCount: products.length,
  itemBuilder: (context, index) {
    return ProductCard(
      product: products[index],
    );
  },
)

其原则是仅构建所需的内容,而非预先生成所有元素。React Native通过FlatList等机制实现了相同理念。核心概念是相通的,不同之处在于具体的API、渲染模型、优化技术以及相关的开发体验。当列表变得复杂时,决定其流畅性的因素——如分页、图片缓存、元素尺寸控制、状态更新以及避免不必要的重新渲染——比所选择的框架更为重要。

生态系统才是真正的决定性因素

React Native在某个特定方面具有明显优势:它属于JavaScript生态系统。JavaScript和TypeScript已经广泛应用于前端、后端、开发工具以及整个网络领域,而React则是目前使用最广泛的UI库之一。因此,那些拥有强大React开发团队的组织可以轻松过渡到React Native,重新利用他们已有的技能和库。

Flutter的优势则截然不同。它拥有以Flutter和Dart为核心的相对集中的生态系统,对于那些希望在不依赖庞大JavaScript生态体系的情况下开发移动应用的团队来说,这种架构显得更加简洁统一。两者并无绝对的优劣之分,哪种更合适取决于你现有的团队情况。

那么你应该选择哪一个呢?

并不存在放之四海而皆准的最佳选择,合适的决策应基于项目的具体情况以及相关人员的技能。如果一个团队已具备扎实的 React 和 TypeScript 使用经验,那么 React Native 可以几乎毫无障碍地融入其现有的技术栈。如果团队希望使用基于 Dart 且采用组件驱动模型的专用跨平台 UI 框架,Flutter 则是理想之选。那些依赖团队现有 React 专业技能及 JavaScript 基础设施的应用,显然更适合 React Native;而那些需要高度定制化 UI、且由熟悉 Flutter 的团队开发的应用,则更适合同样的框架。需要避免的错误是,仅仅因为某篇文章宣称某个框架“更好”就选择它,而非根据其是否适合当前产品来决策。

总结

Flutter和React Native从不同角度解决同一个核心问题。Flutter采用Dart语言,提供以组件为驱动的开发模式以及高度集成的UI工具包,非常适合自定义设计。React Native则将React和JavaScript生态系统引入移动开发领域,同时通过一种早已超越早期桥接式架构局限的成熟结构,让开发者能够使用原生平台的各项功能。并没有哪种框架能默认就让所有应用变得更好。关键问题从来不是“哪个框架更胜一筹”,而是“哪种框架更适合这款产品、这支团队以及这类应用”。几乎任何方式都能渲染出第一个界面,而后续功能的实现才是这两个框架真正产生差异的地方。