本文介绍: React Hooks 是 React 16.8 版本引入的新特性,它们允许在函数组件使用状态和其他 React 特性useStateuseEffect,useContext,useReducer,useCallback,useMemo,useRef,useImperativeHandle,useLayoutEffect,useDebugValue

React Hooks 是 React 16.8 版本引入的新特性,它们允许在函数组件中使用状态和其他 React 特性。以下是一些主要的

React Hooks:

  1. useState: 是 React 的一个 Hook,它允许在函数组件中添加管理状态。在此之前,只有类组件才能拥有自己状态useState 返回一个包当前状态值和更新状态函数数组

基本用法如下

import React, { useState } from 'react';

function Example() {
  // 声明一个新的状态变量,其初始值为 0
  const [count, setCount] = useState(0);

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

这个例子中:

  1. useEffect: 是 React 的一个 Hook,它允许在函数组件中执行作用操作。这些副作用可能包括数据获取订阅手动更改 React 组件的 DOM 输出等。useEffect 可以看作是 componentDidMount, componentDidUpdate, 和 componentWillUnmount 生命周期方法组合

基本用法如下

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

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

  // 使用 Effect Hook监听 count 状态的变化
  useEffect(() => {
    document.title = `You clicked ${count} times`;

    return () => {
      // 清理工作(可选)
    };
  }, [count]); // 当依赖项数组中的值改变时,重新运行 effect

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

这个例子中:

  1. useContext: 是 React 的一个 Hook,它允许在函数组件中访问上下文对象。React 上下文 API 使得数据可以在组件树中传递而无需手动通过每个层级的 props

基本用法如下

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

// 创建一个新的 context 对象
const ThemeContext = createContext();

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

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

function ThemedButton() {
  // 使用 useContext 获取当前theme 值
  const theme = useContext(ThemeContext);

  return <button style={{ background: theme }}>Click me</button>;
}

这个例子中:

  1. useReducer: 是 React 的一个 Hook,它允许在函数组件中管理复杂的、可复用逻辑useReducer 接收一个 reducer 函数和初始状态作为参数,并返回当前的状态以及用于更新状态的 dispatch 方法

基本用法如下

import React, { useReducer } from 'react';

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

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

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

这个例子中:

  1. useCallback:` 是 React 的一个 Hook,它用于优化性能。当你在函数组件中使用内联回调例如事件处理器)时,每次渲染都会创建一个新的函数实例。这可能会导致不必要的子组件重新渲染,即使它们没有依赖于这些回调

    useCallback 接收两个参数:一个需要 memoize 的回调函数和一个依赖项数组。当依赖项数组中的值发生变化时,返回的 memoized 回调函数将会更新;否则,它会返回先前缓存版本

基本用法如下

import React, { useCallback } from 'react';

function Example({ a, b }) {
  // 使用 useCallback记住计算的值
  const memoizedCallback = useCallback(
    () => {
      console.log(a + b);
    },
    [a, b] // 当 a 或 b 变化时,重新计算
  );

  return (
    <button onClick={memoizedCallback}>
      Click me
    </button>
  );
}

这个例子中:

  • 我们定义了一个包含 ab加法操作回调函数,并通过 useCallback 返回了一个 memoized 版本

  • 如果 ab 的值发生变化,useCallback 将返回一个新的 memoized 回调函数;否则,它将返回先前缓存版本

  • 当用户点击按钮时,我们触发的是 memoized 回调函数。这样可以避免不必要的子组件重新渲染,因为除非 ab 的值变化,否则回调函数不会改变。

    注意,只有当你的回调函数被传递给子组件并且这个子组件执行shouldComponentUpdate() 或者使用了 React.memo() 时,useCallback 才能真正地提升性能。如果你的回调函数仅用于内部操作(如直接操作 DOM),那么使用 useCallback 不会带来任何好处。

  1. useMemo:是 React 的一个 Hook,它用于优化性能。当你在函数组件中执行昂贵的计算或者创建复杂对象时,每次渲染都会重新进行这些操作。这可能会导致不必要的性能开销。

    useMemo 接收两个参数:一个需要 memoize 的值(通常是返回结果)和一个依赖项数组。当依赖项数组中的值发生变化时,返回的 memoized 值将会更新;否则,它会返回先前缓存版本

    基本用法如下

import React, { useMemo } from 'react';

function Example({ a, b }) {
  // 使用 useMemo 来记住计算的值
  const memoizedValue = useMemo(() => {
    console.log('Computing expensive value...');
    return a + b;
  }, [a, b]); // 当 a 或 b 变化时,重新计算

  return <div>{memoizedValue}</div>;
}

在这个例子中:

  • 我们定义了一个包含 ab加法操作,并通过 useMemo 返回了一个 memoized 版本。

  • 如果 ab 的值发生变化,useMemo 将返回一个新的 memoized 值;否则,它将返回先前缓存的版本。

  • 每次渲染时,我们使用的是 memoized 值,而不是重新计算的结果

    注意,只有当你的计算结果传递给子组件并且这个子组件执行shouldComponentUpdate() 或者使用了 React.memo() 时,useMemo 才能真正地提升性能。如果你的计算结果仅用于内部操作(如直接操作 DOM),那么使用 useMemo 不会带来任何好处。

  1. useRef:是 React 的一个 Hook,它允许在函数组件中创建可变引用。这个 Hook 返回一个 ref 对象,其 .current 属性初始化传递参数initialValue)。返回的对象在整个组件生命周期内保持不变。

基本用法如下

import React, { useRef } from 'react';

function TextInputWithFocusButton() {
  // 创建一个 ref保存文本输入框的 DOM 元素
  const inputEl = useRef(null);

  const onButtonClick = () => {
    // 当按钮被点击时,使文本输入框获取焦点
    inputEl.current.focus();
  };

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

在这个例子中:

  1. useImperativeHandle: 是 React 的一个 Hook,它用于定制暴露给父组件的 ref 值。通常情况下,我们可以通过 ref 访问子组件内部的一些实例方法或属性。然而,在某些场景下,我们可能希望暴露一些特定的方法或属性,而不是默认的整个实例

基本用法如下

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

function FancyInput(props, ref) {
  const inputEl = useRef(null);

  // 使用 useImperativeHandle 来暴露 customMethod 给父组件
  useImperativeHandle(ref, () => ({
    focus: () => {
      inputEl.current.focus();
    },
    customMethod: () => {
      console.log('I am a custom method');
    }
  }));

  return <input ref={inputEl} type="text" />;
}

// 使用 forwardRef 将 ref 转发到 FancyInput 中
const WrappedFancyInput = forwardRef(FancyInput);

function ParentComponent() {
  const fancyInputRef = useRef(null);

  const handleClick = () => {
    // 在父组件中调用子组件的 customMethod 方法
    fancyInputRef.current.customMethod();
  };

  return (
    <>
      <WrappedFancyInput ref={fancyInputRef} />
      <button onClick={handleClick}>Call Custom Method</button>
    </>
  );
}

在这个例子中:

  • 我们创建了一个名为 FancyInput 的函数组件,并使用了 forwardRef 高阶函数来接收一个 ref 参数。

  • FancyInput 内部,我们使用 useImperativeHandle 来定义要暴露给父组件的方法和属性。这里我们暴露了 focuscustomMethod 方法。

  • 父组件通过 ref 属性将 ref 对象传递WrappedFancyInput 子组件。这样,父组件就可以通过 fancyInputRef.current 访问到子组件暴露的 focuscustomMethod 方法。

    注意,过度使用 useImperativeHandle 可能会导致代码难以理解和维护。因此,你应该尽量避免直接操作子组件的 DOM,而是尽可能地使用 React 的数据流进行通信

  1. useLayoutEffect: 是 React 的一个 Hook,它类似于 useEffect,但有两个关键的区别

    1. useLayoutEffect 在所有 DOM 变更之后同步调用,但在浏览器绘制之前。这使得你可以读取布局同步触发重新渲染。
    2. 服务器端渲染中,useLayoutEffect 不会被执行

基本用法如下

import React, { useLayoutEffect } from 'react';

function Example() {
  useLayoutEffect(() => {
    // 这里可以访问到最新的 DOM 样式几何信息
    console.log('DOM 已经更新,但我还没有被绘制');
  });

  return <div>Example</div>;
}

在这个例子中:

  1. useDebugValue:是 React 的一个 Hook,它用于在 React 开发者工具显示自定义 hook标签。这对于调试复杂自定义 hook 很有用。

基本用法如下:

import React, { useDebugValue } from 'react';

function useFriendStatus(friendID) {
  const [isOnline, setIsOnline] = useState(null);

  // 获取 friendID 对应的好友在线状态
  // ...

  // 使用 useDebugValue 来为这个 hook 显示一个可读的标签
  useDebugValue(isOnline ? '在线' : '离线');

  return isOnline;
}

function FriendStatus() {
  const isOnline = useFriendStatus(123456);

  return (
    <span>{isOnline ? '在线' : '离线'}</span>
  );
}

在这个例子中:

  • 我们创建了一个名为 useFriendStatus 的自定义 hook,它接收一个 friendID 参数,并返回好友的在线状态。

  • useFriendStatus 内部,我们使用 useDebugValue 来为这个 hook 显示一个可读的标签。这个标签将在 React 开发者工具的组件树中显示。

  • FriendStatus 组件中,我们调用了 useFriendStatus 并渲染了相应的在线状态。

    注意,useDebugValue 只在开发模式工作,并且只会影响 React 开发者工具中的展示。因此,在生产环境中,你不需要担心它会带来额外的性能开销。

这些是核心的 React Hooks,此外社区开发了许多其他的自定义 Hooks,例如 useDebounceuseThrottle 等,以解决特定的问题场景

原文地址:https://blog.csdn.net/weixin_46002631/article/details/134729728

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_30616.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注