React自定义 usePrevious实现

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 (
    

Now: {count}, before: {beforevalue}

); }

一些问题

  1. useRef为什么可以用来封装成usePrevious?
  2. React-hooks的特点 -> 每次渲染都是最新的props,所以我们无法拿到previousProps,这时候我在网上查阅到了usePrevious,代码如下:
const usePrevious = (preValue) => {
    const ref = useRef();
    useEffect(() => {
        ref.current = preValue;
    }, [preValue])
    
    return ref.current;
}
  1. 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 (
    

Now: {count}, before: {beforevalue}

); }

打印结果

返回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渲染之后执行的

参考

  • useRef为什么可以用来封装成usePrevious?
  • 一篇文章,带你学会useRef、useCallback、useMemo
  • 什么是 useRef , useRef 与 createRef 区别, 以及在什么情况下使用 useRef
  • react文档-如何获取上一轮的 props 或 state?

你可能感兴趣的:(React自定义 usePrevious实现)