React项目开发中函数组件与函数式编程关系

 更新时间:2023年11月22日 09:47:25   作者:卡颂  
函数组件和函数式编程究竟是什么关系呢?本文会围绕这个话题展开讲解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

函数组件 和 函数式编程 有关系么?

长期使用React的同学应该知道,React中存在两种组件:

  • Class Component,类组件                                                                           
  • Function Component,函数组件

既然提到函数,那么很自然的,我们会进一步思考:

  • 类组件和OOP(面向对象编程)有关系么?
  • 函数组件和FP(函数式编程)有关系么?

毕竟,如果类组件和OOP有关,那么OOP中的思想(继承、封装、多态...)也能指导类组件的业务开发(函数组件与FP的关系同理)。换言之,我们可以直接用这些编程范式的最佳实践指导React项目开发。

编程范式与DSL

首先,我们应该明确,框架语法本质是一种DSL(领域相关语言),他是为了某个特定领域的开发量身定制的。

比如,React作为一款针对view开发DSL,虽然不同的view使用的框架不同,比如:

  • 对于web,框架为ReactDOM
  • 对于小程序,框架为Taro
  • 对于原生开发,字节内部有个叫React Lynx的框架

但这些框架都大体遵循同一套DSLReact语法),这套DSL并不属于某一种编程范式,而应该被视为不同编程范式中,更符合view开发的语言特性的集合

所以,作为React DSL的一部分,函数组件可以体现OOP的思想,类组件也能体现FP的思想。只要这些思想有利于view开发,就可以纳入DSL的语法中。

比如,下面的函数组件Header,是由WelcomeMessageLogoutButton组件组合而成,这是OOP中的组合优于继承思想:

function Header(props) {
  return (
    <div>
      <WelcomeMessage name={props.name} />
      <LogoutButton onClick={props.onLogout} />
    </div>
  );
}

再比如,下面的类组件Cpn中,要改变状态count,并不是通过突变(类似this.state.count++),而是调用this.setState,传入不可变数据:

class Cpn extends React.Component {
  // ...
  onClick() {
    const count = this.state.count;
    this.setState({count: count + 1});
  }
  render() {
    // ...
  }
}

使用不可变数据属于FP中的思想。

所以,当我们要深入了解某个React特性时,应该以如下顺序递进的思考:

  • React的开发理念是什么?
  • 为了实现这套理念,吸收了哪些编程范式中的思想
  • 这些思想如何在React中落地

如果我们用上述思考过程研究函数组件与函数式编程的关系,会发现:

  • 函数组件属于落地的产物(上述思考的第三步)
  • 函数式编程属于编程范式(上述思考的第二步)

这就是两者的关系 —— 函数组件属于多种编程范式(主要是OOPFP)在React中最终的落地产物,其中借鉴了一部分FP的思想。

我们不应该将函数组件单纯视为FPReact中的具象体现。

那么,函数组件究竟是如何演进而来的呢?

函数组件的演进

让我们按照上述三步演进顺序思考。首先,React的开发理念践行了如下公式(即:UI是数据快照经过函数映射而来):

UI = fn(snapshot)

要落地这个理念,有两个要素需要实现:

  • 数据快照
  • 函数映射

在这里,FP不可变数据更适合作为数据快照的载体,所以React中状态是不可变的,因为状态的本质是快照。

函数映射的载体则没有特殊要求。在React中,每次触发更新,所有组件都会重新renderrender的过程就是函数映射的过程,输入是propsstate,输出是JSX

React相对的,Vue中组件则更符合OOP的理念,考虑如下App组件:

const App = {
  setup(initialProps) {
    const count = reactive({count: 0})
    const add = () => { count.value++ }
    return {count, add}
  }
  template: "...省略"
}

组件的setup方法只会在初始化时执行一次,后续触发更新时操作的都是同一个闭包中的数据。这里面的闭包就是OOP思想中的实例。

既然React函数映射的载体没有特殊要求,那么类组件、函数组件都是可以的。

那为什么函数组件最终替代了类组件成为React开发的主流呢?很多同学认为函数组件的Hooks可以更好的复用逻辑这一点,是函数组件优于类组件的主要原因。

但实际上,基于装饰器的类开发模式早已被验证是优秀的逻辑复用模式,类组件配合TS装饰器的模式是行得通的。

主要原因还是 —— 函数组件能够更好的落地UI = fn(snapshot)这一理念。

刚才说过,公式中的snapshot快照的含义。在React中,快照主要包括三类数据:

  • state
  • props
  • context

对于同一个组件,根据公式UI = fn(snapshot),相同的快照输入应该获得相同输出(JSX)。

但状态更新也可能触发副作用,比如请求数据、操作DOM...

在类组件中,这些副作用逻辑被分散在各个生命周期钩子函数中,React无法掌控。

而在函数组件中:

  • 副作用受限在useEffect中。每次renderReact都会保证上次的副作用效果已经被清除(通过useEffect回调的返回值函数)
  • ref的传播也需要借由forwardRef,这进一步限制了ref可能的影响范围
  • 数据请求的副作用被交给Suspense处理,考虑下面组件:
function UserList({id}) {
  // 异步请求数据
  const data = use(fetchUser(id));
  // ...
}

使用时:

<Suspense fallback={<div>加载中...</div>}>
  <UserList id={1}/>
</Suspense>

总而言之,使用函数组件时,所有副作用都处于一种受到管控的状态,可以尽可能保证每次更新时相同的快照输入,获得相同的JSX输出,所以函数组件在React中才会发扬光大。

同时,这也契合了FP中的纯函数思想。

总结

函数组件并不是函数式编程React中的具体实现,而是React的设计理念UI = fn(snapshot)落地的最好载体。

React中,还吸收了其他编程范式中的优秀思想。FP只是其中影响React最深的一种。毕竟,一切落地都是为了践行最初的设计理念。

以上就是React项目开发中函数组件与函数式编程关系的详细内容,更多关于React函数组件函数式编程的资料请关注脚本之家其它相关文章!

相关文章

  • react redux及redux持久化示例详解

    react redux及redux持久化示例详解

    这篇文章主要为大家介绍了react redux及redux持久化示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-08-08
  • react使用antd的上传组件实现文件表单一起提交功能(完整代码)

    react使用antd的上传组件实现文件表单一起提交功能(完整代码)

    最近在做一个后台管理项目,涉及到react相关知识,项目需求需要在表单中带附件提交,怎么实现这个功能呢?下面小编给大家带来了react使用antd的上传组件实现文件表单一起提交功能,一起看看吧
    2021-06-06
  • React split实现分割字符串的使用示例

    React split实现分割字符串的使用示例

    当我们需要将一个字符串按照指定的分隔符进行分割成数组时,我们可以在组件的生命周期方法中使用split方法来实现这个功能,本文就来介绍一下,感兴趣的可以了解下
    2023-10-10
  • React如何利用Antd的Form组件实现表单功能详解

    React如何利用Antd的Form组件实现表单功能详解

    这篇文章主要给大家介绍了关于React如何利用Antd的Form组件实现表单功能的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-04-04
  • React实践之Tree组件的使用方法

    React实践之Tree组件的使用方法

    本篇文章主要介绍了React实践之Tree组件的使用方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-09-09
  • react中使用swiper的具体方法

    react中使用swiper的具体方法

    本篇文章主要介绍了react中使用swiper的具体方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-05-05
  • React Immutable使用方法详细介绍

    React Immutable使用方法详细介绍

    Immutable.js出自Facebook,是最流行的不可变数据结构的实现之一。它实现了完全的持久化数据结构,使用结构共享。所有的更新操作都会返回新的值,但是在内部结构是共享的,来减少内存占用
    2022-09-09
  • react-three-fiber实现炫酷3D粒子效果首页

    react-three-fiber实现炫酷3D粒子效果首页

    这篇文章主要介绍了react-three-fiber实现3D粒子效果,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-08-08
  • react.js框架Redux基础案例详解

    react.js框架Redux基础案例详解

    这篇文章主要介绍了react.js框架Redux基础案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-09-09
  • 详解react-native-fs插件的使用以及遇到的坑

    详解react-native-fs插件的使用以及遇到的坑

    本篇文章主要介绍了react-native-fs插件的使用以及遇到的坑,详细的介绍了react-native-fs安装使用,具有一定的参考价值,有兴趣的可以了解一下
    2017-09-09

最新评论