编程崽

登录

一叶在编程苦海沉沦的扁舟之上,我是那只激情自射的崽

同步修改变量功能封装 useVal for react

同步修改变量功能封装 useVal for react

react 正常 useState 功能,并不是同步修改state,再某些场景需要借助 useRef 才能完成功能。

比如调用某个接口拿了数据A,需要进行某些计算时,需要用到组件中另一个数据B的最新的值,这个功能就不能顺利完成。

要么把数据A也方法一个useState中,然后使用useEffect监听数据A和数据B,进行计算。

要么使用一个数据B的ref,修改数据B时需要手动或监听数据B的变化,修改数据B的ref值,在接口完成后,从数据B的ref中读取最新的数据B。

就很难受。

所以封装了下面这个js,用法和useState相同,只是会多返回一个getRef的方法,使用getRef可以读取到最新的值,下面有使用示例。

useVal.ts 文件中

ts 复制代码
import { useState, useRef, useCallback } from 'react';
import type { Dispatch, SetStateAction } from 'react';

// 可以当做 useState 用,但数组会多传回一个方法,使用方法可以实时获取最新的值
function useVal<S>(initialState: S | (() => S)): [S, Dispatch<SetStateAction<S>>, (() => S)] {
  let initData = typeof initialState === 'function' ? (initialState as (() => S))() : initialState
  // 内部使用 useState
  const [data, setData] = useState<S>(() => initData)
  // 创建一个 useRef,用来实时给外部提供最新的值
  const dataRef = useRef(initData)

  // 供外部修改值的方法,方法中会同时给 ref 赋值,供外部随时获取最新值
  const setDataExport = useCallback((params: S | ((prevState: S) => S)) => {
    // 这里的旧值从ref中取
    let oldData = dataRef.current
    // 放置新的值的变量
    let newData = oldData

    // 如果传入的是方法,这里执行得到结果
    if (typeof params === 'function') newData = (params as ((prevState: S) => S))(oldData)
    // 不是方法,直接赋值
    else newData = params

    // 先更新ref
    dataRef.current = newData
    // 再真的去更新 useState 记录的值,这里需要方法返回新值的方式
    setData(() => newData)
  }, [])

  // 供外部获取实时的值的方法
  const getRef = useCallback((): S => dataRef.current, [])

  return [data, setDataExport, getRef]
}

export { useVal }

使用示例:

ts 复制代码
import { useEffect, useState } from 'react'
import { useVal } from '@/utils/useVal'

export default function() {
  const [a, setA] = useState<number>(1)
  const [b, setB, getB] = useVal<number>(1)

  useEffect(() => {
    setInterval(() => {
      setA(old => old + 1)
      setB(old => old + 1)
      console.log(`修改一次:  a: ${a}, b: ${b}, b的ref: ${getB()}`)
    }, 1000)
  }, [])

  return ('Test')
}

打印结果:

sh 复制代码
修改一次:  a: 1, b: 1, b的ref: 2
修改一次:  a: 1, b: 1, b的ref: 3
修改一次:  a: 1, b: 1, b的ref: 4
修改一次:  a: 1, b: 1, b的ref: 5

可以看到,因为react Hook的特性,打印中a和b的值都是1,而b的ref的值,一直都是最新的,相当于同步修改了。

更新时间:2023/11/27 11:01:15