react中的refs


概述

很久之前就知道refs,感覺好神秘,恰好今天突然發現字符串形式的ref在官網不推薦使用了,於是好好總結一下ref的用法,供以后開發時參考,相信對其他人也有用。

參考資料:
Refs & DOM
Forwarding Refs

refs

在react數據流中,可以通過props,refs和Context來訪問其它組件的屬性,其中利用refs可以在數據流外強制修改組件實例。

需要注意的是,以前是通過給refs賦一個string,比如textInput,然后就可以通過this.refs.textInput來訪問DOM節點,示例如下:

import React, { Component } from 'react';

class NoControl extends Component {
    constructor(props) {
        super(props);
        this.handleSubmit = this.handleSubmit.bind(this);
    }
    handleSubmit(e) {
        e.preventDefault();
        console.log(this.refs.name);
    }

    render() {
        return(
            <form onSubmit={this.handleSubmit}>
                <input type="text" ref="name"/>
                <button type="submit">Submit</button>
            </form>
        );
    }
}

export default NoControl;

但是官網不推薦使用這種形式使用refs了,並且這種方法在未來的版本可能會被移除。官方建議使用回調的形式代替這種使用方式。

refs的基本用法

一般說來,我們需要在constructor里面初始化一個ref,然后就能在return里面用了,示例如下:

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.myRef = React.createRef();
  }
  render() {
    return <div ref={this.myRef} />;
  }
}

上面的this.myRef有一個current屬性,它的值取決於下面三種情況:

  1. 如果ref屬性被用於html元素,那么它的值是底層DOM元素。
  2. 如果ref屬性被用於自定義類組件,那么它的值是已掛載的這個自定義類組件的實例。
  3. 函數式組件沒有ref屬性。

另外,通過ref我們還可以調用這個自定義類組件的方法,示例如下:

import React, { Component } from 'react';

class CustomInput extends Component {
    constructor(props) {
        super(props);
        this.handleFocus = this.handleFocus.bind(this);
        this.myRef = React.createRef();
    }

    handleFocus(e) {
        this.myRef.current.focus();
    }
    render() {
        return(
            <input type="text" ref={this.myRef}/>
        )
    }

}

class NoControl extends Component {
    constructor(props) {
        super(props);
        this.handleSubmit = this.handleSubmit.bind(this);
        this.myRef = React.createRef();
    }
    handleSubmit(e) {
        e.preventDefault();
        this.myRef.current.handleFocus();
    }

    render() {
        return(
            <form onSubmit={this.handleSubmit}>
                <CustomInput ref={this.myRef}/>
                <button type="submit">Submit</button>
            </form>
        );
    }
}

export default NoControl;

refs的回調用法

由於refs里面的回調函數會在組件創建的時候自動生成。所以可以利用refs的回調用法,在組件創建的時候獲得這個組件的一些信息,比如獲得焦點等。示例如下:

import React, { Component } from 'react';

class NoControl extends Component {
    constructor(props) {
        super(props);
        this.handleSubmit = this.handleSubmit.bind(this);
        this.setElement = this.setElement.bind(this);
        this.myInput = null;
    }

    handleSubmit(e) {
        e.preventDefault();
        this.forceUpdate();
    }

    setElement(element) {
        this.myInput = element;
    }

    componentDidMount() {
        this.myInput.focus();
    }
    
    render() {
        return(
            <form onSubmit={this.handleSubmit}>
                <input type="text" ref={this.setElement}/>
                <button type="submit">Submit</button>
            </form>
        );
    }
}

export default NoControl;

refs轉發

在使用HOC(高階組件)的時候,我們是用一個類組件來對普通組件進行封裝的,這個時候怎么獲得里面這個普通組件的ref呢。

react官方提供了React.forwardRef這個api來實現。示例如下:

//NoControl.jsx
import React, { Component } from 'react';
import CustomInput from './CustomInput';

class NoControl extends Component {
    constructor(props) {
        super(props);
        this.handleSubmit = this.handleSubmit.bind(this);
        this.myRef = React.createRef();
    }
    handleSubmit(e) {
        e.preventDefault();
        this.myRef.current.handleFocus();
        this.forceUpdate();
    }

    render() {
        return(
            <form onSubmit={this.handleSubmit}>
                <CustomInput ref={this.myRef}/>
                <button type="submit">Submit</button>
            </form>
        );
    }
}

export default NoControl;


//CustomInput.jsx
import React, { Component } from 'react';

function logProps(Component) {
    class LogProps extends React.Component {
        componentDidUpdate(prevProps) {
            console.log('old props:', prevProps);
            console.log('new props:', this.props);
        }
        render() {
            console.log('HOC exists;');
            const { forwardedRef, ...rest } = this.props;
            return <Component ref={forwardedRef} {...rest} />;
        }
    }
    function forwardRef(props, ref) {
        return <LogProps {...props} forwardedRef={ref} />;
    }
    return React.forwardRef(forwardRef);
}

class CustomInput extends Component {
    constructor(props) {
        super(props);
        this.handleFocus = this.handleFocus.bind(this);
        this.myRef = React.createRef();
    }

    handleFocus(e) {
        this.myRef.current.focus();
    }
    render() {
        return(
            <input type="text" ref={this.myRef}/>
        );
    }
}

export default logProps(CustomInput);

需要注意的是,forwardRef有第二個參數ref,然后它被React.forwardRef這個api封裝,最后返回Component類組件。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM