详解 React 常用的一些钩子函数(对比vue)

useState

(类似Vue里面的data)

用于在函数组件中添加状态。

返回一个包含当前状态值和更新状态值的数组。

import React, { useState } from 'react';

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

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}

useEffect 

(类似Vue里面的mounted、destroyed)

用于在函数组件中执行副作用操作(如数据获取、订阅、手动DOM操作等)。

接收一个函数,该函数包含副作用逻辑,可以返回一个清理函数用于处理cleanup。

import React, { useState, useEffect } from 'react';

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

  useEffect(() => {
    const fetchData = async () => {
      const response = await fetch('https://api.example.com/data');
      const result = await response.json();
      setData(result);
    };

    fetchData();

    // Cleanup 函数(可选)
    return () => {
      // 清理逻辑...
    };
  }, []); // 依赖项为空数组表示仅在组件挂载和卸载时运行
}

依赖项

useEffect的第二个参数是一个依赖项数组,用于指定哪些变量的变化会触发 useEffect 中的副作用函数的重新执行。这个依赖项数组的目的是帮助 Reac t优化性能,确保副作用函数仅在依赖项发生变化时执行,而不是在每次渲染时都执行。 

为什么需要依赖项数组?

避免重复执行: 如果没有依赖项数组,副作用函数会在每次组件重新渲染时都被调用,这可能导致不必要的性能开销。

处理异步操作和副作用: 在 useEffect 中,我们可能会涉及异步操作、订阅事件等副作用,而这些副作用可能与组件的状态或属性相关。使用依赖项数组可以确保我们在副作用函数中访问到的状态和属性是最新的。

依赖项数组的不同情况

空数组

如果依赖项数组为空,副作用函数仅在组件挂载和卸载时执行,相当于类似于类组件中的componentDidMountcomponentWillUnmount

 useEffect(() => {
   // 在组件挂载时执行
   return () => {
     // 在组件卸载时执行
   };
 }, []);

有依赖项

如果依赖项数组不为空,副作用函数将在组件挂载时执行一次,并在依赖项发生变化时执行。

    useEffect(() => {
      // 在组件挂载时执行
      // 在依赖项发生变化时执行
      return () => {
        // 在组件卸载时执行
      };
    }, [dependency1, dependency2]);

没有依赖项数组 

如果省略依赖项数组,副作用函数将在每次组件重新渲染时都执行,这可能导致性能问题和不必要的副作用。

    useEffect(() => {
      // 在每次组件重新渲染时执行
      return () => {
        // 在每次组件重新渲染时执行清理逻辑
      };
    });

注意事项

避免无限循环: 当使用依赖项数组时,确保依赖项数组中的变量不会在useEffect中被修改,否则可能导致无限循环。

不要滥用空依赖项数组: 虽然空依赖项数组可以确保useEffect仅在组件挂载和卸载时执行,但在一些情况下,可能需要仔细考虑是否真的需要空依赖项数组。

useMemo

(类似Vue里面computed)

useMemo用于记忆(缓存)计算结果,并在依赖项变化时重新计算。

这有助于避免不必要的重复计算,提高性能。

    import React, { useMemo } from 'react';

    function ExpensiveComponent({ prop1, prop2 }) {
      // 使用 useMemo 缓存计算结果
      const result = useMemo(() => {
        // 进行昂贵的计算或处理
        return prop1 + prop2;
      }, [prop1, prop2]); // 依赖项数组

      return <p>Result: {result}</p>;
    }

useCallback

(类似Vue里面watch)

用于缓存回调函数,避免在每次渲染时重新创建。

接收一个回调函数和依赖项数组,返回缓存后的回调函数。

useCallback的依赖项参数用于指定哪些变量的变化会导致生成新的回调函数。

   import React, { useState, useCallback } from 'react';

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

     const handleClick = useCallback(() => {
       // 使用 count 进行逻辑处理
       console.log(count);
     }, [count]);

     return (
       <div>
         <p>Count: {count}</p>
         <button onClick={() => setCount(count + 1)}>Increment</button>
         <ChildComponent onClick={handleClick} />
       </div>
     );
   }

   function ChildComponent({ onClick }) {
     // 使用缓存后的回调函数
     return <button onClick={onClick}>Click me</button>;
   }

在这个例子中,useCallback缓存了handleClick回调函数,并且指定了依赖项数组为[count]。这意味着只有当count发生变化时,handleClick才会生成新的回调函数。 

依赖项

为什么需要依赖项数组?

避免不必要的重新创建: 如果没有依赖项数组,每次组件重新渲染时都会生成新的回调函数,即使函数体内的逻辑不依赖于任何变量的变化。通过指定依赖项数组,可以控制在什么情况下生成新的回调函数。

确保闭包内的值是最新的: 如果回调函数内部引用了某些状态或属性,确保依赖项数组包含这些状态或属性,以确保闭包内的值是最新的。

注意事项

空依赖项数组:useEffect类似,如果依赖项数组为空,表示回调函数不依赖于任何外部变量,它将永远只生成一次。

    const handleClick = useCallback(() => {
      // 处理点击事件
    }, []); // 空依赖项数组

谨慎处理依赖项: 确保依赖项数组中的变量是正确的,否则可能导致回调函数不会在预期的时候重新生成。

性能考虑: 在大型应用中,使用useCallback可能有助于性能优化,但不要滥用。只有在明确存在性能问题时,才应该考虑使用useCallback

useReducer

(Vuex 中的 mutations)

虽然 useReducermutations 有一些区别,但它们都是用于管理组件状态的工具。

状态管理: useReducer 用于在函数组件中管理复杂的状态逻辑。它可以替代 useState,特别适用于处理具有复杂更新逻辑或依赖前一个状态的状态。

 import React, { useReducer } from 'react';
    const initialState = { count: 0 };

    const reducer = (state, action) => {
      switch (action.type) {
        case 'increment':
          return { count: state.count + 1 };
        case 'decrement':
          return { count: state.count - 1 };
        default:
          return state;
      }
    };

    function Counter() {
      const [state, dispatch] = useReducer(reducer, initialState);

      return (
        <div>
          <p>Count: {state.count}</p>
          <button onClick={() => dispatch({ type: 'increment' })}>Increment</button>
          <button onClick={() => dispatch({ type: 'decrement' })}>Decrement</button>
        </div>
      );
    }

useContext

(类似Vue里面的Provider)

用于在函数组件中访问上下文(context)。

上下文允许在组件树中直接传递数据,而不必通过逐层传递 props。

useContext 使得在组件中获取上下文数据变得非常方便。

创建上下文对象

首先,需要创建一个上下文对象,通过 React.createContext

    import React, { createContext } from 'react';

    const MyContext = createContext();

这将创建一个包含 ProviderConsumer 的上下文对象。Provider 用于提供上下文数据,而 Consumer 用于消费该数据。

使用 useContext 获取上下文数据

在组件中使用 useContext 钩子,传入上下文对象,即可获取上下文数据。

    import React, { useContext } from 'react';

    const MyComponent = () => {
      const contextValue = useContext(MyContext);

      return <p>{contextValue}</p>;
    };

在这个例子中,contextValue 就是从 MyContext 上下文中获取的值。

提供上下文数据

使用 Provider 组件来提供上下文数据。Provider 接收一个 value 属性,该属性的值将成为整个组件树中使用该上下文的组件能够获取的值。

    const App = () => {
      return (
        <MyContext.Provider value="Hello, Context!">
          <MyComponent />
        </MyContext.Provider>
      );
    };

 useRef

(类似Vue里面的ref)

用于在函数组件中获取对 DOM 元素或自定义组件实例的引用。

import React, { useRef, useEffect } from 'react';
 
function MyComponent() {
  // 创建一个 ref 对象
  const myRef = useRef(null);
 
  // 使用 ref 对象引用 DOM 元素
  useEffect(() => {
    myRef.current.focus();
  }, []);
 
  return <input ref={myRef} />;
}

原文链接:https://juejin.cn/post/7325255455289720866 作者:JacksonChen

(0)
上一篇 2024年1月19日 上午11:09
下一篇 2024年1月19日 下午4:00

相关推荐

发表回复

登录后才能评论