接react hooks之effect、state篇,在hooks中组件挂载时开启定时器时,我们通常需要用一个变量去保存定时器id方便组件卸载时清除。
正常想法下是这样写的:
import React,{ useEffect, useState } from 'react';
function demo() {
let timer;
const [list, setList] = useState([]);
const getList = () => {
// 获取数据
}
// 第一次请求
useEffect(() => {
getList();
}, [])
// 30s后开始轮询
useEffect(() => {
timer = window.setInterval(() => {
getList();
}, 30000)
return () => window.clearInterval(timer); // 此处一定要return出一个函数
}, [])
return (
// <>dom</>
)
}
浏览器会报warning:
Assignments to the 'timer' variable from inside React Hook useEffect will be lost after each render. To preserve the value over time, store it in a useRef Hook and keep the mutable value in the '.current' property. Otherwise, you can move this variable directly inside useEffect react-hooks/exhaustive-deps
意思如下
每次渲染后,从React Hook Useffect内部对“timer”变量的指定将丢失。要随时间保留该值,请将其存储在useRef hook中,并将可变值保留在“.current”属性中。
这个时候就需要引入useRef了
React的官方文档是这样描述的:
useRef 返回一个可变的 ref 对象,其 .current 属性被初始化为传入的参数(initialValue)。返回的 ref 对象在组件的整个生命周期内持续存在。
特点如下:
- 它可以很方便地保存任何可变值,其类似于在 class 中使用实例字段的方式。
- 它创建的是一个普通 Javascript 对象。而 useRef() 和自建一个 {current: ...} 对象的唯一区别是,useRef 会在每次渲染时返回同一个 ref 对象。
- 当 ref 对象内容发生变化时,
useRef
并不会通知你。变更.current
属性不会引发组件重新渲染。如果想要在 React 绑定或解绑 DOM 节点的 ref 时运行某些代码,则需要使用回调 ref 来实现。
回到问题,使用useRef解决上述warning
import React,{ useEffect, useState, useRef } from 'react';
function demo() {
const timerRef = useRef(null);
const [list, setList] = useState([]);
const getList = () => {
// 获取数据
}
// 第一次请求
useEffect(() => {
getList();
}, [])
// 30s后开始轮询
useEffect(() => {
timerRef.current = window.setInterval(() => {
getList();
}, 30000)
return () => window.clearInterval(timerRef.current);
}, [])
return (
// <>dom</>
)
}
其他场景中,useRef还可以这样用。
function App() {
const rootRef = useRef(null)
useEffect(() => {
// rootRef.current.style.backgroundColor = 'red'; // 操作dom
const p = document.createElement('p');
p.innerHTML = "this is new p";
rootRef.current.appendChild(p);
}, [])
return (
<>
<div ref={rootRef} className="App">
<Root />
</div>
</>
);
}