Refs and the DOM
Refs
  • A ref is an identifier that React uses to reference DOM elements
  • import React from 'react';
    import ReactDOM from 'react-dom';
    import PropTypes from 'prop-types';
    
    import { Component } from 'react'
    class AddColorForm extends Component {
    	constructor(props) {
        		super(props)
        		this.submit = this.submit.bind(this)
      	}
    
    	submit(e) {
        		const { _title, _color } = this.refs
        		e.preventDefault();
        		alert(`New Color: ${_title.value} ${_color.value}`)
        		_title.value = '';
        		_color.value = '#000000';
        		_title.focus();
    	}
    
    	render() {
    		return (
    			<form onSubmit={this.submit}>
                  			<input ref="_title" type="text"
                         			placeholder="color title..." required/>
                  			<input ref="_color" type="color" required/>
                  			<button>ADD</button>
              		</form>
    		) }
    }
    
    ReactDOM.render(<AddColorForm />, document.getElementById('root'));
    		
    React.createRef
  • When the ref attribute is used on an HTML element, the ref created in the constructor with React.createRef() receives the underlying DOM element as its current property
  • When the ref attribute is used on a custom class component, the ref object receives the mounted instance of the component as its current
  • Not use the ref attribute on function components because they don’t have instances
  • import React from 'react';
    import ReactDOM from 'react-dom';
    import PropTypes from 'prop-types';
    
    import { Component } from 'react'
    class AddColorForm extends Component {
    	constructor(props) {
        		super(props)
        		this.submit = this.submit.bind(this)
    		this._title = React.createRef();
    		this._color = React.createRef();
      	}
    
    	submit(e) {
    		const _title = this._title.current;
    		const _color = this._color.current;
        		e.preventDefault();
        		alert(`New Color: ${_title.value} ${_color.value}`)
        		_title.value = '';
        		_color.value = '#000000';
        		_title.focus();
    	}
    
    	render() {
    		return (
    			<form onSubmit={this.submit}>
                  			<input ref={this._title} type="text"
                         			placeholder="color title..." required/>
                  			<input ref={this._color} type="color" required/>
                  			<button>ADD</button>
              		</form>
    		) }
    }
    
    ReactDOM.render(<AddColorForm />, document.getElementById('root'));
    		
    import React from 'react';
    import ReactDOM from 'react-dom';
    
    class CustomTextInput extends React.Component {
      constructor(props) {
        super(props);
        // create a ref to store the textInput DOM element
        this.textInput = React.createRef();
        this.focusTextInput = this.focusTextInput.bind(this);
      }
    
      focusTextInput() {
        // Explicitly focus the text input using the raw DOM API
        // Note: we're accessing "current" to get the DOM node
        this.textInput.current.focus();
      }
    
      render() {
        // tell React that we want to associate the <input> ref
        // with the `textInput` that we created in the constructor
        return (
          <div>
            <input
              type="text"
              ref={this.textInput} />
    
            <input
              type="button"
              value="Focus the text input"
              onClick={this.focusTextInput}
            />
          </div>
        );
      }
    }
    
    class AutoFocusTextInput extends React.Component {
      constructor(props) {
        super(props);
        this.text = React.createRef();
      }
    
      componentDidMount() {
        this.text.current.focusTextInput();
      }
    
      render() {
        return (
          <CustomTextInput ref={this.text} />
        );
      }
    }
    
    ReactDOM.render(<AutoFocusTextInput />, document.getElementById('root'));
    		
    Forwarding Refs
  • Not access to a child’s DOM node from a parent component, it breaks component encapsulation
  • Ref forwarding lets components opt into exposing any child component’s ref as their own
    1. Create a React ref by calling React.createRef and assign it to a ref variable
    2. Pass ref down to <Button ref={ref}> by specifying it as a JSX attribute
    3. React passes the ref to the (props, ref) => ... function inside forwardRef as a second argument
    4. Forward this ref argument down to <button ref={ref}> by specifying it as a JSX attribute
    5. When the ref is attached, ref.current will point to the <button> DOM node
    import React from 'react';
    import ReactDOM from 'react-dom';
    
    class ButtonGroup extends React.Component {
      constructor(props) {
        super(props);
        this.textValue = React.createRef();
      }
    
      componentDidMount() {
        console.log(this.textValue.current.innerHTML);
      }
    
      render() {
        return (
          <div>
    	    <Button ref = {this.textValue} />
          </div>
        );
      }
    }
    
    const Button = React.forwardRef((props, ref) => (
    	<button ref={ref}>Submit</button>
    ))
    
    ReactDOM.render(<ButtonGroup />, document.getElementById('root'));