hooks学习笔记1-useState、useCallback+useMemo

useState

useState用于在函数组件中添加状态。它接受一个初始值作为参数,并返回一个包含当前状态值和更新状态值的数组。

使用方法

state是当前状态的值,setState是用于更新状态的函数,initialValue是初始值。

scss 复制代码
const [state, setState] = useState(initialValue);

在组件中可以通过state来访问当前状态的值,通过setState来更新状态的值。

scss 复制代码
// 读取状态值
console.log(state);

// 更新状态值
setState(newValue);

useState可以多次使用,用于声明多个状态变量。

scss 复制代码
const [state1, setState1] = useState(initialValue1);
const [state2, setState2] = useState(initialValue2);

更新状态的函数可以接受一个新值,也可以接受一个函数。

scss 复制代码
const [num, setNum] = useState(0);
setNum(1);
setNum(old=>old+1);

惰性初始化 state

initialState 参数只会在组件的初始化渲染中起作用,后续渲染时会被忽略。

如果初始 state 需要通过复杂计算获得,则可以传入一个函数,在函数中计算并返回初始的 state,此函数只在初始渲染时被调用。

这样可以避免在每次渲染时都执行昂贵的初始化计算。

ini 复制代码
const [state, setState] = useState(() => {
  const initialValue = someExpensiveComputation();
  return initialValue;
});

注意事项

  • useState是按顺序声明的,所以在组件中的顺序很重要。
  • 更新函数它类似 class 组件的 this.setState,但是它不会把新的 state 和旧的 state 进行合并,而是直接替换
  • 在初始渲染期间,返回的状态 (state) 与传入的第一个参数 (initialState) 值相同

useCallback+useMemo

useCallback

useCallback用于缓存一个函数,以便在依赖项不变的情况下避免函数的重新创建。它接受一个回调函数和一个依赖项数组,并返回一个缓存的回调函数。

使用方法

ini 复制代码
const memoizedCallback = useCallback(callback, dependencies);

这里的callback是要缓存的回调函数,dependencies是一个依赖项数组,当数组中的任何一个值发生变化时,缓存的回调函数会重新创建。

例如,当你将回调函数作为props传递给子组件时,可以使用useCallback来确保子组件不会在父组件重新渲染时重新创建回调函数。

javascript 复制代码
import React, { useCallback } from 'react';

function MyComponent() {
  const handleClick = useCallback(() => {
    // 处理点击事件的逻辑
  }, []); // 依赖数组为空,表示回调函数不依赖任何值

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

在上面的例子中,handleClick函数会在组件第一次渲染时创建,并且在后续的重新渲染中复用。如果依赖数组不为空,那么只有当依赖项发生变化时,handleClick函数才会重新创建。

一般来说,useCallback适用于以下场景:

  • 当你将回调函数作为参数传递给子组件时,可以使用useCallback来确保子组件不会频繁重新渲染。
  • 在使用memoshouldComponentUpdate进行组件性能优化时,可以用useCallback来缓存回调函数。

需要注意的是,由于useCallback使用了浅比较来确定回调函数是否需要重新创建,所以如果回调函数内部引用了依赖项(如变量或状态),需要确保依赖项是稳定的,避免出现意外的行为

useMemo

useMemo用于缓存一个值,以便在依赖项不变的情况下避免值的重新计算。它接受一个计算函数和一个依赖项数组,并返回一个缓存的值。

使用方法

ini 复制代码
const memoizedValue = useMemo(callback, dependencies);

这里的callback是计算函数,dependencies是一个依赖项数组,当数组中的任何一个值发生变化时,缓存的值会重新计算。

javascript 复制代码
import React, { useMemo } from 'react';

function MyComponent({ a, b }) {
  const result = useMemo(() => {
    // 根据依赖项a和b进行计算
    return a + b;
  }, [a, b]); // 依赖项为[a, b]

  return (
    <div>{result}</div>
  );
}

在上面的例子中,result变量会在组件第一次渲染时计算,并在后续的重新渲染中复用,除非依赖项ab发生变化。如果依赖项发生变化,result将会重新计算。

useMemo适用于以下场景:

  • 当一些计算比较昂贵,但依赖项不经常变化时,可以使用useMemo缓存计算结果,避免重复计算。
  • 当在渲染期间需要进行数据转换或映射时,可以使用useMemo缓存转换结果。
  • 在使用memoshouldComponentUpdate进行组件性能优化时,可以用useMemo缓存具有相同结果的值。

需要注意的是,由于useMemo使用了浅比较来确定依赖项是否发生变化,所以如果依赖项是引用类型(如对象或数组),需要确保依赖项的引用地址不变,以便正确触发重新计算。

当在渲染期间需要进行数据转换或映射时,可以使用useMemo缓存转换结果,以避免重复计算。以下是一个简单的例子,展示了如何使用useMemo来进行数据转换:

javascript 复制代码
import React, { useMemo } from 'react';

function MyComponent({ data }) {
  const transformedData = useMemo(() => {
    // 进行数据转换,例如将每个元素的值增加1
    return data.map(item => item + 1);
  }, [data]); // 依赖项为[data]

  return (
    <div>
      {transformedData.map(item => (
        <span key={item}>{item}</span>
      ))}
    </div>
  );
}

在上面的例子中,data是一个数组,我们希望对每个元素的值进行加一的操作。通过使用useMemo,我们可以将数据转换的逻辑定义为计算函数,并将data作为依赖项。

data发生变化时,transformedData会重新计算。但在同一个渲染周期内,如果data没有发生变化,那么transformedData会复用上一次计算的结果,从而避免重复的数据转换操作。

这种方式可以提高性能,特别是当data数组较大或者转换操作比较复杂时。通过缓存计算结果,可以避免每次重新渲染都进行昂贵的数据转换操作,从而提升组件的渲染性能。

使用useCallback+useMemo+React.memo进行性能优化

typescript 复制代码
import React,{useState,memo,useMemo,useCallback} from 'react';

function SubCounter({onClick,data}:{onClick:()=>void,data:{number:number}}){
    console.log('SubCounter render');
    return (
        <button onClick={onClick}>{data.number}</button>
    )
}
const NewSubCounter = memo(SubCounter);
export  default  function Counter6(){
    console.log('Counter render');
    const [name,setName]= useState('计数器');
    const [number,setNumber] = useState(0);
    const data = {number}
    const addClick = ()=>{
        setNumber(number+1);
    }
    // const data =useMemo(()=>({number}),[number])
    // const addClick =useCallback(()=>{
    //     setNumber(number+1);
    // },[number]);
    return (
        <>
            <input type="text" value={name} onChange={(e)=>setName(e.target.value)}/>
            <NewSubCounter data={data} onClick={addClick}/>
        </>
    )
}

函数组件使用 React.memo ,将函数组件传递给 memo 之后,就会返回一个新的组件,新组件的功能:如果接受到的属性不变,则不重新渲染函数

上面的代码中的 const NewSubCounter = memo(SubCounter);将SubCounter组件做处理。 但是它接收的参数data和addClick在父组件重新渲染时一起改变,所以当你input输入时能看到两个打印SubCounter renderCounter render,使用useMemo,useCallback处理了数据和函数后,input输入出现一个打印,点击按钮出现两个打印。

相关推荐
BBB努力学习程序设计36 分钟前
CSS Sprite技术:用“雪碧图”提升网站性能的魔法
前端·html
BBB努力学习程序设计42 分钟前
CSS3渐变:用代码描绘色彩的流动之美
前端·html
冰暮流星1 小时前
css之动画
前端·css
jump6801 小时前
axios
前端
spionbo1 小时前
前端解构赋值避坑指南基础到高阶深度解析技巧
前端
用户4099322502121 小时前
Vue响应式声明的API差异、底层原理与常见陷阱你都搞懂了吗
前端·ai编程·trae
开发者小天1 小时前
React中的componentWillUnmount 使用
前端·javascript·vue.js·react.js
永远的个初学者2 小时前
图片优化 上传图片压缩 npm包支持vue(react)框架开源插件 支持在线与本地
前端·vue.js·react.js
爱吃土豆的马铃薯ㅤㅤㅤㅤㅤㅤㅤㅤㅤ2 小时前
npm i / npm install 卡死不动解决方法
前端·npm·node.js
Kratzdisteln2 小时前
【Cursor _RubicsCube Diary 1】Node.js;npm;Vite
前端·npm·node.js