Blog · GitLab (User) Created at 2018-2-13 14:13:52 Updated at 2018-4-19 15:56:49 Tomáš Hübelbauer
Bookmark React in Patterns

React

Refs

Refs are useful for when you need to do imperative stuff over a React component (these are declarative).

Imagine you are building a React autocomplete textbox component. The idea is fairly simple: render a container with an input in it and a select underneath. After each keystroke in the input, fire off an AJAX request or something and when it comes back, update the select with new items. Of course it is more involved than that:

Once you click an option in the select you want the input to reflect it and move the focus back on it, because the select will capture it after the click.

This is where refs come in.

In prior versions of React refs were strings you tagged your elements with and you had the React.findDOMNode API to look up a DOM node based on the ref name.

This is no longer the case and refs are now functions which fire with an instance of the DOM node once the DOM node mounts and with null when it unmounts.

Here's how you can take advantage of that:

class AutocompleteTextBox extends React.Component {
    constructor(props) {
        super(props);
        this.state = { value: '', suggestions: [] };
    }

    onValueRef = node => {
        this.inputNode = node;
    }

    onValueChange = event => {
        const value = event.target.value;
        this.setState({ suggestions: [ value + "a", value + "b", value + "c" ], value });
    }

    onSuggestionSelect => event => {
        const suggestion = event.target.value;
        this.setState({ value: suggestion });
        // This will be undefined before the `input` mounts and null once the `input` unmounts.
        // That shouldn't be a problem though because users have no way of clicking `option`s that are not mounted yet or no more.
        this.inputNode.focus(); // Move focus back to the `input` after it has lost it when an `option` was clicked!
        this.inputNode.select(); // In fact select the `input` so the user can retype the value if they change their mind.
    }

    render() {
        return <div>
            <input onChange={this.onValueChange} value={this.state.value} ref={this.onValueRef} />
            <select onSelect={this.onSuggestionSelect}>
                {this.state.suggestions.map(s => <option selected={this.state.value === s} value={s}>{s}</option>)}
            </select>
        </div>
    }
}
Changes (5)
2018-4-19 15:56:49 Tomáš Hübelbauer
Bookmark React in Patterns
2018-2-18 08:59:19 Tomáš Hübelbauer
Rename to React dropping the cringy JS suffix
2018-2-17 20:00:01 Tomáš Hübelbauer
Link to the React+Redux+TypeScript connect decorator problem showcase
2018-2-13 14:28:32 Tomáš Hübelbauer
Add the VS 2017 template link
2018-2-13 14:14:26 Tomáš Hübelbauer
Migrate the note I wrote for colleagues
Comments E-mail me!