網(wǎng)站首頁(yè) 編程語(yǔ)言 正文
開(kāi)篇
使用過(guò) React 技術(shù)棧的同學(xué)相信都使用過(guò) ref 傳遞給 render 中的元素,而在使用 React 封裝組件時(shí),會(huì)有這樣一個(gè)場(chǎng)景:
組件將 props.children 作為 render 內(nèi)容;組件內(nèi)部會(huì)創(chuàng)建 ref 綁定到 props.children 上。
我們知道,元素上只能綁定一個(gè) ref 屬性引用,但對(duì)于上面這個(gè)場(chǎng)景,props.children 上可能已經(jīng)存在一個(gè) ref 屬性,而組件內(nèi)部定義的 ref 也會(huì)綁定到 props.children 上。
我們要想一種方式,將兩者的 ref 都可以生效于元素上。
思路
首先我們回顧一下 React 創(chuàng)建 ref 的方式:
- React.createRef():React 16.3 版本提供的 class 創(chuàng)建 ref 方式;
- React.useRef():React Hooks 提供的 函數(shù)組件 創(chuàng)建 ref 方式;
- 回調(diào) Refs:傳遞一個(gè)函數(shù)作為元素的 ref 屬性,此函數(shù)接收 React 組件實(shí)例或 HTML DOM 元素作為參數(shù)。
綜合考慮,既然 回調(diào) Refs 允許我們傳遞一個(gè)函數(shù),并且接收元素實(shí)例作為這個(gè)函數(shù)的參數(shù),那我們就可以定義一個(gè)這樣的函數(shù),在函數(shù)內(nèi)編寫我們的邏輯來(lái)處理 多個(gè) ref 綁定元素實(shí)例的場(chǎng)景。(函數(shù)的靈活性)
實(shí)現(xiàn)
- 編寫一個(gè)函數(shù)(閉包函數(shù)),接收 props.children.ref 和 組件內(nèi) ref 作為參數(shù);
- 函數(shù)(閉包函數(shù))需要 return 返回一個(gè)函數(shù),這個(gè)函數(shù)將作為 回調(diào) Refs 去作用于元素;
- 在 return 的這個(gè)函數(shù)中,將函數(shù)參數(shù)(元素引用)綁定到 props.children.ref 和 組件內(nèi) ref 上。
上代碼:
function forkRef(refA, refB) { ? return refValue => { ? ? setRef(refA, refValue); ? ? setRef(refB, refValue); ? }; } function setRef(ref, value) { ? if (typeof ref === 'function') { ? ? ref(value); ? } else if (ref) { ? ? ref.current = value; ? } }
在 setRef 中會(huì)針對(duì)創(chuàng)建 ref 的方式做不同處理,比如:React.createRef 和 React.useRef 創(chuàng)建的 ref 是一個(gè)具有 current 屬性的對(duì)象。
使用:
const nodeRef = React.useRef(null); // 組件內(nèi)部的 ref const handleRef = forkRef(props.children.ref, nodeRef); const childrenProps = { ref: handleRef }; return React.cloneElement(children, childrenProps);
自定義 Hook - useForkRef
在 Hook 函數(shù)組件中,我們可以借助于 React.memo() 優(yōu)化一下 forkRef() 的邏輯,避免每次組件更新時(shí)都創(chuàng)建一個(gè)新的閉包函數(shù)。
下面我們使用 TS 編寫一個(gè) useForkRef:
import * as React from 'react'; interface MutableRefObject{ ? current: T; } type Ref = ((instance: T | null) => void) | MutableRefObject | null; export function setRef(ref: Ref , value: unknown) { ? if (typeof ref === 'function') { ? ? ref(value); ? } else if (ref) { ? ? ref.current = value; ? } } export default function useForkRef(refA: Ref , refB: Ref ) { ? return React.useMemo(() => { ? ? if (refA == null && refB == null) { ? ? ? return null; ? ? } ? ? return (refValue: unknown) => { ? ? ? setRef(refA, refValue); ? ? ? setRef(refB, refValue); ? ? }; ? }, [refA, refB]); }
使用:
const nodeRef = React.useRef(null); // 組件內(nèi)部的 ref const handleRef = useForkRef(children.ref, nodeRef); const childrenProps: any = { ref: handleRef }; React.cloneElement(children, childrenProps)
原文鏈接:https://juejin.cn/post/7071897973642231822
相關(guān)推薦
- 2022-02-03 ionic 富文本編輯樣式后,前臺(tái)不能回顯樣式
- 2022-12-11 python模塊itsdangerous簡(jiǎn)單介紹_python
- 2022-06-01 Kubernetes集群的組成介紹_云和虛擬化
- 2022-09-03 詳解Docker鏡像的基本操作方法_docker
- 2022-08-22 Android中關(guān)于Binder常見(jiàn)面試問(wèn)題小結(jié)_Android
- 2022-12-21 React?之最小堆min?heap圖文詳解_React
- 2022-04-04 asp.net使用原生控件實(shí)現(xiàn)自定義列導(dǎo)出功能的方法_實(shí)用技巧
- 2022-07-13 Win系統(tǒng)服務(wù)器管理器打開(kāi)方式
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過(guò)濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡(jiǎn)單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支