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输入出现一个打印,点击按钮出现两个打印。

相关推荐
web1478621072317 分钟前
C# .Net Web 路由相关配置
前端·c#·.net
m0_7482478018 分钟前
Flutter Intl包使用指南:实现国际化和本地化
前端·javascript·flutter
飞的肖21 分钟前
前端使用 Element Plus架构vue3.0实现图片拖拉拽,后等比压缩,上传到Spring Boot后端
前端·spring boot·架构
青灯文案129 分钟前
前端 HTTP 请求由 Nginx 反向代理和 API 网关到后端服务的流程
前端·nginx·http
m0_7482548834 分钟前
DataX3.0+DataX-Web部署分布式可视化ETL系统
前端·分布式·etl
ZJ_.1 小时前
WPSJS:让 WPS 办公与 JavaScript 完美联动
开发语言·前端·javascript·vscode·ecmascript·wps
GIS开发特训营1 小时前
Vue零基础教程|从前端框架到GIS开发系列课程(七)响应式系统介绍
前端·vue.js·前端框架·gis开发·webgis·三维gis
Cachel wood1 小时前
python round四舍五入和decimal库精确四舍五入
java·linux·前端·数据库·vue.js·python·前端框架
学代码的小前端1 小时前
0基础学前端-----CSS DAY9
前端·css
joan_851 小时前
layui表格templet图片渲染--模板字符串和字符串拼接
前端·javascript·layui