成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

React高手都善于使用useImprativeHandle

開發 前端
在 React Hooks 中,useImperativeHandle 是一個非常簡單的 Hook,他比較小眾,剛開始接觸 React 學習的朋友可能并不熟悉他。不過對于 React 頂尖高手而言,這是非常重要的 Hook,他能讓我們對 React 的使用變得更加得心應手。應對更多更復雜的場景。

一、useRef

學習 useImperativeHandle,得從 useRef 說起。我們前面已經學習過了 useRef,它能夠結合元素組件的 ref 屬性幫我們拿到該元素組件對應的真實 DOM。

例如,我想要拿到一個 input 元素的真實 DOM 對象,并調用 input 的 .focus() 方法,讓 input 獲得焦點。

import {useRef} from "react";

export default function Demo() {
  const inputRef = useRef<HTMLInputElement>(null);

  const focusTextInput = () => {
    if (inputRef.current) {
      inputRef.current.focus();
    }
  }

  return (
    <>
      <input type="text" ref={inputRef} />
      <button onClick={focusTextInput}>
        點擊我讓input組件獲得焦點
      </button>
    </>
  );
}

每一個 React 提供的元素組件,都具備 ref 屬性。在上面的章節中我們可以知道,當我們拿到了元素的原生 DOM 對象之后,就可以脫離 React 的開發思路,從而應對更多更復雜的場景。

那么問題就來了,原生組件有自己的 ref 屬性,那么自定義組件呢?當然是沒有的,因此我們得自己想辦法處理。

二、forwardRef

forwardRef 能夠在我們自定義組件時,把內部組件的 ref 屬性傳遞給父組件。

它接受我們自定義的組件作為參數,并返回一個新的組件。新組件具備我們自定義組件的全部能力,并得到一個 ref 屬性,父組件通過 useRef 獲取到的內容與內部組件的 ref 完全一致。

我們來看一個案例。

現在我們要實現如下效果,當點擊 Edit 按鈕時,輸入框自動獲得焦點。

我們知道,在 DOM 中,只要得到 input 對象,然后就可以調用 .focus() 方法來實現目標?,F在我們要封裝一個自定義的 MyInput 組件,他具備 input 同樣的能力,同時,我們還要封裝一個標題進去。

<label>Enter your name</label>
<input />

我們的代碼如下:

import {forwardRef, LegacyRef} from 'react'

type MyInputProps = React.InputHTMLAttributes<HTMLInputElement> & {
  label: string
}

function MyInput(props: MyInputProps, ref: LegacyRef<HTMLInputElement>) {
  const {label, ...other} = props

  return (
    <label>
      {label}
      <input {...other} ref={ref} />
    </label>
  )
}

export default forwardRef(MyInput)

MyInput 在聲明時要傳入兩個參數,一個 props,一個 ref。通過展開運算符,我們能夠確保 MyInput 支持 input 所有的屬性。

封裝好之后,我們就可以在點擊實踐中,通過 ref 得到的引用去調用 .focus() 達到 input 獲取焦點的目標。

import { useRef } from 'react'
import MyInput from './MyInput'

export default function ImperativeHandle() {
  const ref = useRef<any>(null)

  function handleClick() {
    ref.current?.focus()
  }

  return (
    <form>
      <MyInput 
        label='Enter your name:' 
        ref={ref} 
      />
      <button type='button' onClick={handleClick}>Edit</button>
    </form>
  )
}

三、useImperativeHandle

在實踐中,很多時候,我們并不想通過 ref 去獲取子組件內部的某個元素組件的真實 DOM 對象。而是希望父組件能夠調用子組件內部的某些方法

但是在 React 中,又無法直接 new 一個子組件的實例,像面向對象那樣通過子組件實例去調用子組件的方法。

因此,React 提供了一個 hook,useImperativeHandle,讓我們能夠重寫子組件內部 ref 對應的引用,從而達到在父組件中,調用子組件內部方法的目的

例如,上面的 MyInput 組件,我們可以修改代碼為:

import {forwardRef, useImperativeHandle, useRef} from 'react'

type MyInputProps = React.InputHTMLAttributes<HTMLInputElement> & {
  label: string
}

function MyInput(props: MyInputProps, ref: any) {
  const {label, ...other} = props
  const inputRef = useRef<any>(null)

  useImperativeHandle(ref, () => {
    return {
      focus() {
        inputRef.current.focus()
      }
    }
  }, [])

  return (
    <label>
      {label}
      <input {...other} ref={inputRef} />
    </label>
  )
}

export default forwardRef(MyInput)
useImperativeHandle(
  ref, 
  createHandle, 
  dependencies?
)

useImperativeHandle 接收三個參數,分別是

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

useImperativeHandle 執行本身返回 undefined。

四、官方案例

官方文檔中有這種一個案例,效果如圖所示。當點擊按鈕時,我希望下方的 input 自動獲得焦點,并切中間的滾動條滾動到最底部。

現在,我們結合前面的知識來分析一下這個案例應該如何實現。

首先我們先進行組件拆分,將整個內容拆分為按鈕部分與信息部分,信息部分主要負責信息的暫時與輸入,因此頁面組件大概長這樣。

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

我們期望點擊按鈕時,信息部分的輸入框自動獲取焦點,信息部分的信息展示區域能滾動到最底部,因此整個頁面組件的代碼可以表示為如下:

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} />
    </>
  );
}

信息部分 Post 又分為兩個部分,分別是信息展示部分與信息輸入部分。

此時這兩個部分的 ref 要透傳給 Post,并最終再次透傳給頁面組件。

所以信息展示部分 CommentList 組件的代碼為。

import { forwardRef, useRef, useImperativeHandle } from 'react';

const CommentList = forwardRef(function CommentList(props, 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 的代碼為。

import { forwardRef, useRef, useImperativeHandle } from 'react';

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

export default AddComment;

Post 要把他們整合起來。

import { forwardRef, useRef, useImperativeHandle } from 'react';
import CommentList from './CommentList.js';
import AddComment from './AddComment.js';

const Post = forwardRef((props, 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} />
    </>
  );
});

export default Post;

這樣,我們整個案例的代碼就寫完了。useRef、useImprativeHandle、forwardRef 一起配合幫助我們完成了這個功能。

責任編輯:姜華 來源: 這波能反殺
相關推薦

2013-03-18 09:30:14

大數據IT

2020-05-29 10:18:58

python開發代碼

2023-12-20 14:48:26

2024-01-16 08:43:51

React底層機制Hook

2011-05-26 10:04:30

程序員

2024-02-05 21:48:25

VueReactHooks

2018-05-25 15:10:14

360手機衛士

2009-07-16 13:51:43

2018-03-15 09:07:37

手機垃圾文件清理

2022-04-18 17:28:14

React前端

2024-01-25 09:04:25

2009-03-02 10:14:00

2009-12-29 15:32:01

架構師

2022-04-08 10:15:29

VueReacHooks

2024-02-26 12:10:37

2024-02-01 09:05:30

ContextReact性能優化

2011-05-16 16:59:41

SEO

2009-04-15 10:49:01

木馬釋放器卡巴斯基

2019-11-07 21:41:21

AndroidiOS不同

2023-11-09 16:20:32

Vue.jsReact前端
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 水蜜桃亚洲一二三四在线 | 国产精品自产拍 | 男女羞羞视频在线 | 一级毛片播放 | 少妇午夜一级艳片欧美精品 | 国产成人精品在线播放 | 99精品久久久国产一区二区三 | 欧美性受xxxx白人性爽 | 国产精品久久久久一区二区三区 | 欧美福利精品 | 在线播放91| 亚洲免费福利视频 | 九色91视频 | 免费h在线 | 日韩av免费看 | 国产精品99久久久久 | 中文精品视频 | 亚洲精品久| 亚洲精品国产成人 | 国产精品综合色区在线观看 | 日韩视频在线免费观看 | 色综合久久久久 | 国产成人免费视频网站视频社区 | 国产视频久久 | 国产精品99久久久久久久久久久久 | 成人av大全 | 中文精品久久 | 蜜桃在线视频 | 成人高清视频在线观看 | 国产草草视频 | 国产精品久久久久无码av | 欧美精品在线一区二区三区 | 爱综合 | 亚洲 欧美 另类 综合 偷拍 | 亚洲人在线 | 中文字幕国产视频 | 亚洲成人免费在线观看 | 欧美精品一区三区 | 欧美日韩不卡合集视频 | www.五月婷婷.com | 在线色 |