本文已参与「新人创作礼」活动,一起开启掘金创作之路。
前言
在Vue中可以简单地使用watch
来监听数据的变化,还能获取到改变前的旧值,而在React
中比较复杂,所以想在React
中实现一个类似Vue
的watch
监听属性,咱们用自定义Hook在实现吧。
自定义Hook函数开头约定为
use
,所以组件命名为useWatch
1.创建一个useWatch.js文件
旧值咱们就用useRef
来进行存储,它可以很方便地保存任何可变值 官网
useRef
返回一个可变的 ref 对象,其.current
属性被初始化为传入的参数(initialValue
)。返回的 ref 对象在组件的整个生命周期内持续存在。
import { useEffect, useRef } from 'react'
// value 是要监听的属性 fn 是回调函数
const useWatch = (value, fn) => {
// 存储旧值
const oldValue = useRef()
useEffect(() => {
fn(value, oldValue.current)
oldValue.current = value
}, [value])
}
export default useWatch
2.实现组件初次渲染不执行fn
回调函数
useEffect
会在初次渲染时会调用一次,所以要限制一下fn
回调函数。
import { useEffect, useRef } from 'react'
const useWatch = (value, fn) => {
const oldValue = useRef()
// 声明一个变量限制初次渲染 fn 函数
const isFirst = useRef(false)
useEffect(() => {
// 判断是否是初次渲染,初次渲染就不执行 fn 回调函数
if(isFirst.current) {
fn(value, oldValue.current)
}else {
isFirst.current = true
}
oldValue.current = value
}, [value])
}
export default useWatch
3.添加 immediate
配置控制组件
Vue的
watch
是可以通过immediate
来控制是否初次渲染后就执行回调函数,所以咱们也加一下。
import { useEffect, useRef } from 'react'
const useWatch = (value, fn, config = { immediate: false }) => {
const oldValue = useRef()
const isFirst = useRef(false)
useEffect(() => {
if (isFirst.current) {
fn(value, oldValue.current)
} else {
isFirst.current = true
// 是否要立即执行 fn 回调函数
if (config.immediate) {
fn(value, oldValue.current)
}
}
oldValue.current = value
}, [value])
}
export default useWatch
4.使用useWatch
监听
普通类型
或者复杂类型
都是没问题的
import { useState } from 'react'
import useWatch from "./Hook/useWatch";
export default function HelloWorld() {
const [name, setName] = useState('豆豆')
const [obj, setObj] = useState({name: '胡歌', age: 18})
// 当name变化后会执行回调函数
useWatch(name, (newName, oldName) => {
console.log('newName', newName); // 一只豆豆
console.log('oldName', oldName); // 豆豆
})
useWatch(obj, (newObj, oldObj) => {
console.log('newObj', newObj); // {name: '彭于晏', age: 18}
console.log('oldObj', oldObj); // {name: '胡歌', age: 18}
})
const changeName = () => {
setName('一只豆豆')
setObj({
...obj,
name: '彭于晏'
})
};
return (
<>
<button onClick={changeName}>click my</button>
</>
);
}
打印效果图
结语
有帮助的话,给个赞哈。如果有错误欢迎在评论区指出。