react函数组件怎么模拟类组件生命周期?一个 useEffect 搞定

react类组件

react16.8 推出之前,也就是2019年6月前,使用的是类组件。当然,现在基本上不使用它了,两者都用过的朋友们,应该能感受到类组件更加的复杂,但是在面试和学习过程中,提到它还是很有必要的,如果对于this指向与JavaScript中的类不太清楚的小伙伴可以提前熟悉一下。

一起走走this关键字走过的路------this的指向问题小美是一个白富美,她想在代码美如画的程序员小金面前介绍自己------你好, - 掘金

类组件的定义

react中规定了,类组件都必须继承React.ComponentReact.PureComponent,并且,在类的方法中,必须至少实现 render() 方法。由于我们今天主要是研究react函数组件如何模拟类组件的生命周期。接下来就着重介绍组件的渲染生命周期,走起。

一、基本定义

javascript 复制代码
import React from 'react';

class MyComponent extends React.Component {
    // 1. 构造函数(初始化)
    constructor(props) {
        super(props);
        this.state = '' // 初始值
        // 方法绑定
        this.handleClick = this.handleClick.bind(this);
    }
    // 2. 静态生命周期方法
    static getDerivedStateFromProps(props, state) {
        // 返回要更新的state或null
        return null;
    }
    componentWillMount() {
        // 组件挂载前
    }
    // 3. 渲染方法(必需)
    render() {
        return <div>组件内容</div>;
    }
    // 4. 组件挂载完成
    componentDidMount() {
        // DOM操作、数据请求等
    }

    // 更新阶段
    componentWillReceiveProps() {
    // 外部接受到新的propos时执行
    }
    getDerivedStateFromProps(){
    // 返回要更新的state或者null
    }
    shouldComponentUpdate(){

    }
    componentWillUpdate(){

    }   
    Render() { }
    componentDidUpdate() {
    }

    // 销毁阶段
    componentWillUnmount() {

    }   
}

很多生命周期已经在react 16.8之后被弃用了,我们使用useEffect来模拟类组件的生命周期只要关注这几个重要的,就能满足日常的封装组件,接下来看在函数组件中,只用useEffect如何模拟这些生命周期。

注:getDerivedStateFromProps存在时,componentWillMount、componentWillReceiveProps这两个生命周期不会执行。静态方法取代了实例方法,实际上是这个静态方法会阻止 willMountwillReceiveProps 的执行。

函数组件

函数组件相对来说,对我们近几年学习react开发的同学们比较熟悉,也就是JSX/TSX语法,一个普通JavaScript函数,返回一个React元素(描述DOM的普通JS对象)。

一、useEffect

可能很多伙伴会在面试中提到useEffect,相信大家都会这样回答:用于组件初始化数据获取、清除副作用函数、依赖第二个参数的变化再次执行这个useEffect......那么,它们分别对应了哪些,模拟了哪个生命周期呢?

1、componentDidMount

在组件挂载后执行,和useEffect传递入第二个参数空数组依赖等价,大多用于获取组件初始化数据,还有事件监听或者初始化第三方库组件实例。

javascript 复制代码
componentDidMount() {
  fetch('/api/data').then(data => this.setState({ data }));
}
// 函数组件
useEffect(() => {
  fetch('/api/data').then(data => setData(data));
}, []);
// 类组件
componentDidMount() {
  this.map = new MapLibre.Map({ container: 'map' });// 第三方组件,比如高德地图...
}

// 函数组件
useEffect(() => {
  const map = new MapLibre.Map({ container: 'map' });
}, []);

2、componentWillReceiveProps

组件更新传值后执行,和useEffect第二个参数依赖组件的props传参等价,用于propos变化时,重置组件状态,获取新的数据。

scala 复制代码
// 类组件
class MyComponent extends React.Component {
  componentWillReceiveProps(nextProps) {
    if (nextProps.userID !== this.props.userID) {
      this.setState({ userData: null });
      this.fetchUserData(nextProps.userID); // 根据新 props 请求数据
    }
  }
}
// 函数组件
function MyComponent({ userID }) {
  const [userData, setUserData] = useState(null);

  useEffect(() => {
    if (userID) {
      setUserData(null);
      fetchUserData(userID); // 根据 props.userID 变化请求数据
    }
  }, [userID]); // 依赖数组:仅在 userID 变化时执行

  return <div>{userData?.name}</div>;
}

3、componentDidUpdate

只要组件更新,就执行,相当于useEffect第二个参数什么不传。用于组件更新后需要同步DMO或者与不是React库(如谷歌地图)交互等情况使用。

4、computedWillUnmount

组件卸载时执行,在useEffect的第一个参数的返回值的箭头函数中执行。通常用于移除事件监听、移除定时器还有断开WebSocket连接等。

javascript 复制代码
//类组件
class MyComponent extends React.Component {
  componentDidMount() {
    this.timer = setInterval(() => {
      console.log("Timer tick");
    }, 1000);

    window.addEventListener("resize", this.handleResize);
  }

  componentWillUnmount() {
    clearInterval(this.timer); // 清除定时器
    window.removeEventListener("resize", this.handleResize); // 移除事件监听
  }

  handleResize = () => {
    console.log("Window resized");
  };

  render() {
    return <div>Check console for logs</div>;
  }
}
// 函数组件
function MyComponent() {
  useEffect(() => {
    // 1. 设置定时器(effect 主体)
    const timer = setInterval(() => {
      console.log("Timer tick");
    }, 1000);

    // 2. 添加事件监听
    const handleResize = () => console.log("Window resized");
    window.addEventListener("resize", handleResize);

    // 返回清理函数(会在卸载或依赖变化时执行)
    return () => {
      clearInterval(timer); // 清除定时器
      window.removeEventListener("resize", handleResize); // 移除事件监听
    };
  }, []); 
  return <div>111</div>;
}

5、getDerivedStateFromProps

组件初始化后,每次接受新的props时调用,根据新的props计算并返回一个对象更新state,或者返回null不更新,相当于useState传入箭头函数内部执行。实际要配合useEffect依赖state值实现,我们这里展示执行时机。

javascript 复制代码
// 类组件
 static getDerivedStateFromProps(nextProps, prevState) {
    if (nextProps.value !== prevState.prevValue) {
      return {
        derivedValue: nextProps.value * 2, // 根据 props 计算新的 state
        prevValue: nextProps.value,       // 保存上一次的 props 用于比较
      };
    }
    return null; // 不更新 state
  }
  
  // 函数组件
  function Com () {
     const [value,setValue] = useState(() =>{
         conslog.log("getDerivedStateFromProps")
     })
  }
相关推荐
百万蹄蹄向前冲2 小时前
秋天的第一口代码,Trae SOLO开发体验
前端·程序员·trae
努力奋斗12 小时前
VUE-第二季-02
前端·javascript·vue.js
路由侠内网穿透2 小时前
本地部署 SQLite 数据库管理工具 SQLite Browser ( Web ) 并实现外部访问
运维·服务器·开发语言·前端·数据库·sqlite
一只韩非子3 小时前
程序员太难了!Claude 用不了?两招解决!
前端·claude·cursor
JefferyXZF3 小时前
Next.js项目结构解析:理解 App Router 架构(二)
前端·全栈·next.js
gnip3 小时前
可重试接口请求
前端·javascript
若梦plus3 小时前
模块化与package.json
前端
烛阴3 小时前
Aspect Ratio -- 宽高比
前端·webgl
若梦plus4 小时前
Node.js中util.promisify原理分析
前端·node.js