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

你想知道的關(guān)于Refs的知識(shí)都在這了

開發(fā) 前端
Refs 提供了一種方式,允許我們?cè)L問 DOM 節(jié)點(diǎn)或在 render 方法中創(chuàng)建的 React 元素。

 [[280681]]

Refs 提供了一種方式,允許我們?cè)L問 DOM 節(jié)點(diǎn)或在 render 方法中創(chuàng)建的 React 元素。

Refs 使用場(chǎng)景

在某些情況下,我們需要在典型數(shù)據(jù)流之外強(qiáng)制修改子組件,被修改的子組件可能是一個(gè) React 組件的實(shí)例,也可能是一個(gè) DOM 元素,例如:

  •  管理焦點(diǎn),文本選擇或媒體播放。
  •  觸發(fā)強(qiáng)制動(dòng)畫。
  •  集成第三方 DOM 庫。

設(shè)置 Refs

1. createRef

支持在函數(shù)組件和類組件內(nèi)部使用

createRef 是 React16.3 版本中引入的。

創(chuàng)建 Refs

使用 React.createRef() 創(chuàng)建 Refs,并通過 ref 屬性附加至 React 元素上。通常在構(gòu)造函數(shù)中,將 Refs 分配給實(shí)例屬性,以便在整個(gè)組件中引用。

訪問 Refs

當(dāng) ref 被傳遞給 render 中的元素時(shí),對(duì)該節(jié)點(diǎn)的引用可以在 ref 的 current 屬性中訪問。 

  1. import React from 'react';  
  2. export default class MyInput extends React.Component {  
  3.     constructor(props) {  
  4.         super(props);  
  5.         //分配給實(shí)例屬性  
  6.         this.inputRef = React.createRef(null);  
  7.     }  
  8.     componentDidMount() {  
  9.         //通過 this.inputRef.current 獲取對(duì)該節(jié)點(diǎn)的引用  
  10.         this.inputRef && this.inputRef.current.focus();  
  11.     }  
  12.     render() {  
  13.         //把 <input> ref 關(guān)聯(lián)到構(gòu)造函數(shù)中創(chuàng)建的 `inputRef` 上  
  14.         return (  
  15.             <input type="text" ref={this.inputRef}/>  
  16.         )  
  17.     }  

ref 的值根據(jù)節(jié)點(diǎn)的類型而有所不同:

  •  當(dāng) ref 屬性用于 HTML 元素時(shí),構(gòu)造函數(shù)中使用 React.createRef() 創(chuàng)建的 ref 接收底層 DOM 元素作為其 current 屬性。
  •  當(dāng) ref 屬性用于自定義的 class 組件時(shí), ref 對(duì)象接收組件的掛載實(shí)例作為其 current 屬性。
  •  不能在函數(shù)組件上使用 ref 屬性,因?yàn)楹瘮?shù)組件沒有實(shí)例。

總結(jié):為 DOM 添加 ref,那么我們就可以通過 ref 獲取到對(duì)該DOM節(jié)點(diǎn)的引用。而給React組件添加 ref,那么我們可以通過 ref 獲取到該組件的實(shí)例【不能在函數(shù)組件上使用 ref 屬性,因?yàn)楹瘮?shù)組件沒有實(shí)例】。

2. useRef

僅限于在函數(shù)組件內(nèi)使用

useRef 是 React16.8 中引入的,只能在函數(shù)組件中使用。

創(chuàng)建 Refs

使用 React.useRef() 創(chuàng)建 Refs,并通過 ref 屬性附加至 React 元素上。 

  1. const refContainer = useRef(initialValue); 

useRef 返回的 ref 對(duì)象在組件的整個(gè)生命周期內(nèi)保持不變。

訪問 Refs

當(dāng) ref 被傳遞給 React 元素時(shí),對(duì)該節(jié)點(diǎn)的引用可以在 ref 的 current 屬性中訪問。 

  1. import React from 'react';  
  2. export default function MyInput(props) {  
  3.     const inputRef = React.useRef(null);  
  4.     React.useEffect(() => {  
  5.         inputRef.current.focus();  
  6.     });  
  7.     return (  
  8.         <input type="text" ref={inputRef} />  
  9.     )  

關(guān)于 React.useRef() 返回的 ref 對(duì)象在組件的整個(gè)生命周期內(nèi)保持不變,我們來和 React.createRef() 來做一個(gè)對(duì)比,代碼如下: 

  1. import React, { useRef, useEffect, createRef, useState } from 'react';  
  2. function MyInput() {  
  3.     let [count, setCount] = useState(0);  
  4.     const myRef = createRef(null);  
  5.     const inputRef = useRef(null);  
  6.     //僅執(zhí)行一次  
  7.     useEffect(() => {  
  8.         inputRef.current.focus();  
  9.         window.myRef = myRef;  
  10.         window.inputRef = inputRef;  
  11.     }, []);    
  12.     useEffect(() => {  
  13.         //除了第一次為true, 其它每次都是 false 【createRef】  
  14.         console.log('myRef === window.myRef', myRef === window.myRef);  
  15.         //始終為true 【useRef】  
  16.         console.log('inputRef === window.inputRef', inputRef === window.inputRef);  
  17.     })  
  18.     return (  
  19.         <>  
  20.             <input type="text" ref={inputRef}/>  
  21.             <button onClick={() => setCount(count+1)}>{count}</button>  
  22.         </>  
  23.     )  

3. 回調(diào) Refs

支持在函數(shù)組件和類組件內(nèi)部使用

React 支持 回調(diào) refs 的方式設(shè)置 Refs。這種方式可以幫助我們更精細(xì)的控制何時(shí) Refs 被設(shè)置和解除。

使用 回調(diào) refs 需要將回調(diào)函數(shù)傳遞給 React元素 的 ref 屬性。這個(gè)函數(shù)接受 React 組件實(shí)例 或 HTML DOM 元素作為參數(shù),將其掛載到實(shí)例屬性上,如下所示: 

  1. import React from 'react';  
  2. export default class MyInput extends React.Component {  
  3.     constructor(props) {  
  4.         super(props);  
  5.         this.inputRef = null 
  6.         this.setTextInputRef = (ele) => {  
  7.             this.inputRef = ele 
  8.         }  
  9.     }  
  10.     componentDidMount() {  
  11.         this.inputRef && this.inputRef.focus();  
  12.     }  
  13.     render() {  
  14.         return (  
  15.             <input type="text" ref={this.setTextInputRef}/>  
  16.         )  
  17.     }  

React 會(huì)在組件掛載時(shí),調(diào)用 ref 回調(diào)函數(shù)并傳入 DOM元素(或React實(shí)例),當(dāng)卸載時(shí)調(diào)用它并傳入 null。在 componentDidMoune 或 componentDidUpdate 觸發(fā)前,React 會(huì)保證 Refs 一定是最新的。

可以在組件間傳遞回調(diào)形式的 refs. 

  1. import React from 'react';  
  2. export default function Form() {  
  3.     let ref = null 
  4.     React.useEffect(() => {  
  5.         //ref 即是 MyInput 中的 input 節(jié)點(diǎn)  
  6.         ref.focus();  
  7.     }, [ref]);  
  8.     return (  
  9.         <>  
  10.             <MyInput inputRef={ele => ref = ele/>  
  11.             {/** other code */}  
  12.         </>  
  13.     )  
  14.  
  15. function MyInput (props) {  
  16.     return (  
  17.         <input type="text" ref={props.inputRef}/>  
  18.     )  

4. 字符串 Refs(過時(shí)API)

函數(shù)組件內(nèi)部不支持使用 字符串 refs [支持 createRef | useRef | 回調(diào) Ref] 

  1. function MyInput() {  
  2.     return (  
  3.         <>  
  4.             <input type='text' ref={'inputRef'} />  
  5.         </>  
  6.     )  

類組件

通過 this.refs.XXX 獲取 React 元素。 

  1. class MyInput extends React.Component {  
  2.     componentDidMount() {  
  3.         this.refs.inputRef.focus();  
  4.     }  
  5.     render() {  
  6.         return (  
  7.             <input type='text' ref={'inputRef'} />  
  8.         )  
  9.     }  

Ref 傳遞

在 Hook 之前,高階組件(HOC) 和 render props 是 React 中復(fù)用組件邏輯的主要手段。

盡管高階組件的約定是將所有的 props 傳遞給被包裝組件,但是 refs 是不會(huì)被傳遞的,事實(shí)上, ref 并不是一個(gè) prop,和 key 一樣,它由 React 專門處理。

這個(gè)問題可以通過 React.forwardRef (React 16.3中新增)來解決。在 React.forwardRef 之前,這個(gè)問題,我們可以通過給容器組件添加 forwardedRef (prop的名字自行確定,不過不能是 ref 或者是 key).

React.forwardRef 之前 

  1. import React from 'react';  
  2. import hoistNonReactStatic from 'hoist-non-react-statics';  
  3. const withData = (WrappedComponent) => {  
  4.     class ProxyComponent extends React.Component {  
  5.         componentDidMount() {  
  6.             //code  
  7.         }  
  8.         //這里有個(gè)注意點(diǎn)就是使用時(shí),我們需要知道這個(gè)組件是被包裝之后的組件  
  9.         //將ref值傳遞給 forwardedRef 的 prop  
  10.         render() {  
  11.             const {forwardedRef, ...remainingProps} = this.props; 
  12.              return (  
  13.                 <WrappedComponent ref={forwardedRef} {...remainingProps}/>  
  14.             )  
  15.         }  
  16.     }  
  17.     //指定 displayName.   未復(fù)制靜態(tài)方法(重點(diǎn)不是為了講 HOC)  
  18.     ProxyComponent.displayName = WrappedComponent.displayName || WrappedComponent.name || 'Component';  
  19.     //復(fù)制非 React 靜態(tài)方法  
  20.     hoistNonReactStatic(ProxyComponent, WrappedComponent);  
  21.     return ProxyComponent;  

這個(gè)示例中,我們將 ref 的屬性值通過 forwardedRef 的 prop,傳遞給被包裝的組件,使用: 

  1. class MyInput extends React.Component {  
  2.     render() {  
  3.         return (  
  4.             <input type="text" {...this.props} />  
  5.         )  
  6.     }  
  7.  
  8. MyInput = withData(MyInput);  
  9. function Form(props) {  
  10.     const inputRef = React.useRef(null);  
  11.     React.useEffect(() => {  
  12.         console.log(inputRef.current)  
  13.     })  
  14.     //我們?cè)谑褂?nbsp;MyInput 時(shí),需要區(qū)分其是否是包裝過的組件,以確定是指定 ref 還是 forwardedRef  
  15.     return (  
  16.         <MyInput forwardedRef={inputRef} />  
  17.     )  

React.forwardRef

Ref 轉(zhuǎn)發(fā)是一項(xiàng)將 ref 自動(dòng)地通過組件傳遞到其一子組件的技巧,其允許某些組件接收 ref,并將其向下傳遞給子組件。

轉(zhuǎn)發(fā) ref 到DOM中: 

  1. import React from 'react';  
  2. const MyInput = React.forwardRef((props, ref) => {  
  3.     return (  
  4.         <input type="text" ref={ref} {...props} />  
  5.     )  
  6. });  
  7. function Form() {  
  8.     const inputRef = React.useRef(null);  
  9.     React.useEffect(() => {  
  10.         console.log(inputRef.current);//input節(jié)點(diǎn)  
  11.     })  
  12.     return (  
  13.         <MyInput ref={inputRef} />  
  14.     )  
  1.  調(diào)用 React.useRef 創(chuàng)建了一個(gè) React ref 并將其賦值給 ref 變量。
  2.  指定 ref 為JSX屬性,并向下傳遞 <MyInput ref={inputRef}>
  3.  React 傳遞 ref 給 forwardRef 內(nèi)函數(shù) (props, ref) => ... 作為其第二個(gè)參數(shù)。
  4.  向下轉(zhuǎn)發(fā)該 ref 參數(shù)到 <button ref={ref}>,將其指定為JSX屬性
  5.  當(dāng) ref 掛載完成,inputRef.current 指向 input DOM節(jié)點(diǎn)

注意

第二個(gè)參數(shù) ref 只在使用 React.forwardRef 定義組件時(shí)存在。常規(guī)函數(shù)和 class 組件不接收 ref 參數(shù),且 props 中也不存在 ref。

在 React.forwardRef 之前,我們?nèi)绻雮鬟f ref 屬性給子組件,需要區(qū)分出是否是被HOC包裝之后的組件,對(duì)使用來說,造成了一定的不便。我們來使用 React.forwardRef 重構(gòu)。 

  1. import React from 'react';  
  2. import hoistNonReactStatic from 'hoist-non-react-statics';  
  3. function withData(WrappedComponent) {  
  4.     class ProxyComponent extends React.Component {  
  5.         componentDidMount() {  
  6.             //code  
  7.         }  
  8.         render() {  
  9.             const {forwardedRef, ...remainingProps} = this.props;  
  10.             return (  
  11.                 <WrappedComponent ref={forwardedRef} {...remainingProps}/>  
  12.             )  
  13.         }  
  14.     }    
  15.     //我們?cè)谑褂帽粀ithData包裝過的組件時(shí),只需要傳 ref 即可  
  16.     const forwardRef = React.forwardRef((props, ref) => (  
  17.         <ProxyComponent {...props} forwardedRef={ref} />  
  18.     ));  
  19.     //指定 displayName.  
  20.     forwardRef.displayName = WrappedComponent.displayName || WrappedComponent.name || 'Component';  
  21.     return hoistNonReactStatic(forwardRef, WrappedComponent);  
  22.  
  1. class MyInput extends React.Component {  
  2.     render() {  
  3.         return (  
  4.             <input type="text" {...this.props} />  
  5.         )  
  6.     }  
  7.  
  8. MyInput.getName = function() {  
  9.     console.log('name');  
  10.  
  11. MyInput = withData(MyInput);  
  12. console.log(MyInput.getName); //測(cè)試靜態(tài)方法拷貝是否正常  
  13. function Form(props) {  
  14.     const inputRef = React.useRef(null);  
  15.     React.useEffect(() => {  
  16.         console.log(inputRef.current);//被包裝組件MyInput  
  17.     })  
  18.     //在使用時(shí),傳遞 ref 即可  
  19.     return (  
  20.         <MyInput ref={inputRef} />  
  21.     )  

react-redux 中獲取子組件(被包裝的木偶組件)的實(shí)例

舊版本中(V4 / V5)

我們知道,connect 有四個(gè)參數(shù),如果我們想要在父組件中子組件(木偶組件)的實(shí)例,那么需要設(shè)置第四個(gè)參數(shù) options 的 withRef 為 true。隨后可以在父組件中通過容器組件實(shí)例的 getWrappedInstance() 方法獲取到木偶組件(被包裝的組件)的實(shí)例,如下所示: 

  1. //MyInput.js  
  2. import React from 'react';  
  3. import { connect } from 'react-redux';  
  4. class MyInput extends React.Component {  
  5.     render() {  
  6.         return (  
  7.             <input type="text" />  
  8.         )  
  9.     }  
  10.  
  11. export default connect(null, null, null, { withRef: true })(MyInput);  
  1. //index.js  
  2. import React from "react";  
  3. import ReactDOM from "react-dom";  
  4. import { createStore } from 'redux';  
  5. import { Provider } from 'react-redux';  
  6. import MyInput from './MyInput';  
  7. function reducer(state, action) {  
  8.     return state;  
  9.  
  10. const store = createStore(reducer);  
  11. function Main() {  
  12.     let ref = React.createRef();  
  13.     React.useEffect(() => {  
  14.         console.log(ref.current.getWrappedInstance());  
  15.     })  
  16.     return (  
  17.         <Provider store={store}>  
  18.             <MyInput ref={ref} />  
  19.         </Provider>  
  20.     )  
  21.  
  22. ReactDOM.render(<Main />, document.getElementById("root")); 

這里需要注意的是:MyInput 必須是類組件,而函數(shù)組件沒有實(shí)例,自然也無法通過 ref 獲取其實(shí)例。react-redux 源碼中,通過給被包裝組件增加 ref 屬性,getWrappedInstance 返回的是該實(shí)例 this.refs.wrappedInstance。 

  1. if (withRef) {  
  2.     this.renderedElement = createElement(WrappedComponent, {  
  3.         ...this.mergedProps,  
  4.         ref: 'wrappedInstance'  
  5.     })  

新版本(V6 / V7)

react-redux新版本中使用了 React.forwardRef方法進(jìn)行了 ref 轉(zhuǎn)發(fā)。 自 V6 版本起,option 中的 withRef 已廢棄,如果想要獲取被包裝組件的實(shí)例,那么需要指定 connect 的第四個(gè)參數(shù) option 的 forwardRef 為 true,具體可見下面的示例: 

  1. //MyInput.js 文件  
  2. import React from 'react';  
  3. import { connect } from 'react-redux';  
  4. class MyInput extends React.Component {  
  5.     render() {  
  6.         return (  
  7.             <input type="text" />  
  8.         )  
  9.     }  
  10.  
  11. export default connect(null, null, null, { forwardRef: true })(MyInput); 

直接給被包裝過的組件增加 ref,即可以獲取到被包裝組件的實(shí)例,如下所示: 

  1. //index.js  
  2. import React from "react";  
  3. import ReactDOM from "react-dom";  
  4. import { createStore } from 'redux';  
  5. import { Provider } from 'react-redux';  
  6. import MyInput from './MyInput';  
  7. function reducer(state, action) {  
  8.     return state;  
  9.  
  10. const store = createStore(reducer);  
  11. function Main() {  
  12.     let ref = React.createRef();  
  13.     React.useEffect(() => {  
  14.         console.log(ref.current);  
  15.     })  
  16.     return (  
  17.         <Provider store={store}>  
  18.             <MyInput ref={ref} />  
  19.         </Provider>  
  20.     )  
  21.  
  22. ReactDOM.render(<Main />, document.getElementById("root")); 

同樣,MyInput 必須是類組件,因?yàn)楹瘮?shù)組件沒有實(shí)例,自然也無法通過 ref 獲取其實(shí)例。

react-redux 中將 ref 轉(zhuǎn)發(fā)至 Connect 組件中。通過 forwardedRef 傳遞給被包裝組件 WrappedComponent 的 ref。  

  1. if (forwardRef) {    
  2.     const forwarded = React.forwardRef(function forwardConnectRef(    
  3.         props,    
  4.         ref    
  5.     ) {    
  6.         return <Connect {...props} forwardedRef={ref} />    
  7.     })    
  8.     forwarded.displayName = displayName    
  9.     forwarded.WrappedComponent = WrappedComponent    
  10.     return hoistStatics(forwarded, WrappedComponent)    
  11. }    
  12. //...    
  13. const { forwardedRef, ...wrapperProps } = props    
  14. const renderedWrappedComponent = useMemo(    
  15.     () => <WrappedComponent {...actualChildProps} ref={forwardedRef} />,   
  16.     [forwardedRef, WrappedComponent, actualChildProps]  
  17.   

 

責(zé)任編輯:龐桂玉 來源: segmentfault
相關(guān)推薦

2021-06-17 13:40:47

區(qū)塊鏈比特幣公有鏈

2022-09-15 14:22:19

協(xié)作規(guī)范前后端

2018-11-28 10:39:01

5G網(wǎng)絡(luò)運(yùn)營(yíng)商

2017-08-30 14:20:00

H5公益騰訊

2023-09-11 08:51:23

LinkedList雙向鏈表線程

2018-03-31 08:45:52

iPhone交通卡iOS 11.3

2019-11-04 09:07:48

DevOps互聯(lián)網(wǎng)IT

2019-04-24 08:31:43

分布式限流kafka

2017-01-11 08:37:07

Apache SparStreamingDataFrames

2021-07-02 14:09:36

開發(fā)技能代碼

2020-03-18 18:20:19

區(qū)塊鏈數(shù)字貨幣比特幣

2018-06-26 04:49:46

運(yùn)營(yíng)商流量漫游提速降費(fèi)

2017-12-13 14:24:08

Google 開發(fā)者瀏覽器

2019-04-26 09:38:36

中臺(tái)平臺(tái)化轉(zhuǎn)型

2020-08-14 11:05:35

Wi-Fi5G手機(jī)

2022-11-08 15:55:34

鴻蒙開發(fā)套件

2020-09-15 17:10:36

Wi-Fi6路由5G

2020-09-17 11:29:41

路由器設(shè)備緩存

2017-08-15 15:35:21

大數(shù)據(jù)數(shù)據(jù)分析薪資秘密

2017-08-15 16:05:18

大數(shù)據(jù)數(shù)據(jù)分析薪資秘密
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 亚洲综合免费 | 国产精品视频久久久久 | 国产精品久久久久久影院8一贰佰 | 91精品国产自产精品男人的天堂 | 天天玩天天干天天操 | 国产草草视频 | 男人的天堂视频网站 | 日韩欧美在线一区二区 | 中文在线亚洲 | 呦呦在线视频 | 国产精品成人在线 | 久久99国产精一区二区三区 | 黄色一级电影在线观看 | 久久精品国产一区二区电影 | 成人精品国产 | 亚洲一区二区三区免费观看 | 精品福利av导航 | 欧美日韩成人一区二区 | 日本一区二区不卡 | 国内自拍偷拍 | 一级在线毛片 | 国产亚洲精品久久19p | 91精品国产一区二区三区 | 亚洲精品视频免费 | 国产精品无码久久久久 | 久久看看 | 欧美成人一区二区三区 | 欧美精品在线观看 | 精品成人免费视频 | 午夜网站视频 | 成人亚洲片 | 久久国内精品 | 美女啪啪国产 | 在线国产视频 | 日韩精品1区2区3区 国产精品国产成人国产三级 | 懂色av色香蕉一区二区蜜桃 | 综合五月 | 成人一区二区三区在线 | 久久三区| 国产日韩中文字幕 | 成人在线一区二区三区 |