useRef
定义
const refContainer = useRef(initialValue);
- refContainer对象里会有个current属性,当更新current值时并不会re-render,这是与useState不同的地方
- 更新useRef是side effect(副作用),所以一般写在useEffect或event handler里
- useRef类似于类组件的this
为什么使用useRef
返回的 ref 对象在组件的整个生命周期内保持不变
- 示例1:
由于每次渲染周期获取到的state数据都是本次的,而要达到跨渲染周期就需要采用useRef 由于闭包,函数里的变量值为调用函数时对应的快照like值
import React, { useState } from "react";
const LikeButton: React.FC = () => {
const [like, setLike] = useState(0)
function handleAlertClick() {
setTimeout(() => {
alert(`you clicked on ${like}`)
//形成闭包,所以弹出来的是当时触发函数时的like值
}, 3000)
}
return (
<>
<button onClick={() => setLike(like + 1)}>{like}赞</button>
<button onClick={handleAlertClick}>Alert</button>
</>
)
}
export default LikeButton
现象:在like为6的时候, 点击 alert , 再继续增加like到10, 弹出的值为 6, 而非 10. 有两个法子解决如上问题:
方法一: 在组件前定义一个类似 global 的变量 方法二: 采用useRef,作为组件实例的变量,保证获取到的数据肯定是最新的 方法一:
import React from 'react'
let like = 0
const LikeButton: React.FC = () => {
function handleAlertClick() {
setTimeout(() => {
alert(`you clicked on ${like}`)
}, 3000)
}
return (
<>
<button
onClick={() => {
like = ++like
}}
>
{like}赞
</button>
<button onClick={handleAlertClick}>Alert</button>
</>
)
}
export default LikeButton
采用global变量 该示例同时也说明,非state变量不会引起重新render
方法二:
import React, { useRef } from 'react'
const LikeButton: React.FC = () => {
// 定义一个实例变量
let like = useRef(0)
function handleAlertClick() {
setTimeout(() => {
alert(`you clicked on ${like.current}`)
}, 3000)
}
return (
<>
<button
onClick={() => {
like.current = like.current + 1
}}
>
{like.current}赞
</button>
<button onClick={handleAlertClick}>Alert</button>
</>
)
}
export default LikeButton
采用useRef 该示例同时也说明,ref更改不会re-render
两种法子的区别
上面两个法子都可以解决问题,那两个有什么区别呢
-
useRef 是定义在实例基础上的,如果代码中有多个相同的组件,每个组件的 ref 只跟组件本身有关,跟其他组件的 ref 没有关系。
-
组件前定义的 global 变量,是属于全局的。如果代码中有多个相同的组件,那这个 global 变量在全局是同一个,他们会互相影响。
import React, { useRef } from 'react'
// 定义一个全局变量
let like = 0
const LikeButton: React.FC = () => {
let likeRef = useRef(0)
function handleAlertClick() {
setTimeout(() => {
alert(`you clicked on ${like}`)
alert(`you clicked on ${likeRef.current}`)
}, 3000)
}
return (
<p>
<button
onClick={() => {
like = ++like
likeRef.current = likeRef.current + 1
}}
>
点赞
</button>
<button onClick={handleAlertClick}>Alert</button>
</p>
)
}
export default LikeButton
两种法子的区别 现象 三个按钮依次点下,点击任意alert,最先弹出的是3(表示global变量取的最后渲染组件的值),后弹出1(表示ref属于组件自己,互相不影响)
useRef与createRef
createRef 每次渲染都会返回一个新的引用,而 useRef 每次都会返回相同的引用 在一个组件的正常的生命周期中可以大致可以分为3个阶段:
- 从创建组件到挂载到DOM阶段。初始化props以及state, 根据state与props来构建DOM
- 组件依赖的props以及state状态发生变更,触发更新
- 销毁阶段
第一个阶段,useRef与createRef没有差别 第二个阶段,createRef每次都会返回个新的引用;而useRef不会随着组件的更新而重新创建 第三个阶段,两者都会销毁
import React, { useState, useRef, createRef } from 'react'
const RefDifference: React.FC = () => {
let [renderIndex, setRenderIndex] = useState(1)
let refFromUseRef = useRef<number>()
let refFromCreateRef = createRef()
console.info(refFromUseRef.current, 'refFromUseRef.current')
console.info(refFromCreateRef.current, 'refFromCreateRef.current')
if (!refFromUseRef.current) {
refFromUseRef.current = renderIndex
}
if (!refFromCreateRef.current) {
refFromCreateRef.current = renderIndex
}
return (
<>
<p>Current render index: {renderIndex}</p>
<p>
<b>refFromUseRef</b> value: {refFromUseRef.current}
</p>
<p>
<b>refFromCreateRef</b> value:
{refFromCreateRef.current}
</p>
<button onClick={() => setRenderIndex((prev) => prev + 1)}>
Cause re-render
</button>
</>
)
}
export default RefDifference
useRef与createRef
现象 点击按钮时,从控制台可以看到refFromUseRef.current一直为1(因为refFromUseRef.current已经存在该引用),而refFromCreateRef.current就是undefined(因为createRef 每次渲染都会返回一个新的引用,所以if判断时为true,会被重新赋值,页面就会显示出新的值)
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!