Skip to content

函数组件模拟生命周期

创建方式

jsx
const Hello = (props)=>{
  return <div>{props.message}</div>
}
const Hello = props => <div>{props.message}</div>
function Hello(props){
  return <div>{props.message}</div>
}

函数组件没有 state,用的是 useState 函数组件没有生命周期,用到是 useEffect (React v16.8.0推出Hooks API)。

TIP

useEffect 的作用是解决问题

UseEffect

componentDidMount

模拟componentDidMount,设置为 [](即不使用任何响应式值) 表示只在第一次渲染的时候调用。

jsx
useEffect(()=>{console.log('use effect')},[])

componentDidUpdate

模拟componentDidUpdate[参数] 接受的参数(可以多个)表示依赖的响应式值,当依赖的值发生变化时会进行同步。

jsx
useEffect(()=>{console.log(' n和m change')})
useEffect(()=>{console.log(' n change')},[n])

componentWillUnmount

模拟componentWillUnmount,在 return 返回的函数,可以处理副作用。

jsx
useEffect(()=>{
  console.log('child渲染或变化了')
  return ()=>{ console.log('child消失了')}
})

constructor

函数组件执行的时候,就相当于 constructor

shouldComponentUpdate

React.memouseMemo 可以解决。

render

函数组件的返回值就是 render 的返回值。

useEffect 区别

没有依赖数组和使用空数组 [] 作为依赖组,行为是不同的。

jsx
useEffect(() => {
  // 这里的代码会在每次渲染后运行
});

useEffect(() => {
  // 这里的代码只会在组件挂载(首次出现)时运行
}, []);

useEffect(() => {
  // 这里的代码不但会在组件挂载时运行,而且当 a 或 b 的值自上次渲染后发生变化后也会运行
}, [a, b]);

Effect 会执行两次的问题

在React开发环境 useEffect 默认会执行两次,这是 React 18 引入的 严格模式(Strict Mode) 的故意设计行为,目的是帮助开发者提前发现潜在问题。

那么如何解决这个问题呢?

  1. 实现清理函数(推荐)
jsx
useEffect(() => {
const timer = setInterval(() => {
  console.log('Timer running');
}, 1000);

// 清理函数:必须实现!
  return () => clearInterval(timer); 
}, []); // 依赖数组为空,仅在挂载/卸载时运行

关键点

  • 始终编写清理函数 (return () => {...}),避免内存泄漏。

  • 确保 Effect 逻辑是幂等的(多次执行结果一致)。

  • 合理设置依赖数组([][state]),避免不必要的重复执行。

  1. 禁用严格模式(不推荐)
jsx
// 不推荐!仅用于临时调试
ReactDOM.createRoot(document.getElementById('root')).render(
  // <React.StrictMode>
    <App />
  // </React.StrictMode>
);

警告

失去 React 对潜在问题的检测能力,可能导致生产环境出现未清理的副作用。

  1. 使用 Ref 控制执行次数

通过 useRef 标记是否已执行,避免重复操作(如数据请求):

jsx
const hasFetched = useRef(false);
useEffect(() => {
  if (!hasFetched.current) {
    fetchData();
    hasFetched.current = true;
  }
}, []);

自定义Hook之useUpdate

模拟 componentDidUpdate 时,第一次渲染也会执行,消除第一次渲染需要自定一个 useUpdate

jsx
import {useEffect, useState} from "react"

const useUpdate = (fndep) => {
  const [countsetCount] = useState(0)
  useEffect(() => {
    setCount(x => x + 1)
  }, [dep])
  useEffect(() => {
    if (count > 1) {
      fn()
    setCount(x => x - 1)
    }
  }, [count, fn])
}
export default useUpdate

App.js 内调用自定义 useUpdate

jsx
import {useState} from "react"
import useUpdate  from "./useUpdate"
function App() {
  const [nsetN] = useState(0)
  const onclick = () => {setN(n + 1)}
  useUpdate(() => {console.log('number change')}, n);
  return (
    <div>{n}<button onClick={onclick}>+1</button></div>
  )
}
export default App;

参考链接

响应式 Effect 的生命周期

使用 Effect 进行同步

使用自定义 Hook 复用逻辑