用法在使用useEffect这个hooks的时候,我们通过会通过给他增加一个依赖项,来完成当某个或某些依赖发生改变的时候,完成一些副作用的操作,其正常用法如下:
import React, { useEffect, useState } from "react";
import "./styles.css";
const Profile = () => {
const [count, setCount] = useState(0);
useEffect(() => {
console.log("Number is added!");
}, [count]);
return (
<>
Current weight: {count}
>
);
};
export default Profile;
但是,当应用场景逐渐复杂之后,我们发现这么两个问题:
问题一分析:
import React, {
useEffect, useRef } from "react";
import "./styles.css";
const Profile = () => {
const [user, setUser] = React.useState({
name: "Alex", weight: 40 });
React.useEffect(() => {
console.log("You need to do exercise!");
}, [user]);
const gainWeight = () => {
const newWeight = Math.random() >= 0.5 ? user.weight : user.weight + 1;
setUser(user 用法=> ({
...user, weight: newWeight }));
};
return (
<>
<p>Current weight: {
user.weight}</p>
<button onClick={
gainWeight}>Eat burger</button>
</>
);
};
用法
export default Profile;
这里可以发现发现,只要点击按钮,无论数字是否增加,都会调用useEffect中的函数,其根本原因是***useEffect其本身是通过===来判定元素是否相同的***,而在javascrfipt中:
[] === [] // false
{
} === {
} // false
因此如果是引用类型,不管其中的某个值是否发生变化,都会引用该useEffect内的方法。
问题二分析:
import React, { useEffect, useState } from "react";
import "./styles.css";
const Profile = () => {
const [count, setCount] = useState(0);
const [simulate, setSimulate] = useState([]);
useEffect(() => {
console.log("Number is added!");
}, [count, simulate]);
const addList = () => {
setSimulate(sim => [...sim, Math.random().toFixed(2)]);
};
const addNum = () => {
setCount(Math.random() > 0.5 ? count + 1 : count);
};
return (
<>
Current weight: {count}
>
);
};
export default Profile;
当simulate变化的时候,确实会调用打印日志,但是我们可能希望只有在number增加的情况下才能打印(当然这里可以只把count作为依赖项),但是某些场景下,count和simulate是耦合的,没办法分开的。这里讨论的是这种耦合场景下的使用情况。因此,为了解决这个问题,很多时候需要知道更新之前状态时的count的值,但是显然在useEffect中我们通过该钩子函数,无法获取之前的值。
针对问题一:改变依赖项
例如: 在这里我们只想监控weight的变化,可以将依赖项改为 user.weight
import React, { useEffect, useRef } from "react";
import "./styles.css";
const Profile = () => {
const [user, setUser] = React.useState({ name: "Alex", weight: 40 });
const prevUser = usePrevious(user);
React.useEffect(() => {
console.log("You need to do exercise!");
}, [user.weight]);
const gainWeight = () => {
const newWeight = Math.random() >= 0.5 ? user.weight : user.weight + 1;
setUser(user => ({ ...user, weight: newWeight }));
};
return (
<>
Current weight: {user.weight}
>
);
};
export default Profile;
**针对问题一和二:**获取之前的状态,然后比较之后进行更新
因此问题就是,如何在函数式组件中获取之前的state,参考了各种文章之后,得到结论,利用useRef的功能,其本身是通过内部闭包来保存赋予的数据的值,能够记忆上一次的赋予的值
一个usePrevious的例子
import React, {
useEffect, useRef } from "react";
import Test from "./Test";
import "./styles.css";
const Profile = () => {
const [user, setUser] = React.useState({
name: "Alex", weight: 40 });
const prevUser = usePrevious(user);
React.useEffect(() => {
prevUser &&
user.weight > prevUser.weight &&
console.log("You need to do exercise!");
}, [user]);
const gainWeight = () => {
const newWeight = Math.random() >= 0.5 ? user.weight : user.weight + 1;
setUser(user => ({
...user, weight: newWeight }));
};
return (
<>
<p>Current weight: {
user.weight}</p>
<button onClick={
gainWeight}>Eat burger</button>
<Test />
</>
);
};
export default Profile;
function usePrevious(value) {
const ref = useRef();
useEffect(() => {
ref.current = value;
}, [value]);
return ref.current;
}
Introduction to useRef Hook: 这篇文章很好的讲解了useRef和createRef以及useRef的用法!