当前位置: 首页 > news >正文

React 函数组件和类组件的区别

1. 定义方式

  • 函数组件:使用 ES6 的函数定义组件,接收 props 作为参数,返回一个 JSX 元素或 null。
function Welcome(props) {return <h1>Hello, {props.name}</h1>;
}
  • 类组件:使用 ES6 的类定义组件,继承自 React.Component,通过 render 方法返回 JSX。
class Welcome extends React.Component {render() {return <h1>Hello, {this.props.name}</h1>;}
}

2. 状态管理

  • 函数组件:在 React 16.8 之前,函数组件没有自己的状态,需要通过外部状态管理库(如 Redux)或父组件传值来管理状态。React 16.8 引入了 Hooks 后,函数组件可以通过 useState Hook 管理自己的状态。
import React, { useState } from 'react';function Counter() {const [count, setCount] = useState(0);return (<div><p>You clicked {count} times</p><button onClick={() => setCount(count + 1)}>Click me</button></div>);
}
  • 类组件:通过 this.state 来管理组件的内部状态,并使用 this.setState 方法来更新状态。
class Counter extends React.Component {constructor(props) {super(props);this.state = { count: 0 };}render() {return (<div><p>You clicked {this.state.count} times</p><button onClick={() => this.setState({ count: this.state.count + 1 })}>Click me</button></div>);}
}

3. 生命周期方法

  • 函数组件:没有生命周期方法,但在 React 16.8 引入 Hooks 后,可以通过 useEffect Hook 来实现类似生命周期的功能。
import React, { useState, useEffect } from 'react';function DataFetching() {const [data, setData] = useState([]);useEffect(() => {fetch('https://api.example.com/data').then(response => response.json()).then(data => setData(data));}, []); // 空数组表示类似 componentDidMount 的效果return (<div>{data.map(item => (<div key={item.id}>{item.name}</div>))}</div>);
}
  • 类组件:拥有多个生命周期方法,如 componentDidMount、componentDidUpdate、componentWillUnmount 等,这些方法在组件的挂载、更新和卸载过程中自动调用。
class DataFetching extends React.Component {constructor(props) {super(props);this.state = { data: [] };}componentDidMount() {fetch('https://api.example.com/data').then(response => response.json()).then(data => this.setState({ data }));}render() {return (<div>{this.state.data.map(item => (<div key={item.id}>{item.name}</div>))}</div>);}
}
  • 类组件:拥有多个生命周期方法,如 componentDidMount、componentDidUpdate、componentWillUnmount 等,这些方法在组件的挂载、更新和卸载过程中自动调用。
class DataFetching extends React.Component {constructor(props) {super(props);this.state = { data: [] };}componentDidMount() {fetch('https://api.example.com/data').then(response => response.json()).then(data => this.setState({ data }));}render() {return (<div>{this.state.data.map(item => (<div key={item.id}>{item.name}</div>))}</div>);}
}

4. 组件的复用性

  • 函数组件:更易于复用逻辑,可以通过自定义 Hooks 来提取组件逻辑,实现逻辑的复用。
function useCounter(initialCount) {const [count, setCount] = useState(initialCount);const increment = () => setCount(count + 1);return { count, increment };
}function Counter() {const { count, increment } = useCounter(0);return (<div><p>You clicked {count} times</p><button onClick={increment}>Click me</button></div>);
}
  • 类组件:复用逻辑通常需要借助高阶组件(HOC)或继承的方式,相对来说更加复杂。

5. 性能优化

  • 函数组件:可以通过 React.memo 对组件进行性能优化,避免不必要的重渲染。
const MyComponent = React.memo(function MyComponent(props) {/* 只有 props 发生变化时才会重新渲染 */return /* ... */;
});
  • 类组件:可以通过 shouldComponentUpdate 方法来控制组件是否更新,从而优化性能。
class MyComponent extends React.Component {shouldComponentUpdate(nextProps, nextState) {return nextProps.value !== this.props.value || nextState.count !== this.state.count;}render() {/* ... */}
}

React.memo 和shouldComponentUpdate 详细讲解

React.memo

React.memo 是 React 提供的一个高阶组件,用于优化函数组件的性能。 当组件的 props 没有发生变化时,它可以阻止组件的不必要的重新渲染。

用法

import React, { memo } from 'react';const MyComponent = (props) => {console.log('MyComponent render', props.value);return <div>{props.value}</div>;
};// 使用 React.memo 包裹组件
const MemoizedMyComponent = memo(MyComponent, (prevProps, nextProps) => {// 自定义比较逻辑return prevProps.value === nextProps.value; // 如果返回 true,则不重新渲染
});// 在父组件中使用
function ParentComponent() {const [count, setCount] = useState(0);return (<div><button onClick={() => setCount(count + 1)}>Update Count</button><MemoizedMyComponent value={count} /></div>);
}

参数说明

  • 第一个参数:要被优化的函数组件。
  • 第二个参数(可选):一个比较函数,用于比较当前 props 和上一个 props。如果返回 true,组件不会重新渲染;如果返回 false,组件会重新渲染。如果不提供此函数,React 会使用默认的浅比较(shallow comparison)。

默认行为
如果不提供自定义的比较函数,React 会使用浅比较来判断 props 是否发生变化。浅比较会检查对象的引用是否相同,而不是进行深度比较。

const MemoizedMyComponent = memo(MyComponent);
shouldComponentUpdate

shouldComponentUpdate 是类组件中的一个生命周期方法,用于控制组件是否应该在状态或属性发生变化时重新渲染。 如果返回 false,组件不会重新渲染;如果返回 true,组件会重新渲染。

用法

class MyComponent extends React.Component {shouldComponentUpdate(nextProps, nextState) {// 自定义比较逻辑return nextProps.value !== this.props.value || nextState.count !== this.state.count;}render() {console.log('MyComponent render', this.props.value, this.state.count);return <div>{this.props.value}</div>;}
}// 在父组件中使用
function ParentComponent() {const [count, setCount] = useState(0);return (<div><button onClick={() => setCount(count + 1)}>Update Count</button><MyComponent value={count} /></div>);
}
对比
特性React.memoshouldComponentUpdate
适用组件类型函数组件类组件
使用方式高阶组件,包裹函数组件类组件的生命周期方法
参数两个参数:要优化的组件和自定义比较函数(可选)两个参数: 和
默认行为浅比较无默认行为,需要手动实现比较逻辑
性能影响优化函数组件的渲染性能优化类组件的渲染性能
适用场景简单的展示型函数组件,或需要根据 props 变化控制渲染的场景复杂的类组件,需要精细控制渲染逻辑的场景
代码简洁性代码简洁,易于使用需要手动实现比较逻辑,代码可能较为复杂
选择建议
  • 如果你使用的是函数组件,建议使用 React.memo 来优化性能。
  • 如果你使用的是类组件,建议使用 shouldComponentUpdate 来优化性能。
  • 在复杂的业务场景中,可以结合 React.memo 和 shouldComponentUpdate 来实现更精细的性能优化。

6. 代码简洁性

  • 函数组件:代码更为简洁,逻辑清晰,尤其是使用 Hooks 后,可以将相关逻辑放在一起,增强可读性。
  • 类组件:代码相对复杂,需要处理 this 的指向问题,且生命周期方法分散在不同地方,逻辑可能不够直观。

7. 使用场景

  • 函数组件:适用于简单的展示型组件或逻辑较为简单的场景,随着 Hooks 的引入,函数组件的功能得到了极大的增强,现在也被广泛用于复杂的业务场景。
  • 类组件:适用于需要管理复杂状态和生命周期的组件,或者在一些特殊的场景下(如需要使用 ref 来访问 DOM 节点)。

总结

特性函数组件类组件
定义方式使用函数定义,接收 参数,返回 JSX使用类定义,继承自 ,通过 方法返回 JSX
状态管理React 16.8 之前无状态,16.8 之后通过 Hook 管理状态通过 和 管理状态
生命周期方法无生命周期方法,通过 Hook 实现类似功能拥有多个生命周期方法,如 、 等
复用逻辑通过自定义 Hooks 复用逻辑通过高阶组件(HOC)或继承复用逻辑
性能优化使用使用
代码简洁性更为简洁,逻辑清晰代码相对复杂,需处理 指向
使用场景简单展示型组件或逻辑简单的场景,现在也适用于复杂业务场景复杂状态管理和生命周期控制的场景,或特殊场景(如需要访问 DOM 节点)

相关文章:

  • dify本地部署,docker-plugin_daemon-1启动不了,一直报错
  • OpenSPG/KAG V0.7发布,多方面优化提升,事实推理效果领先且构建成本降至11%
  • 科技天眼守望农田:珈和卫星遥感监测赋能智慧农业,护航粮食安全新未来
  • 无刷电机槽数相同、转子极数不同的核心区别
  • Java ThreadLocal内存泄漏分析
  • 健康养生:开启活力生活新篇章
  • 前端如何构建跨平台可复用的业务逻辑层(Web、App、小程序)
  • 守护进程编程以及ssh反向代理
  • C语言==》字符串断行
  • 每日文献(十四)——Part one
  • 前端:uniapp框架中<scroll-view>如何控制元素进行局部滚动
  • Vue3笔记
  • 文献分享 | 使用ANSYS Fluent进行除雾系统设计分析
  • LIB-ZC, 一个跨平台(Linux)平台通用C/C++扩展库, 多关键字搜索模块
  • vue3学习笔记之条件渲染
  • 关于EXPLAIN ANALYZE 工具的解析及使用方法(AI)
  • centos7更换yum源不生效
  • KingbaseV8
  • easyExcel单元格合并
  • 【TVM教程】microTVM TFLite 指南
  • 央媒关注微短剧如何探索精品化之路:从“悬浮”落回“现实”
  • 在没有穹顶的剧院,和春天的音乐会来一场约会
  • 两大跨国巨头称霸GLP-1市场,国产减肥药的机会在哪?
  • 外交部:中国将深化同柬埔寨等周边国家友好合作,携手推进亚洲现代化进程
  • 美国佛罗里达州立大学发生枪击事件
  • 提升青春期+亲子含量:社区商业综合体这样用好“二次元”