MST

星途 面试题库

面试题:React Hooks 中 useEffect 的执行机制及应用场景

请详细阐述 useEffect 这个 Hook 的执行时机、依赖数组的作用,以及在实际项目中常见的使用场景有哪些。比如如何使用 useEffect 来处理数据获取、DOM 操作等场景。
37.0万 热度难度
前端开发React

知识考点

AI 面试

面试题答案

一键面试

useEffect 的执行时机

  1. 首次渲染后执行:当组件第一次渲染到 DOM 中后,useEffect 中的回调函数会被执行。这使得我们可以在组件挂载后执行一些副作用操作,比如订阅事件、获取数据等。
  2. 每次更新后执行:在组件后续的更新中(无论是由于 props 变化还是 state 变化导致的更新),useEffect 的回调函数会再次执行。这保证了在每次数据变化后,相关的副作用操作都能重新执行以保持最新状态。
  3. 可以控制执行时机:通过传递依赖数组,可以控制 useEffect 回调函数的执行时机。如果依赖数组为空 [],则 useEffect 只会在组件挂载和卸载时执行,不会在每次更新时执行。如果依赖数组包含某些值,只有当这些值发生变化时,useEffect 才会执行。

依赖数组的作用

  1. 控制副作用的执行频率:如上述提到,通过指定依赖数组,我们可以决定 useEffect 在何时执行。这对于优化性能非常重要,避免不必要的副作用执行。例如,如果 useEffect 中执行的是一个昂贵的操作(如 API 调用),通过合理设置依赖数组,可以避免在无关数据变化时重复执行该操作。
  2. 确保数据一致性:依赖数组中的值代表了 useEffect 中副作用操作所依赖的数据。当这些数据变化时,useEffect 执行以更新相关的状态或 DOM,从而确保应用程序状态和 DOM 与最新的数据保持一致。

实际项目中常见的使用场景

  1. 数据获取
    import React, { useState, useEffect } from'react';
    
    const DataFetchingComponent = () => {
        const [data, setData] = useState(null);
        useEffect(() => {
            const fetchData = async () => {
                const response = await fetch('https://example.com/api/data');
                const result = await response.json();
                setData(result);
            };
            fetchData();
        }, []);
        return (
            <div>
                {data? <p>{JSON.stringify(data)}</p> : <p>Loading...</p>}
            </div>
        );
    };
    
    export default DataFetchingComponent;
    
    在这个例子中,useEffect 只在组件挂载时执行一次,因为依赖数组为空。它执行数据获取操作,并将获取到的数据设置到 state 中。
  2. DOM 操作
    import React, { useEffect } from'react';
    
    const DOMManipulationComponent = () => {
        useEffect(() => {
            const element = document.getElementById('my-element');
            if (element) {
                element.style.color = 'blue';
            }
            return () => {
                if (element) {
                    element.style.color = 'initial';
                }
            };
        }, []);
        return <div id="my-element">Some text</div>;
    };
    
    export default DOMManipulationComponent;
    
    这里 useEffect 在组件挂载后获取 DOM 元素并修改其样式。返回的函数是清理函数,在组件卸载时恢复元素的初始样式。
  3. 事件监听
    import React, { useEffect } from'react';
    
    const EventListenerComponent = () => {
        const handleScroll = () => {
            console.log('Window scrolled');
        };
        useEffect(() => {
            window.addEventListener('scroll', handleScroll);
            return () => {
                window.removeEventListener('scroll', handleScroll);
            };
        }, []);
        return <div>Scroll the window to see the log</div>;
    };
    
    export default EventListenerComponent;
    
    useEffect 在组件挂载时添加滚动事件监听器,并在组件卸载时移除监听器,防止内存泄漏。
  4. 根据 prop 变化进行操作
    import React, { useEffect } from'react';
    
    const PropDependentComponent = ({ id }) => {
        useEffect(() => {
            console.log(`Prop 'id' changed to: ${id}`);
            // 这里可以执行依赖于 id 的操作,如根据 id 获取特定数据
        }, [id]);
        return <div>{id}</div>;
    };
    
    export default PropDependentComponent;
    
    id prop 变化时,useEffect 会执行,从而可以进行依赖于 id 的操作。