AVt天堂网 手机版,亚洲va久久久噜噜噜久久4399,天天综合亚洲色在线精品,亚洲一级Av无码毛片久久精品

當(dāng)前位置:首頁 > 科技  > 軟件

來自 React 19 的背刺:ForwardRef 被無情拋棄

來源: 責(zé)編: 時(shí)間:2024-06-21 17:25:06 158觀看
導(dǎo)讀在之前的版本中,forwardRef 一直是我最愛用的 ref 之一。它在封裝組件時(shí)非常有用。可是萬萬沒想到,由于使用方式稍微麻煩了一點(diǎn),在新的版本中,直接被 React 19 背刺一刀,實(shí)現(xiàn)同樣的功能,以后可以不用它了.... forwardRef 被

FTi28資訊網(wǎng)——每日最新資訊28at.com

在之前的版本中,forwardRef 一直是我最愛用的 ref 之一。它在封裝組件時(shí)非常有用。可是萬萬沒想到,由于使用方式稍微麻煩了一點(diǎn),在新的版本中,直接被 React 19 背刺一刀,實(shí)現(xiàn)同樣的功能,以后可以不用它了.... forwardRef 被無情拋棄。FTi28資訊網(wǎng)——每日最新資訊28at.com

本文主要內(nèi)容包括如下幾個(gè)部分。FTi28資訊網(wǎng)——每日最新資訊28at.com

  • React 中的 控制反轉(zhuǎn) IOC。
  • forwardRef 基礎(chǔ)知識(shí)。
  • React 19 中 ref 機(jī)制更改,forwardRef 被無情拋棄。
  • useImperativeHandle 與 ref 的新配合。

一、React 中的控制反轉(zhuǎn)

在面向?qū)ο缶幊讨校琁OC (Inversion of Control) 控制反轉(zhuǎn)是一個(gè)非常高級(jí)的概念。它是一種設(shè)計(jì)理念,在減少對象之間的耦合關(guān)系上有非常重要的作用。FTi28資訊網(wǎng)——每日最新資訊28at.com

?FTi28資訊網(wǎng)——每日最新資訊28at.com

許多前端雖然對其有所耳聞,但說實(shí)話,能理解的并不多。甚至很對前端對解耦這個(gè)概念都是一頭霧水。FTi28資訊網(wǎng)——每日最新資訊28at.com

IOC 的設(shè)計(jì)理念里,有三個(gè)角色,一個(gè)角色是容器 C,一個(gè)角色是被控制者 B,一個(gè)角色是控制者 A,許多時(shí)候,在代碼開發(fā)中,控制者 A 直接去控制對象 B,會(huì)導(dǎo)致 B 被多次實(shí)例化而從讓代碼邏輯變得更加復(fù)雜。因此 IOC 的理念是讓 控制者 A 失去對 B 的直接控制權(quán),它只能與容器交互。從而將 A 與 B 的直接聯(lián)系隔離開。FTi28資訊網(wǎng)——每日最新資訊28at.com

這樣說可能會(huì)有點(diǎn)繞,但是呢,我們使用一個(gè)大家經(jīng)常使用的代碼來說明一下,你一下就能明白。FTi28資訊網(wǎng)——每日最新資訊28at.com

const ref = useRef()
<InputNumber ref={ref} />
ref.current.focus()

在這個(gè)案例里,我們的目標(biāo)是直接獲取到 input 對象,并且調(diào)用它的 focus 方法,讓 input 獲得焦點(diǎn)。FTi28資訊網(wǎng)——每日最新資訊28at.com

var input = document.getElementById('input')input.focus()

但是在模塊的劃分上,input 元素本身并不屬于當(dāng)前模塊/組件,因此,調(diào)用 input 方法的行為,其實(shí)是屬于一種混亂。除非我們不做解耦和封裝。FTi28資訊網(wǎng)——每日最新資訊28at.com

因此,在 React 的組件封裝中,并不支持直接獲取到 input 的引用,而是以一種傳入控制器的方式來調(diào)用它。在這個(gè)場景里:FTi28資訊網(wǎng)——每日最新資訊28at.com

input 對象本身是被調(diào)用者
InputNumber 組件是容器
ref 是控制器FTi28資訊網(wǎng)——每日最新資訊28at.com

當(dāng)前組件利用 ref 來調(diào)用 input。從而讓代碼的解耦變得非常合理。可擴(kuò)展性也很強(qiáng)。FTi28資訊網(wǎng)——每日最新資訊28at.com

?FTi28資訊網(wǎng)——每日最新資訊28at.com

注意一些概念上的區(qū)分:控制反轉(zhuǎn)是一種設(shè)計(jì)思維,依賴注入是控制反轉(zhuǎn)的一種具體實(shí)現(xiàn),在 React 中,ref 也是一種控制反轉(zhuǎn)的具體實(shí)現(xiàn)。FTi28資訊網(wǎng)——每日最新資訊28at.com

所以不要聽著別人吹控制反轉(zhuǎn)就覺得牛,你可能也天天在用。FTi28資訊網(wǎng)——每日最新資訊28at.com

二、forwardRef 基礎(chǔ)知識(shí)

forwardRef 能夠幫助 React 組件傳遞 ref。或者說是內(nèi)部對象控制權(quán)的轉(zhuǎn)移與轉(zhuǎn)發(fā)。它接收一個(gè)組件作為參數(shù)。FTi28資訊網(wǎng)——每日最新資訊28at.com

import { forwardRef } from 'react';function MyInput(props, ref) {  // ...}const InputNumber = forwardRef(MyInput);

這里需要注意的是,我們需要把 ref 放在自定義組件的參數(shù)中。FTi28資訊網(wǎng)——每日最新資訊28at.com

function MyInput(props, ref) {  // ...}

forwardRef 返回一個(gè)可渲染的函數(shù)組件。因此,我們可以通過一個(gè)簡單的案例完善上面的代碼。FTi28資訊網(wǎng)——每日最新資訊28at.com

function MyInput(props, ref) {  return (    <label>      {props.label}      <input ref={ref} />    </label>  );}const InputNumber = forwardRef(MyInput)

所以呢,在 React 的開發(fā)中,forwardRef 能夠幫助我們實(shí)現(xiàn)更良好的解耦,這也是我一直非常喜歡使用 forwardRef 的原因。FTi28資訊網(wǎng)——每日最新資訊28at.com

三、ref 機(jī)制更改,forwardRef 被無情拋棄

但是,在 React 19 中,forwardRef 被直接背刺,由于 ref 傳遞機(jī)制的更改,我們可以不用 forwardRef 也能做到同樣的事情了。FTi28資訊網(wǎng)——每日最新資訊28at.com

首先,在聲明組件時(shí),ref 不再獨(dú)立成為一個(gè)參數(shù),而是作為 props 屬性中的一個(gè)屬性。FTi28資訊網(wǎng)——每日最新資訊28at.com

function MyInput(props) {  return (    <label>      {props.label}      <input ref={props.ref} />    </label>  );}

其次,代碼這樣寫了之后,就可以直接在父組件中,通過 ref 拿到 input 的控制權(quán)。FTi28資訊網(wǎng)——每日最新資訊28at.com

function Index() {  const input = useRef(null)  function __clickHandler() {    input.current.focus()  }  return (    <div>      <button onClick={__clickHandler}>        點(diǎn)擊獲取焦點(diǎn)      </button>      <MyInput ref={input} />    </div>  )}

在父組件中的使用與以前一樣,但是子組件由于不再需要 forwardRef,變得更加簡單了。FTi28資訊網(wǎng)——每日最新資訊28at.com

四、useImperativeHandle 與 ref 的新配合

除了直接拿到元素對象本身就已經(jīng)存在的 ref,我們還可以通過 useImperativeHandle 來自定義 ref 控制器能執(zhí)行哪些方法FTi28資訊網(wǎng)——每日最新資訊28at.com

useImperativeHandle 接收三個(gè)參數(shù),分別是:FTi28資訊網(wǎng)——每日最新資訊28at.com

  • ref: 組件聲明時(shí)傳入的 ref。
  • createHandle: 回調(diào)函數(shù),需要返回 ref 引用的對象,我們也是在這里重寫 ref 引用。
  • deps: 依賴項(xiàng)數(shù)組,可選。state,props 以及內(nèi)部定義的其他變量都可以作為依賴項(xiàng),React 內(nèi)部會(huì)使用 Object.is 來對比依賴項(xiàng)是否發(fā)生了變化。依賴項(xiàng)發(fā)生變化時(shí),createHandle 會(huì)重新執(zhí)行,ref 引用會(huì)更新。如果不傳入依賴項(xiàng),那么每次更新 createHandle 都會(huì)重新執(zhí)行。

在官方文檔中,有這樣一個(gè)案例,演示效果如圖所示,當(dāng)我點(diǎn)擊按鈕時(shí),下方的 input 自動(dòng)獲取焦點(diǎn),并且中間的滾動(dòng)條滾動(dòng)到最底部。FTi28資訊網(wǎng)——每日最新資訊28at.com

FTi28資訊網(wǎng)——每日最新資訊28at.com

我們結(jié)合新的 ref 傳遞機(jī)制和 useImperativeHandle 一起來分析一下這個(gè)案例應(yīng)該怎么實(shí)現(xiàn)。FTi28資訊網(wǎng)——每日最新資訊28at.com

!FTi28資訊網(wǎng)——每日最新資訊28at.com

思考時(shí),請一定要把封裝的思維帶入進(jìn)來,否則可能很難感受到這樣做在解耦上的具體好處FTi28資訊網(wǎng)——每日最新資訊28at.com

首先我們先進(jìn)行組件拆分,將整個(gè)內(nèi)容拆分為按鈕部分與信息部分,信息部分主要負(fù)責(zé)信息的展示與輸入,因此頁面組件大概長這樣FTi28資訊網(wǎng)——每日最新資訊28at.com

<>  <button>Write a comment</button>  <Post /></>

我們期望點(diǎn)擊按鈕時(shí),信息部分的輸入框自動(dòng)獲取焦點(diǎn),信息部分的信息展示區(qū)域能滾動(dòng)到最底部,因此整個(gè)頁面組件的代碼可以表示為如下:FTi28資訊網(wǎng)——每日最新資訊28at.com

import { useRef } from 'react';import Post from './Post.js';export default function Page() {  const postRef = useRef(null);  function handleClick() {    postRef.current.scrollAndFocusAddComment();  }  return (    <>      <button onClick={handleClick}>        Write a comment      </button>      <Post ref={postRef} />    </>  );}

再來思考信息部分。FTi28資訊網(wǎng)——每日最新資訊28at.com

信息部分 Post 又分為兩個(gè)部分,分別是信息展示部分與信息輸入部分。此時(shí)這兩個(gè)部分的 ref 要透傳給 Post,并最終再次透傳給頁面組件。因此他們的組件結(jié)構(gòu)應(yīng)該長這樣。FTi28資訊網(wǎng)——每日最新資訊28at.com

<>  <article>    <p>Welcome to my blog!</p>  </article>  <CommentList ref={commentsRef} />  <AddComment ref={addCommentRef} /></>

這個(gè)時(shí)候,有一個(gè)需要考慮的點(diǎn)就是,有兩個(gè)對象需要被控制,因此我們需要借助 useImperativeHandle 來自定義控制器,并在控制的方法中,整合他們。FTi28資訊網(wǎng)——每日最新資訊28at.com

useImperativeHandle(ref, () => {  return {    scrollAndFocusAddComment() {      commentsRef.current.scrollToBottom();      addCommentRef.current.focus();    }  };}, []);

ref 的傳遞,只需要把它看成是一個(gè)普通的 props 即可,因此,Post 組件完整代碼如下:FTi28資訊網(wǎng)——每日最新資訊28at.com

const Post = ({ref}) => {  const commentsRef = useRef(null);  const addCommentRef = useRef(null);  useImperativeHandle(ref, () => {    return {      scrollAndFocusAddComment() {        commentsRef.current.scrollToBottom();        addCommentRef.current.focus();      }    };  }, []);  return (    <>      <article>        <p>Welcome to my blog!</p>      </article>      <CommentList ref={commentsRef} />      <AddComment ref={addCommentRef} />    </>  );}

同樣的道理,我們只需要把 CommentList 與 AddComment 的 ref 傳遞出來就可以了。FTi28資訊網(wǎng)——每日最新資訊28at.com

所以信息展示部分 CommentList 組件的代碼為。FTi28資訊網(wǎng)——每日最新資訊28at.com

import { useRef, useImperativeHandle } from 'react';const CommentList = ({ref}) => {  const divRef = useRef(null);  useImperativeHandle(ref, () => {    return {      scrollToBottom() {        const node = divRef.current;        node.scrollTop = node.scrollHeight;      }    };  }, []);  let comments = [];  for (let i = 0; i < 50; i++) {    comments.push(<p key={i}>Comment #{i}</p>);  }  return (    <div className="CommentList" ref={divRef}>      {comments}    </div>  );};export default CommentList;

信息輸入部分 AddComment 的代碼為。FTi28資訊網(wǎng)——每日最新資訊28at.com

function AddComment(props) {  return (    <input       placeholder="Add comment..."       ref={props.ref}     />  )};export default AddComment;

與之前相比,確實(shí)要簡單了許多。FTi28資訊網(wǎng)——每日最新資訊28at.com

五、總結(jié)

如果你對封裝解耦比較重視,那么你一定能明顯感受到,ref 與 useImperativeHandle 的結(jié)合能發(fā)揮的想象空間遠(yuǎn)不止于此,這種方式給 React 提供了一種擴(kuò)展 React 能力的重要手段,因此,當(dāng)你成為 React 高手之后,你一定會(huì)非常喜歡使用它們,他們的組合能讓 React 項(xiàng)目變得更加多樣化。FTi28資訊網(wǎng)——每日最新資訊28at.com

本文鏈接:http://www.tebozhan.com/showinfo-26-95554-0.html來自 React 19 的背刺:ForwardRef 被無情拋棄

聲明:本網(wǎng)頁內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問題請及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。郵件:2376512515@qq.com

上一篇: 幾行代碼,優(yōu)雅的避免接口重復(fù)請求

下一篇: 如何更改 .NET 中的默認(rèn)時(shí)區(qū)?

標(biāo)簽:
  • 熱門焦點(diǎn)
Top