usePrevious 代码
const usePrevious = (preValue) => {
const ref = useRef();
useEffect(() => {
ref.current = preValue;
}, [preValue])
return ref.current;
}
在代码中使用
import React, { useState } from "react";
import usePrevious from "./usePrevious";
export default function Counter() {
const [count, setCount] = useState(0);
const beforevalue = usePrevious(count);
console.log("count修改", count);
return (
<h1>
Now: {count}, before: {beforevalue}
<button onClick={() => setCount(count + 1)}>点击增加</button>
</h1>
);
}
一些问题
- useRef为什么可以用来封装成usePrevious?
- React-hooks的特点 -> 每次渲染都是最新的props,所以我们无法拿到previousProps,这时候我在网上查阅到了usePrevious,代码如下:
const usePrevious = (preValue) => {
const ref = useRef();
useEffect(() => {
ref.current = preValue;
}, [preValue])
return ref.current;
}
- useRef的特点是如果你给他传入了一个值,那么他在不断的生命周期中是永远不变的?那么他为什么又会每次都精准的拿到上一次的props呢?还是说这与新的生命周期有关呢?
分析代码
我们打印一下log,看它们执行的顺序
import React, { useEffect, useRef } from "react";
export default function usePrevious(value) {
const previous = useRef(value);
useEffect(() => {
console.log("usePrevious中useEffect执行", value);
previous.current = value;
}, [value]);
console.log("返回previous.current", previous.current);
return previous.current;
}
import React, { useState } from "react";
import usePrevious from "./usePrevious";
export default function Counter() {
const [count, setCount] = useState(0);
const beforevalue = usePrevious(count);
console.log("count修改", count);
return (
<h1>
Now: {count}, before: {beforevalue}
<button onClick={() => setCount(count + 1)}>点击增加</button>
</h1>
);
}
打印结果
返回previous.current 1
count修改 2
usePrevious中useEffect执行 2
返回previous.current 2
count修改 3
usePrevious中useEffect执行 3
从打印结果我们看到,是先执行同步操作,return 返回值,再执行 count 的渲染,最后再执行 usePrevious中 useEffect(useEffect是在每次渲染之后才会触发的),由于useRef 会保持引用不变,所以 ref.current 的值的修改并不会引起组件重新渲染,所以即使 ref.current 的值修改了,counter组件中也不会重新执行 usePrevious了,所以可以通过这种方式实现,获取原来 state的值。
useEffect很重要的一点是:它是在每次渲染之后才会触发的,是延迟执行的。而return语句是同步的,所以return的时候,ref.current还是旧值。
所以在每次的渲染过程中,usePrevious的useEffect还没有被调用,返回的还是上一个生命周期中被赋的值
总结
- useRef会保持引用不变,ref.current的值改变并不会引起组件重新渲染
- React Hook中函数式组件的生命周期中,useEffect是在jsx渲染之后执行的