日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學(xué)無(wú)先后,達(dá)者為師

網(wǎng)站首頁(yè) 編程語(yǔ)言 正文

React自定義Hook-useForkRef的具體使用_React

作者:明里人 ? 更新時(shí)間: 2022-05-06 編程語(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

欄目分類
最近更新