react的hook总结

Hook 可以帮助在组件中使用不同的 React 功能。可以使用内置的 Hook 或使用自定义 Hook。本页列出了 React 中所有内置 Hook。

一. State Hook:状态hook

状态帮助组件** “记住”用户输入的信息**。例如,一个表单组件可以使用状态存储输入值,而一个图像库组件可以使用状态存储所选的图像索引。
1.使用 useState 声明可以直接更新的状态变量。

import React, { useState } from 'react';

function Counter() {
  // 声明一个状态变量count,初始值为0
  const [count, setCount] = useState(0);
  return (
    <button onClick={() => setCount(count + 1)}>增加</button>
  );
}

2.使用 useReducer 在 reducer 函数 中声明带有更新逻辑的 state 变量。

import React, { useReducer } from 'react';

// 定义reducer函数
function counterReducer(state, action) {
  switch (action.type) {
    case 'INCREMENT':
      return { count: state.count + 1 };
    case 'SET':
      return { count: action.payload };
    default:
      throw new Error('未知操作类型');
  }
}
function Counter() {
  // 使用useReducer,第一个参数是reducer函数,第二个参数是初始状态
  const [state, dispatch] = useReducer(counterReducer, { count: 0 });

  return (
    <div>
      <p>当前计数: {state.count}</p>
      <button onClick={() => dispatch({ type: 'INCREMENT' })}>增加</button>
      <button onClick={() => dispatch({ type: 'SET', payload: 10 })}>
        设为10
      </button>
    </div>
  );
}

二.Context Hook:上下文hook

上下文帮助组件从祖先组件接收信息,而无需将其作为 props 传递。例如,应用程序的顶层组件可以借助上下文将 UI 主题传递给所有下方的组件,无论这些组件层级有多深。
使用 useContext 读取订阅上下文。

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

// 1. 创建Context对象
const ThemeContext = createContext();

function App() {
  const [theme, setTheme] = useState('light');

  return (
    // 2. 使用Provider提供值
    <ThemeContext.Provider value={{ theme, setTheme }}>
      <Toolbar />
    </ThemeContext.Provider>
  );
}

function Toolbar() {
  return (
    <div>
      <ThemedButton />
    </div>
  );
}

function ThemedButton() {
  // 3. 在子组件中使用useContext获取值
  const { theme, setTheme } = useContext(ThemeContext);
  
  return (
    <button 
      onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}
      style={{
        background: theme === 'light' ? '#fff' : '#333',
        color: theme === 'light' ? '#000' : '#fff'
      }}
    >
      当前主题: {theme} (点击切换)
    </button>
  );
}

三.Ref Hook

ref 允许组件 保存一些不用于渲染的信息,比如 DOM 节点或 timeout ID。与状态不同,更新 ref 不会重新渲染组件。ref 是从 React 范例中的“脱围机制”。当需要与非 React 系统如浏览器内置 API 一同工作时,ref 将会非常有用。

1.使用 useRef 声明 ref。可以在其中保存任何值,但最常用于保存 DOM 节点。

import React, { useRef } from 'react';

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

  const onButtonClick = () => {
    // `current` 指向已挂载的 input 元素
    inputEl.current.focus();
  };

  return (
    <>
      <input ref={inputEl} type="text" />
      <button onClick={onButtonClick}>聚焦输入框</button>
    </>
  );
}

2.使用 useImperativeHandle 自定义从组件中暴露的 ref,但是很少使用。

import React, { useRef, useImperativeHandle, forwardRef } from 'react';

// 子组件
const FancyInput = forwardRef((props, ref) => {
  const inputRef = useRef();
  
  useImperativeHandle(ref, () => ({
    focus: () => {
      inputRef.current.focus();
    },
    getValue: () => {
      return inputRef.current.value;
    },
    setValue: (value) => {
      inputRef.current.value = value;
    }
  }));
  
  return <input ref={inputRef} />;
});

// 父组件
function Parent() {
  const fancyInputRef = useRef();
  
  const handleClick = () => {
    fancyInputRef.current.focus();
    fancyInputRef.current.setValue('Hello');
    console.log(fancyInputRef.current.getValue());
  };
  
  return (
    <div>
      <FancyInput ref={fancyInputRef} />
      <button onClick={handleClick}>操作输入框</button>
    </div>
  );
}

四.Effect Hook

useEffect是 React Hooks 中用于处理副作用的钩子函数。

import { useState, useEffect } from 'react';

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

  // 类似于 componentDidMount 和 componentDidUpdate
  useEffect(() => {
    // 更新文档标题
    document.title = `You clicked ${count} times`;
  });

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

useEffect 有两个很少使用的变换形式,它们在执行时机有所不同:

  • useLayoutEffect 在浏览器重新绘制屏幕前执行,可以在此处测量布局。
  • useInsertionEffect 在 React 对 DOM 进行更改之前触发,库可以在此处插入动态 CSS。

五.性能 Hook

优化重新渲染性能的一种常见方法是跳过不必要的工作。例如,可以告诉 React 重用缓存的计算结果,或者如果数据自上次渲染以来没有更改,则跳过重新渲染。

1.使用 useMemo 缓存计算代价昂贵的计算结果。

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

function ExpensiveCalculationComponent() {
  const [count, setCount] = useState(0);
  const [inputValue, setInputValue] = useState('');

  // 一个昂贵的计算函数
  const expensiveCalculation = (num) => {
    console.log('Calculating...');
    for (let i = 0; i < 1000000000; i++) {} // 模拟耗时操作
    return num * 2;
  };

  // 使用 useMemo 缓存计算结果
  const calculatedValue = useMemo(() => {
    return expensiveCalculation(count);
  }, [count]); // 只有 count 变化时才会重新计算

  return (
    <div>
      <h2>useMemo 示例</h2>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>增加 Count</button>
      
      <p>计算后的值: {calculatedValue}</p>
      
      <input
        value={inputValue}
        onChange={(e) => setInputValue(e.target.value)}
        placeholder="输入一些内容"
      />
      <p>输入的内容: {inputValue}</p>
    </div>
  );
}

export default ExpensiveCalculationComponent;

2.使用 useCallback 将函数传递给优化组件之前缓存函数定义。

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

function CounterWithCallback() {
  const [count, setCount] = useState(0);
  const [otherState, setOtherState] = useState(false);

  // 不使用 useCallback - 每次渲染都会创建新函数
  // const increment = () => {
  //   setCount(count + 1);
  // };

  // 使用 useCallback 缓存函数
  const increment = useCallback(() => {
    setCount(prevCount => prevCount + 1);
  }, []); // 空依赖数组表示函数不依赖任何外部值

  const toggleOtherState = () => {
    setOtherState(prev => !prev);
  };

  return (
    <div>
      <h2>useCallback 示例</h2>
      <p>Count: {count}</p>
      <button onClick={increment}>增加 Count</button>
      
      <p>Other State: {otherState.toString()}</p>
      <button onClick={toggleOtherState}>切换 Other State</button>
      
      <MemoizedChildComponent onIncrement={increment} />
    </div>
  );
}

// 使用 React.memo 优化的子组件
const MemoizedChildComponent = React.memo(function ChildComponent({ onIncrement }) {
  console.log('子组件渲染了');
  return (
    <div style={{ marginTop: '10px' }}>
      <button onClick={onIncrement}>从子组件增加 Count</button>
    </div>
  );
});

export default CounterWithCallback;
  • useMemo 缓存计算结果
  • useCallback 缓存函数本身

有时由于屏幕确实需要更新,无法跳过重新渲染。在这种情况下,可以通过将必须同步的阻塞更新(比如使用输入法输入内容)与不需要阻塞用户界面的非阻塞更新(比如更新图表)分离以提高性能。

useTransition 允许将状态转换标记为非阻塞,并允许其他更新中断它。
useDeferredValue 允许延迟更新 UI 的非关键部分,以让其他部分先更新。

六.资源 Hook

资源可以被组件访问,而无需将它们作为状态的一部分。例如,组件可以从 Promise 中读取消息,或从上下文中读取样式信息。

use 允许读取像 Promise 或 上下文 这样的资源的值。

function MessageComponent({ messagePromise }) {
  const message = use(messagePromise);
  const theme = use(ThemeContext);
  // ...
}

七.其他 Hook

  • 使用 useDebugValue 自定义 React 开发者工具为自定义 Hook 添加的标签。
  • 使用 useId 将唯一的 ID 与组件相关联,其通常与可访问性 API 一起使用。
  • 使用 useSyncExternalStore 订阅外部 store。

八.自定义 Hook

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值