React Hooks常用的几个钩子函数

目录

1. useState

2. useEffect

3. useContext

4. useReducer

5. useMemo 和 useCallback

6. useRef

7. useLayoutEffect

8. 自定义 Hook


在 React 16.8 版本中引入了 Hooks,它是一项新的特性,使得我们在函数组件中可以使用状态(state)和其他 React 特性,而无需编写类组件。

Hook 是一些可以让你在函数组件中“钩入” React 状态及生命周期等特性的函数,它可用于增强函数组件的功能,以解决类组件难以解决的问题。

1. useState

在 React 中,我们可以使用 useState Hook 来管理函数组件的内部状态。

useState 是一种 Hook,它接收一个初始状态值,并返回一个由当前状态值以及一个更新状态值的函数组成的数组。通常,我们将 useState 的返回值解构为数组的形式,然后使用 ES6 数组解构的方式获取当前状态值和更新状态值的函数。

以下是一个简单的例子,在函数式组件中使用 useState Hook 管理计数器的状态:

import React, { useState } from 'react'

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

  return (
    

Count: {count}

) } export default Counter

在上面的例子中,我们先引入 React 和 useState Hook,然后在 Counter 组件中调用 useState Hook,初始化计数器的状态值为 0。然后通过解构赋值的方式获取 count 和 setCount 两个值。count 表示当前状态的值,setCount 表示更新状态的函数。

在 JSX 中,我们可以通过 { count } 的方式引用当前状态值,通过 { () => setCount(count + 1) } 的方式更新状态值。在点击 +1 或 -1 按钮后,setCount 会将当前状态值 +1 或 -1,从而重新渲染组件,这时计数器的值会更新。每次更新状态后,React 都会重新渲染组件使其展示新的页面。

2. useEffect

在 React 中,有一些生命周期函数是仅限于类组件中使用的,但是在函数组件中同样具有重要的作用。为了解决这一问题,React 16.8 版本中引入了 useEffect Hook,让我们得以在函数式组件中处理类组件中的一些生命周期函数。

useEffect 会在每次组件渲染完成后执行,并通过副作用函数来处理任务,类似于 componentDidMount、componentDidUpdate 和 componentWillUnmount 这三个生命周期函数的结合体。

下面是一个简单的例子,在函数式组件中使用 useEffect Hook,在组件渲染后打印一条信息:

import React, { useEffect } from 'react';

function Example() {
  useEffect(() => {
    console.log('Component mounted')
  }, []);

  return 

Hello, World!

; } export default Example;

在上面的例子中,我们首先引入了 React 和 useEffect Hook。然后在 Example 组件中使用了 useEffect Hook,并在 useEffect 中定义了函数打印一条信息“Component mounted”。

为了指定我们的副作用函数只运行一次,我们传递了一个空数组[](这个数组也叫做依赖数组)作为 useEffect 的第二个参数。如果 useEffect 函数中的状态值或 props 值发生变化,React 将重新运行我们的副作用函数。

为了演示 useEffect 运行多次的情况,我们将 useState Hook 用于 Example 组件中的状态:

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

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

  useEffect(() => {
    console.log(`Component updated: ${count}`)
  });

  return (
    

Count: {count}

); } export default Example;

在这个例子中,我们在组件中添加了一个计数器状态。在每次渲染完成后,useEffect 的副作用函数会被调用,因此在打点击 +1 或 -1 按钮时,控制台会印出新的 count 值,也就是说 useEffect 函数会在每次渲染中执行。

在函数组件中使用 useEffect,可以在不使用类组件的情况下复杂功能的开发,例如处理 Ajax 请求、WebSocket 连接、订阅和取消事件等等。使用 useEffect Hook 可以实现类似 compoenentDidMount、componntDidUpdate 和 componentWillUnmount 这三个生命周期函数的功能,让我们的代码更加简洁、易于理解和维护。

3. useContext

在 React 中,我们可以使用 useContext Hook 来实现在不同组件之间共享数据。在 React 应用程序中的任何组件内部,都可以通过 useContext Hook 访问上下文(context)中的全局状态。这让我们避免了将 props 一级一级地传递到每个组件中的情况。

当我们需要在应用程序中的多个组件之间共享状态时,我们可以创建一个上下文对象,然后在您的应用程序中使用该上下文对象。

以下是一个简单的例子,在 useContext Hook 中共享主题状态:

import React, { useContext } from 'react';

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

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

  return (
    
  );
}

function App() {
  return (
    
      
    
  );
}

export default App;

在上面的例子中,我们首先创建了一个名为 `ThemeContext` 的上下文对象,并将其设置为 `light`。然后,我们在 `ThemedButton` 组件中调用 `useContext` hook,并将上下文对象 `ThemeContext` 作为参数传递进去。这样,我们就可以在 `ThemedButton` 组件中访问 `ThemeContext` 上下文对象,从而在渲染时匹配 `background` 和 `color` 样式。

在 App 组件中,通过使用 `ThemeContext.Provider`,我们可以将主题设置为不同的 `dark`,从而使 `ThemedButton` 组件的样式改变。

4. useReducer

当组件状态越来越复杂,只使用 useState Hook 可能会变得非常困难。在这种情况下,可以使用 useReducer Hook 来管理组件的状态。在 React 中,useReducer Hook 可以帮助我们根据系统状态和任意动作来更新状态。

useReducer Hook 接收两个参数:reducer 和 state。reducer 是一个用于计算新状态的函数,而 state 则是一个初始状态值。当我们的应用程序中发生某些操作时,将会触发派发动作(dispatch action),这些动作基于操作类型和操作载荷(payload)。

以下是一个计数器示例,使用 useReducer Hook 来管理计数器组件的状态:

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

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

  return (
    <>
      

Count: {state.count}

); } export default Counter;

在上面的例子中,我们首先定义了一个 initialState 状态值,并定义一个 `reducer` 函数处理与计数器相关的所有操作,例如增加和减少计数器。在 `Counter` 组件内部,我们使用 `useReducer` Hook 将自定义计数器的 reducer 函数和 initialState 状态值传递进去,然后我们就可以使用 `useState` 的方式更改状态。

在计数器的加减操作中,我们通过派发 `dispatch` 函数中的 `type` 来更改组件的状态。如果 `type` 为 `increment`,则计数器将自增 1,如果 `type` 为 `decrement` 则计数器将自减 1。

5. useMemo 和 useCallback

React 组件的渲染过程是很耗费计算资源的,所以为了提高性能,我们需要尽可能地减少组件的渲染次数。当组件需要处理大量计算或者复杂的方法时,每次重新渲染都会浪费资源。为了避免这种情况,我们可以使用 useMemo 和 useCallback。

1. useMemo

useMemo Hook 可以用来缓存组件中的计算结果,并在下次渲染该组件时,重复使用该结果。这样可以避免重复计算,提高渲染速度。useMemo 接收两个参数:计算函数和依赖项数组。

例如,假设你有一个计算函数,它计算两个数的和。你可以使用 useMemo 来缓存计算结果,以提高性能:

const sum = useMemo(() => {
  console.log('calculate sum')  // 只有在依赖项改变时才会执行这行,否则会使用缓存的结果
  return num1 + num2
}, [num1, num2])


第一个参数是一个计算函数,useMemo 会在组件重新渲染时调用这个函数,并把计算结果缓存下来。第二个参数是一个依赖项数组,它包含了计算函数所依赖的变量。当依赖项发生变化时,useMemo 会重新计算计算函数的结果并缓存,否则它会直接返回缓存的结果。

2. useCallback

useCallback Hook 用于缓存函数,以免在每次渲染时创建新的函数实例。如果你的组件中有一个回调函数,在每次渲染时都需要更新,那么你可以使用 useCallback 来解决这个问题。

例如,你可以使用 useCallback 来缓存一个处理点击事件的函数:

const handleClick = useCallback(() => {
  console.log('click')
  // do something
}, [])

useCallback 同样接收两个参数:一个处理函数和一个依赖项数组。当依赖项的值不变时,useCallback 返回的处理函数不会更改。当依赖项的值更改时,useCallback 返回一个新的处理函数。

以上两种 Hook 一般都会被搭配使用。当你需要缓存一个计算结果和一个回调函数时,你可以同时使用 useMemo 和 useCallback 来提高组件性能。

6. useRef

在 React 中,组件的渲染通常是基于虚拟 DOM 的。可以通过“ref”将真实的 DOM 元素绑定到 React 组件上,从而在 React 中访问和操作 DOM,比如设置元素的样式、触发动画、获取元素的位置等等。

React 提供了三种不同类型的 Ref :

- createRef ,用于类组件。
- useRef ,用于函数组件中使用React Hooks。
- forwardRef ,用于在父组件中操作子组件中的元素引用时使用。

下面我们来看一个使用 useRef Hook 获取输入框元素的示例。首先,先在组件中定义一个 useRef ,类似于以下代码:

import React, { useRef } from 'react';

function Input() {
  const inputRef = useRef(null);

  const handleFocus = () => {
    inputRef.current.focus();
  };

  return (
    
); } export default Input;

这里,我们创建了一个 inputRef 来引用 Input 组件中的 input 元素,然后在输入框上添加 ref 属性,将其绑定到 inputRef。

当通过 onClick 事件调用 handleFocus 方法时,它会调用 inputRef.current.focus(),让输入框获取焦点。

通过这个例子,我们可以看到使用 useRef 来访问 DOM 元素非常简单并且易于使用。你可以在函数组件中使用它访问任何 DOM 元素。

7. useLayoutEffect

好的,让我来讲一下如何使用 useLayoutEffect Hook 处理 layout 和 paint 过程。

在 React 中,渲染过程分为三个步骤:reconciliation(协调)、layout(布局)和paint(绘制)。useLayoutEffect Hook 可以帮助我们在 layout 和 paint 过程之间同步更新 UI。

useLayoutEffect Hook 在渲染组件时同步处理 layout 和 paint 过程。它与 useEffect Hook 类似,但是它是在浏览器完成布局和绘制后同步执行,而不是在浏览器绘制完成后执行。这使得使用 useLayoutEffect 可以更精确地处理布局和绘制操作。

下面是一个示例,其中使用了 useLayoutEffect 来更新 DOM 元素的样式:

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

function LayoutEffectDemo() {
  const [color, setColor] = useState('red');
  const ref = useRef(null);

  useLayoutEffect(() => {
    ref.current.style.backgroundColor = color;
  }, [color]);

  return (
    
setColor(e.target.value)} />
Use Layout Effect
); } export default LayoutEffectDemo;

在此示例中,我们使用 useLayoutEffect 来更新元素的样式,并将其与 color 状态关联起来。当 color 发生变化时,useLayoutEffect 将被调用,它会更新 DOM 元素的背景颜色。

可以看到,通过使用 useLayoutEffect,我们可以更加准确地控制 UI 更新的时间点。即使在性能要求较高时,也能够及时响应用户操作。

8. 自定义 Hook

自定义 Hook 是一种将逻辑和状态抽象为可重用函数的技术。它可以将组件逻辑抽象为可处理单独功能的片段,并在多个组件之间共享这些片段。为了创建自定义 Hook,你只需要使用 React Hook,然后将其封装在一个函数中。

下面是一个示例,其中使用自定义 Hook useClickAway 封装了隐藏模态框的逻辑:

import { useEffect, useCallback } from 'react';

function useClickAway(ref, onClickAway) {
  const handleClick = useCallback(
    (event) => {
      // 如果点击的区域在 ref 内,不做处理
      if (ref.current && ref.current.contains(event.target)) {
        return;
      }
      // 点击的区域不在 ref 内,执行 onClickAway
      onClickAway();
    },
    [ref, onClickAway]
  );

  useEffect(() => {
    document.addEventListener('mousedown', handleClick);
    return () => {
      document.removeEventListener('mousedown', handleClick);
    };
  }, [handleClick]);
}

export default useClickAway;

在此示例中,我们创建了一个 useClickAway 自定义 Hook,该 Hook 接收两个参数:ref 和 onClickAway。ref 是对模态框的引用,onClickAway 是点击模态框以外区域时需要执行的回调函数。该 Hook 使用 useCallback 和 useEffect 来处理逻辑,并返回对模态框的引用。

使用这个自定义 Hook 我们可以在模态框组件中使用它来隐藏模态框,例如:

import React, { useRef, useState } from 'react';
import useClickAway from './useClickAway';

function Modal() {
  const [isOpen, setIsOpen] = useState(false);
  const modalRef = useRef(null);

  const closeModal = () => {
    setIsOpen(false);
  };

  useClickAway(modalRef, closeModal); // 在模态框组件中使用自定义 Hook

  return (
    
{isOpen && (

Modal

)}
); } export default Modal;

在此示例中,我们使用 useClickAway Hook 监听模态框外的点击事件,以便在用户点击模态框以外的区域时关闭模态框。使用自定义 Hook 的好处是,我们可以将模态框隐藏的逻辑、DOM 元素引用和事件处理程序封装在一个组件外,从而更好地实现组件复用和可维护性。

你可能感兴趣的:(React,前端,javascript,react.js,笔记,开发语言)