最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • useRef详细总结

    正文概述 掘金(webInRun)   2021-04-13   1155

    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
    

    useRef详细总结 现象:在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
    

    useRef详细总结 采用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 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
    

    两种法子的区别 useRef详细总结 现象 三个按钮依次点下,点击任意alert,最先弹出的是3(表示global变量取的最后渲染组件的值),后弹出1(表示ref属于组件自己,互相不影响)

    useRef与createRef

    createRef 每次渲染都会返回一个新的引用,而 useRef 每次都会返回相同的引用 在一个组件的正常的生命周期中可以大致可以分为3个阶段:

    1. 从创建组件到挂载到DOM阶段。初始化props以及state, 根据state与props来构建DOM
    2. 组件依赖的props以及state状态发生变更,触发更新
    3. 销毁阶段

    第一个阶段,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

    useRef详细总结 现象 点击按钮时,从控制台可以看到refFromUseRef.current一直为1(因为refFromUseRef.current已经存在该引用),而refFromCreateRef.current就是undefined(因为createRef 每次渲染都会返回一个新的引用,所以if判断时为true,会被重新赋值,页面就会显示出新的值)


    起源地下载网 » useRef详细总结

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元