认识React Hooks:useEffect

本文通过React源码剖析了useEffectHook的工作机制,包括如何利用Fiber架构调度副作用,条件执行、清理操作、useRef的应用以及与useContext和useReducer的结合。同时介绍了如何通过useMemo和useCallback优化性能。
摘要由CSDN通过智能技术生成

要更详细地理解React中的useEffect Hook,我们可以通过查看一些核心代码来深入分析。以下是useEffect在React源码中的一个简化版本,它展示了useEffect是如何工作的:

// React内部的Hook结构
const Hook = {
  memoizedState: null,     // 保存Hook的状态
  baseState: null,         // 初始状态
  baseUpdate: null,        // 初始更新
  queue: null,             // 更新队列
  next: null               // 链接到下一个Hook
};

// 调度更新的函数
function scheduleUpdateOnFiber(fiber, lane, eventTime) {
  // ...调度更新逻辑
}

// useEffect的实现
function useEffect(create, deps) {
  const fiber = currentlyRenderingFiber; // 当前渲染的Fiber节点
  const hook = mountWorkInProgressHook(); // 挂载Hook

  // 依赖项检查
  const nextDeps = deps === undefined ? null : deps;
  let destroy = undefined;

  if (currentHook) {
    // 获取上一次的依赖项
    const prevDeps = currentHook.memoizedState[1];
    if (areHookInputsEqual(nextDeps, prevDeps)) {
      // 依赖项没有变化,跳过effect
      return;
    }
    // 获取上一次的销毁函数
    destroy = currentHook.memoizedState[0];
  }

  // 将副作用推入副作用链表
  hook.memoizedState = pushEffect(
    HookHasEffect | HookPassive, // 标志位,表示这是一个有副作用的Passive effect
    create,                      // 创建副作用的函数
    destroy,                     // 清理副作用的函数
    nextDeps                     // 依赖项数组
  );

  // 调度更新
  scheduleUpdateOnFiber(fiber, UpdateLanes, eventTime);
}

// 检查输入是否相等的函数
function areHookInputsEqual(nextDeps, prevDeps) {
  // ...比较逻辑
}

// 将副作用推入链表的函数
function pushEffect(tag, create, destroy, deps) {
  // ...推入逻辑
}

在这个简化的源码中,我们可以看到useEffect是如何利用React的Fiber架构来调度和执行副作用的。useEffect会在组件渲染后将副作用函数和清理函数推入一个链表中,React会在适当的时机执行这些副作用。
在React中,useEffect Hook允许你在函数组件中执行副作用操作。

  1. 条件执行:只在特定变量改变时执行useEffect
import React, { useState, useEffect } from 'react';

function MyComponent() {
  const [count, setCount] = useState(0);

  // 仅在count变化时执行
  useEffect(() => {
    document.title = `You clicked ${count} times`;
  }, [count]); // 依赖项数组

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}
  1. 清理函数:组件卸载前执行清理操作。
import React, { useState, useEffect } from 'react';

function MyComponent() {
  useEffect(() => {
    // 设置事件监听
    window.addEventListener('resize', handleResize);

    // 清理函数
    return () => {
      window.removeEventListener('resize', handleResize);
    };
  }, []); // 空依赖项数组表示仅在挂载和卸载时执行

  function handleResize() {
    // ...
  }

  // ...
}
  1. 跳过首次执行:使用useRef来跳过组件挂载时的副作用执行。
import React, { useState, useEffect, useRef } from 'react';

function MyComponent() {
  const firstUpdate = useRef(true);

  useEffect(() => {
    if (firstUpdate.current) {
      firstUpdate.current = false;
      return;
    }

    // 你的副作用逻辑
  });

  // ...
}
  1. 自定义Hook:封装复杂逻辑。
import React, { useState, useEffect } from 'react';

function useCustomHook() {
  const [data, setData] = useState(null);

  useEffect(() => {
    fetchData().then(setData);
  }, []);

  return data;
}

function MyComponent() {
  const data = useCustomHook();

  // 使用data渲染组件
}
  1. useContextuseReducer结合useEffect可以与其他Hook结合使用。
import React, { useContext, useEffect } from 'react';
import MyContext from './MyContext';

function MyComponent() {
  const value = useContext(MyContext);

  useEffect(() => {
    // 使用上下文值的副作用逻辑
  }, [value]);

  // ...
}
  1. 优化性能:使用useMemouseCallback减少不必要的渲染。
import React, { useState, useEffect, useCallback } from 'react';

function MyComponent() {
  const [count, setCount] = useState(0);

  const increment = useCallback(() => {
    setCount(c => c + 1);
  }, []);

  useEffect(() => {
    // 使用increment的副作用逻辑
  }, [increment]);

  // ...
}

以上就是一些useEffect的认识。希望通过这篇文章,你可以更好地理解如何在React应用中有效地使用useEffect Hook。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值