学习React (3) - 组件进阶 02 函数组件通过使用各种 Hook 来实现类似的生命周期行为

66 阅读2分钟

React 函数组件 最初没有类组件那样的生命周期方法,但是自从 React 16.8 引入了 Hooks,函数组件也可以通过使用各种 Hook 来实现类似的生命周期行为。以下是一些常用的 Hook 及其用途:

useState

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

import React, { useState } from 'react';

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

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

useEffect

用于在函数组件中执行副作用操作,比如数据获取、订阅或手动更改DOM。它可以看作是 componentDidMountcomponentDidUpdatecomponentWillUnmount 的组合。

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

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

  // 类似于 componentDidMount 和 componentDidUpdate:
  useEffect(() => {
    // 使用浏览器API更新页面标题
    document.title = `You clicked ${count} times`;

    // 返回一个清理函数,类似于 componentWillUnmount
    return () => {
      console.log('Cleanup');
    };
  }, [count]); // 仅在 count 更改时重新运行

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

useContext

用于在函数组件中使用上下文,相当于类组件中的 contextTypeContext.Consumer

import React, { useContext } from 'react';

const ThemeContext = React.createContext('light');

function ThemedButton() {
  const theme = useContext(ThemeContext);
  return <button style={{ background: theme === 'dark' ? '#333' : '#FFF' }}>Themed Button</button>;
}

useReducer

用于在函数组件中管理复杂状态逻辑,相当于 Redux 的 reducer。

import React, { useReducer } from 'react';

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    case 'decrement':
      return { count: state.count - 1 };
    default:
      throw new Error();
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, { count: 0 });

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

useRef

用于在函数组件中引用DOM元素或存储一个可变值,这个值在整个组件生命周期内保持不变。

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

function TextInputWithFocusButton() {
  const inputEl = useRef(null);

  const onButtonClick = () => {
    // `current` 指向已挂载到 DOM 上的文本输入元素
    inputEl.current.focus();
  };

  return (
    <div>
      <input ref={inputEl} type="text" />
      <button onClick={onButtonClick}>Focus the input</button>
    </div>
  );
}

useMemo 和 useCallback

用于性能优化,通过缓存计算结果或函数避免不必要的重新计算或重新创建。

  • useMemo 用于缓存计算结果。

    import React, { useMemo } from 'react';
    
    function ExpensiveCalculationComponent({ a, b }) {
      const result = useMemo(() => {
        // 一些计算量大的操作
        return a + b;
      }, [a, b]);
    
      return <div>{result}</div>;
    }
    
  • useCallback 用于缓存函数。

    import React, { useCallback } from 'react';
    
    function ParentComponent() {
      const handleClick = useCallback(() => {
        // 一些处理操作
      }, []);
    
      return <ChildComponent onClick={handleClick} />;
    }
    

通过这些 Hooks,函数组件能够实现与类组件相同的功能,并且通常更简洁、易于理解和测试。