react常用hooks,超细~

useState

  • 作用:

    • 让函数组件像类组件一样拥有自己的状态

      javascript 复制代码
      import React, { useState } from 'react';
      ​
      function Example() {
          const [count, setCount] = useState(() => {
              // 模拟复杂的计算
              const initialValue = 2 * 3;
              return initialValue;
          });
          
          setCount((oldValue)=>{
              return setCount+1;
          })
      ​
          return (
              <div>
                  <p>初始值为: {count}</p>
              </div>
          );
      }
      ​
      export default Example;
    • 参数说明:

      • useState:接收一个参数,作为状态的初始值,参数有两种形式,静态和动态

        • 静态值:直接传入一个具体的值作为状态的初始值,如字符串、数字等
        • 动态值:传入一个计算函数,计算函数的返回值会作为状态的初始值
      • setCount:接收一个参数,用来更新当前状态,参数也有两种形式,静态和动态

        • 静态值:传入也给值,用来替换原状态的值
        • 动态值:传入一个函数,函数接收一个参数(旧的状态值),函数的返回值用来替换原状态值

useEffect

  • 写法1:useEffect(callback)

    • 组件第一次渲染完毕之后,执行callback,等价于componentDidMount
    • 在每次组件更新完毕之后,也会执行callback,等价于componentDidUpdate
  • 写法2:useEffect(callback, [])

    • 只有在第一次渲染完毕之后,才会执行callback,以后每次更新完毕,不再执行
    • 类似于componentDidMount
  • 写法3:useEffect(callback, [依赖状态1,依赖状态2,...])

    • 第一次渲染完毕之后,会执行callback
    • 当某一个或者多个依赖发生变化时,callback会执行
    • 如果组件更新,但是依赖没有变化,callback不会执行
  • 写法4:

    scss 复制代码
    let [state,setSate] = useState(0)
    useEffect(()=>{
        //1、返回的内部函数,会在组件释放的时候执行
        //2、最常见的用法就是在这个函数里清除副作用
        return ()=>{
           
            console.log(state);//这里打印的state是组件更新之前的状态值
        }
    })
    • 写法1的执行一样,但是内部函数的执行时机见上面代码注释

useLayoutEffect与useEffect的区别

  1. useLayoutEffect是同步执行的,会在阻塞浏览器的渲染,会在 DOM 更新完成后,但是浏览器绘制之前执行。可以做:获取 DOM 的宽高、修改样式等操作;以防止页面出现闪烁、抖动,提高用户体验。由于其会阻塞页面的绘制,所有需要谨慎使用。
  2. useEffect是异步执行的,不会阻塞浏览器的渲染,用户可以先看到页面的更新,然后 useEffect 的回调函数再开始执行。所有它比较适合处理一些不影响页面渲染的副作用,比如请求数据等。

useMemo

用来缓存复杂计算的结果,只要依赖项没有发生变化,结果就不会重新计算,可以提高性能。

ini 复制代码
const memoizedValue = useMemo(() => {
  // 进行一些复杂的计算
  return computedValue;
}, [dependency1, dependency2, ...]);
  • 参数:

    • 参数1:传入回调函数,组件初次渲染时调用,当依赖项发生变化时重新调用,返回计算的结果,会作为useMemo的返回结果保存起来
    • 参数2:传入一个数组,数组元素是依赖项,当任意一个依赖项发生改变时,useMemo都会重新调用回调函数,计算结果;如果传入的是一个空数组[],则useMemo的回调函数只会在组件初次渲染时调用一次;如果不传递第二个参数,组件每次渲染都会执行一次回调函数,也就失去了使用useMemo来优化性能的意义。
  • 返回值:useMemo返回的是回调函数的返回值,并将这个值缓存起来。

useMemo与useEffect的区别

  • 参数

    • useMemo与useEffect的参数一样
  • 返回值

    • useMemo返回传入回调函数的返回值,并把这个值缓存起来,避免不必要的重复计算
    • useEffect可以返回一个清理函数,在组件卸载或下一次副作用执行之前调用,用于清除副作用(清除定时器、取消事件订阅等)
  • 执行时机

    • useEffect渲染之后异步执行,也就是说组件渲染完成,页面更新到屏幕上,然后useEffect的回调函数才会执行;为了避免副作用阻塞页面的渲染过程。
    • useMemo在渲染期间同步执行,当组件渲染时,useMemo会立即检查依赖项是否发生变化,如果没有发生变化,就直接返回之前的结果,如果发生了变化,就重新计算结果并且更新缓存。
  • 应用场景

    • useEffect应用处理副作用操作,比如获取数据、事件订阅、定时器、修改DOM等
    • useMemo用来处理复杂计算,并且缓存结果,提高性能。

useCallback

函数组件每次重新渲染时,其内部定义的函数都会被重新创建;如果这个函数被传递给子组件,可能会导致子组件不必要的更新,即使函数的逻辑并没有发生变化;useCallbaack可以帮我们记住函数的引用,只有当依赖项发生变化时,才会重新创建函数,从而避免子组件不必要的渲染。

javascript 复制代码
import React, { useState, useCallback } from 'react';
​
// 子组件
const ChildComponent = React.memo(({ onClick }) => {
  return <button onClick={onClick}>点击我</button>;
});
​
function ParentComponent() {
  const [count, setCount] = useState(0);
​
  // 使用 useCallback 记忆化函数
  const handleClick = useCallback(() => {
    setCount(count + 1);
  }, [count]);
​
  return (
    <div>
      <p>计数: {count}</p>
      <ChildComponent onClick={handleClick} />
    </div>
  );
}
​
export default ParentComponent;

useCallback与useMemo对比

  • 参数

    • useCallback与useMemo的参数一样
  • 作用

    • useCallback用来记忆函数的引用
    • useMemo用来缓存计算结果
    • 都可以用来优化性能

useContext

react应用中的数据一般是通过props来传递的,但是如果组件层级非常深的情况下,使用起来比较繁琐,useContext结合React.createContext,可以在任意下级组件中共享数据,不需要再层层传递。

  • 创建context
javascript 复制代码
import React from 'react';
​
// 创建一个上下文对象,初始值为 null
const MyContext = React.createContext(null);
​
export default MyContext;
  • 提供上下文数据

    javascript 复制代码
    import React from 'react';
    import MyContext from './MyContext';
    ​
    const ParentComponent = () => {
        const sharedData = {
            message: 'Hello from context',
            count: 10
        };
    ​
        return (
            <MyContext.Provider value={sharedData}>
                {/* 子组件 */}
                <ChildComponent />
            </MyContext.Provider>
        );
    };
    ​
    export default ParentComponent;
  • 子组件中使用useContext

    javascript 复制代码
    import React, { useContext } from 'react';
    import MyContext from './MyContext';
    ​
    const ChildComponent = () => {
        // 使用 useContext 获取上下文数据
        const contextData = useContext(MyContext);
    ​
        return (
            <div>
                <p>{contextData.message}</p>
                <p>Count: {contextData.count}</p>
            </div>
        );
    };
    ​
    export default ChildComponent;

useReducer

它是 useState 的替代方案,适用于管理复杂的状态逻辑;

scss 复制代码
const [state, dispatch] = useReducer(reducer, initialArg, init);
  • 参数:

    • reducer :是一个纯函数,接收两个参数:当前状态 state 和一个动作 action,并返回一个新的状态。其形式通常为 (state, action) => newState
    • initialArg:初始状态值,或者用于初始化状态的参数。
    • init (可选):是一个初始化函数,用于惰性初始化状态。如果提供了 init 函数,初始状态将是 init(initialArg) 的返回值。
  • 返回值

    • state:当前状态值
    • dispatch:一个函数,用于触发状态更新,接收一个动作 action 作为参数。
  • 使用

    javascript 复制代码
    import React, { useReducer } from 'react';
    
    // 定义 reducer 函数
    const counterReducer = (state, action) => {
        switch (action.type) {
            case 'increment':
                return { count: state.count + 1 };
            case 'decrement':
                return { count: state.count - 1 };
            default:
                return state;
        }
    };
    
    function Counter() {
        // 使用 useReducer 初始化状态
        const [state, dispatch] = useReducer(counterReducer, { count: 0 });
    
        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;

useRef

  • 保存可变值 :它可以创建一个可变的对象,在组件的整个生命周期内保持不变。每次组件重新渲染时,useRef 返回的对象都是同一个,你可以通过修改该对象的 current 属性来存储和读取数据,并且不会触发组件的重新渲染。

  • 获取 DOM 节点 :可以通过 useRef 来引用 DOM 元素,从而可以在代码中直接操作该 DOM 元素,例如获取元素的尺寸、滚动位置等。

    javascript 复制代码
    import React, { useRef } from 'react';
    
    function Example() {
        const inputRef = useRef(null);
    
        const focusInput = () => {
            // 通过 ref 获取 DOM 节点并调用其方法
            inputRef.current.focus();
        };
    
        return (
            <div>
                <input ref={inputRef} type="text" />
                <button onClick={focusInput}>聚焦输入框</button>
            </div>
        );
    }
    
    export default Example;

forwardRef

是 React 提供的一个高阶组件,用于在组件之间转发 ref。在 React 中,ref 是一种访问 DOM 节点或组件实例的方式,但默认情况下,组件不能直接将 ref 传递给子组件。forwardRef 可以打破这种限制,允许父组件将 ref 传递给子组件,从而让父组件可以访问子组件的 DOM 节点或调用子组件的方法。

useImperativeHandle

  • useImperativeHandle 通常与 forwardRef 一起使用,用于自定义通过 ref 暴露给父组件的实例值。默认情况下,当使用 ref 引用一个组件时,父组件可以访问该组件的所有实例属性和方法,但有时候我们可能只想暴露部分特定的属性或方法,这时就可以使用 useImperativeHandle 来实现。
相关推荐
qq_25249639961 小时前
react 子组件暴露,父组件接收
前端·javascript·react.js
zwjapple2 小时前
React 的 useEffect 清理函数详解
前端·react.js·前端框架
前端大白话3 小时前
前端必看!10个React实战技巧让你代码起飞,附超详细注释
前端·javascript·react.js
bigyoung3 小时前
使用 Arco Design 的 Table 组件实现可编辑列
前端·react.js·arco design
谦谦橘子3 小时前
手写react-router,理解react-router原理
前端·javascript·react.js
Aphasia3113 小时前
React 中ref的三种形式
前端·react.js
张开心_kx5 小时前
面试官又问我是否了解React的单向数据流
前端·javascript·react.js
天狗精灵5 小时前
从节点重排看React 与 Vue3 的 Diff 算法
前端·vue.js·react.js
前端大白话5 小时前
React 必知!useLayoutEffect Hook 与 useEffect 的终极对决,DOM 操作和动画的秘密武器
前端·javascript·react.js