React中类组件和函数组件的理解和区别
react代码模块分为类组件和函数组件。
从语法和定义、内部状态管理、生命周期、性能、可读性和维护性、上下文、集成状态管理库等角度对比React中类组件和函数组件。
1、语法和定义
类组件:
使用 ES6 的类(class)语法定义的 React 组件。它们具有更复杂的功能,特别是在 React 16.8 之前,它们是唯一能够使用状态(state)和生命周期方法的组件。
特点:
- 使用 class 关键字定义,并继承自 React.Component。
- 能够使用 state 来管理组件的内部状态。
- 可以使用生命周期方法,如 componentDidMount、componentDidUpdate 和 componentWillUnmount 等。
- 通过 this.props 来访问传递给组件的属性(props)。
import React, { Component } from 'react';
class HelloComponent extends Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
}
increment = () => {
this.setState({ count: this.state.count + 1 });
}
render() {
return (
<div>
<p>Count: {this.state.count}</p>
<button onClick={this.increment}>Increment</button>
</div>
);
}
}
export default HelloComponent;
函数组件(Function Component):
函数组件是使用 JavaScript 函数定义的 React 组件。自 React 16.8 以来,函数组件通过引入 Hooks 可以实现状态管理和副作用处理,功能上已经与类组件基本等价。
特点:
- 使用 JavaScript 函数定义,通常是更简单和推荐的方式。
- 在函数组件中,无法直接使用 this,而是通过 Hooks(如> useState 和 useEffect)来管理状态和副作用。
- 更加简洁,通常用于无状态组件,但在有状态需求时也可以使用 Hooks。
import React, { useState } from 'react';
function HelloComponent() {
const [count, setCount] = useState(0);
const increment = () => {
setCount(count + 1);
};
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
</div>
);
}
export default HelloComponent;
2、内部状态管理
类组件:
使用类组件时,可以通过组件的内部状态(state)来管理组件的数据。
import React from 'react';
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
render() {
return (
<div>
<p>Count: {this.state.count}</p>
<button onClick={() => this.setState({ count: this.state.count + 1 })}>Increase</button>
</div>
);
}
}
export default Counter;
函数组件(Function Component):
函数组件可以使用hooks(React 16.8+)来管理内部状态。
useState钩子:
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increase</button>
</div>
);
}
export default Counter;
useReducer钩子(适用于复杂的状态逻辑):
import React, { useReducer } from 'react';
function Counter() {
const [count, dispatch] = useReducer((state, action) => {
switch (action.type) {
case 'increment':
return state + 1;
case 'decrement':
return state - 1;
default:
throw new Error();
}
}, 0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => dispatch({ type: 'increment' })}>Increase</button>
<button onClick={() => dispatch({ type: 'decrement' })}>Decrease</button>
</div>
);
}
export default Counter;
3、生命周期
类组件:
类组件生命周期(三个阶段:挂载阶段,更新阶段,卸载阶段)
挂载阶段执行顺序 :constructor->componentWillMount->render->componentDidMount
更新阶段执行顺序: shouldComponentUpdate->componentWillUpdate->render->componentDidUpdate
销毁阶段: componentWillUnmount
import React from "react";
import {Link} from 'react-router-dom'
class Demo extends React.Component{
constructor(props){
super(props)
console.log("constructor")
}
state = {
num:1
}
UNSAFE_componentWillMount(){
console.log("componentWillMount")
}
componentDidMount(){
console.log("componentDidMount")
}
shouldComponentUpdate(){
console.log('shouldComponentUpdate')
return true
}
UNSAFE_omponentWillUpdate(){
console.log("componentWillUpdate")
}
componentDidUpdate(){
console.log("componentDidUpdate")
}
componentWillUnmount(){
console.log("componentWillUnmount")
}
Submit = () => {
this.setState({num:this.state.num+=1})
}
render(){
console.log('render')
return(
<>
<Link to='/app1'>App1</Link>
//这里替换成自己的即可
<h3>{this.state.num}</h3>
<button onClick={this.Submit}>改变</button>
</>
)
}
}
export default Demo
函数组件(Function Component):
函数组件本质没有生命周期,但是我们通过Hooks来模仿类组件当中的生命周期(也是三个阶段)
import { useState ,useEffect} from "react"
function App1 (){
const [username ,setUsername] = useState('')
const setChange = event => {
setUsername(event.target.value);
};
// useEffect = vue mounted 区别是只要视图更新就变化 感觉类似watch 但是他又是初始化的 时候第一个
// useEffect(()=>{},[])
useEffect(()=>{
console.log('模拟componentDidMount第一次渲染', username)
return () =>{
console.log('模拟componentWillUnmount执行销毁后')
}
},[username])
return(
<>
<input value={username} onChange={setChange}></input>
</>
)
}
export default App1
4、性能
React类组件和函数组件之间的性能对比主要关注以下几个方面:
角度 | 类组件 | 函数组件 |
渲染性能 | 在渲染时会进行shouldComponentUpdate生命周期检查 | 需要使用React.memo 或自定义比较逻辑来避免不必要的重渲染 |
状态更新 | 可以在shouldComponentUpdate 中实现更细粒度的更新检查 | 需要使用React.memo 或自定义比较逻辑来避免不必要的重渲染 |
组件的状态和生命周期复杂性 | 可能会引入更多的对象和函数,这可能会影响GC(垃圾回收) | - |
内存占用 | 因为其实例和可能的引用,可能会占用更多内存 | - |
5、可读性和维护性
可读性和维护性是评估代码质量的重要指标。
-
类组件的可读性和维护性可能不如函数组件。类组件中的this指向以及生命周期方法(如componentDidMount)可能会增加理解和维护的难度。
-
函数组件的可读性和维护性较好,因为它们就像纯函数,更接近于数学函数的定义,更容易理解和维护。
-
对于简单的组件,使用函数组件是首选,因为它们更简单且易于理解。
-
对于需要管理状态或生命周期事件的组件,类组件是必须的。
-
可以使用hooks(React 16.8+)来编写函数组件,它们可以让你在不编写类的情况下使用state和其他React特性。
如:类组件
class MyComponent 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>
);
}
}
函数组件(Function Component):
function MyComponent() {
const [count, setCount] = React.useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>Click me</button>
</div>
);
}
在这个例子中,函数组件MyComponent
通过React.useState hook管理了状态,使得它的定义更接近于类组件的行为,同时更易于阅读和维护。
6、上下文
类组件:可以通过this.context
访问上下文。需要在类组件上使用static contextType
声明期望访问的上下文,或者使用contextTypes
属性进行类型检查(使用React 16.6之前的API)。
import React, { Component } from 'react';
class MyClassComponent extends Component {
static contextType = MyContext; // 使用最新的context API
componentDidMount() {
const data = this.context; // 访问上下文
}
render() {
return <div>My Class Component</div>;
}
}
函数组件(Function Component):可以使用useContext
钩子从React获取上下文。
import React, { useContext } from 'react';
function MyFunctionComponent() {
const contextData = useContext(MyContext); // 使用hooks获取上下文
return <div>My Function Component</div>;
}
注意:useContext
只能在函数组件或者自定义钩子中使用。类组件不能使用这种方式访问上下文。
7、集成状态管理库
在React中,类组件和函数组件可以使用状态管理库来管理复杂的状态。常见的状态管理库有Redux、MobX、Context API等。
8、总结类组件、函数组件的优缺点
角度 | 类组件 | 函数组件 |
优点 |
|
|
缺点 |
|
|