React Hooks 简介

195 阅读2分钟

什么是React Hooks?

React Hooks是让你在函数组件中使用React特性(如状态和生命周期方法)的函数。它们使代码更清晰、更简单。

为什么要引入Hooks?

React Hooks解决了类组件存在的几个问题:

  • 类的复杂性:

在类组件中管理生命周期和状态通常容易出错。Hooks简化了这一点。

  • 逻辑可重用性:

钩子使跨组件重用逻辑变得更容易,而不需要使用HOC或者 props。

  • 提高代码可读性:

钩子简化了组件代码,使其更短,更容易理解。

  • 增量采用:

钩子可以与类组件一起使用,允许逐步迁移。

React Hooks原理

React提供了几个钩子。让我们用例子来探索每一个。

useState

管理组件中的状态:

import React, { useState } from 'react';

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

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

export default Counter;

说明:

  • useState将状态变量count初始化为0。
  • setCount更新状态。

useEffect

处理副作用,如获取数据或更新DOM。

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

function Timer() {
    const [time, setTime] = useState(0);

    useEffect(() => {
        const interval = setInterval(() => setTime(t => t + 1), 1000);
        return () => clearInterval(interval); // Cleanup on unmount
    }, []); // Run once on mount

    return <p>Elapsed Time: {time}s</p>;
}

export default Timer;

说明:

  • 组件装载时,执行一次
  • 页面卸载时清除间隔

useContext

访问上下文

import React, { useContext, createContext } from 'react';

const ThemeContext = createContext('light');

function ThemedButton() {
    const theme = useContext(ThemeContext);

    return <button style={{ background: theme === 'dark' ? '#333' : '#fff' }}>I am {theme} themed</button>;
}

function App() {
    return (
        <ThemeContext.Provider value="dark">
            <ThemedButton />
        </ThemeContext.Provider>
    );
}

export default App;

说明:

  • useContext从最近的ThemeContext.Provider获取值

useReducer

管理复杂的状态逻辑:

import React, { useReducer } from 'react';

const initialState = { count: 0 };

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('Unknown action type');
    }
}

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>
    );
}

export default Counter;

说明:

  • useReducer管理复杂的状态判断。

useRef

持久化值或引用DOM节点。

import React, { useRef } from 'react';

function FocusInput() {
    const inputRef = useRef();

    const focus = () => inputRef.current.focus();

    return (
        <div>
            <input ref={inputRef} placeholder="Click button to focus" />
            <button onClick={focus}>Focus Input</button>
        </div>
    );
}

export default FocusInput;

说明:

  • ref提供对DOM元素的引用。

useMemo

惰性计算:

import React, { useMemo } from 'react';

function Factorial({ number }) {
    const factorial = useMemo(() => {
        const calculateFactorial = n => (n <= 1 ? 1 : n * calculateFactorial(n - 1));
        return calculateFactorial(number);
    }, [number]);

    return <p>Factorial of {number}: {factorial}</p>;
}

export default Factorial;

说明:

  • useMemo避免重新计算阶乘,除非数字发生变化。

useCallback

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

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

    const increment = useCallback(() => setCount(prev => prev + 1), []);

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

export default Counter;

说明:

  • 防止在重新渲染时不必要地重新创建。

useLayoutEffect

import React, { useState, useLayoutEffect, useRef } from 'react';

function Box() {
    const boxRef = useRef();
    const [color, setColor] = useState('blue');

    useLayoutEffect(() => {
        console.log('Box dimensions:', boxRef.current.getBoundingClientRect());
    }, [color]);

    return (
        <div>
            <div ref={boxRef} style={{ width: 100, height: 100, background: color }}></div>
            <button onClick={() => setColor(color === 'blue' ? 'red' : 'blue')}>Toggle Color</button>
        </div>
    );
}

export default Box;

说明:

  • useLayoutEffect确保在浏览器绘制之前计算DOM。

原文:dev.to/wafa_bergao…