Refs - Create Refs
- Use
React.createRef()
- Attach the Ref to a React Element using the
ref
attribute
- Assign the Ref to an instance property in the Constructor
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.myRef = React.createRef();
}
render() {
return <div ref={this.myRef} />;
}
}
Refs - Adding to DOM Elements
- The setting and unsetting of
current
happen automatically
-
componentDidMount
and componentDidUpdate
are triggers
- Adding
focus
to an element is imperative
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>
);
}
}
Refs - Functional Components
- Remember that Refs require class instance targets
- Stateless Functional components don't have instances
- Stateless Functional components can use refs however
function MyFunctionalComponent() {
return <input />;
}
class Parent extends React.Component {
constructor(props) {
super(props);
this.textInput = React.createRef();
}
render() {
// This will *not* work!
return (
<MyFunctionalComponent ref={this.textInput} />
);
}
}
Refs - Functional Component Usage
function CustomTextInput(props) {
// textInput must be declared here so the ref can refer to it
let textInput = React.createRef();
function handleClick() {
textInput.current.focus();
}
return (
<div>
<input
type="text"
ref={textInput} />
<input
type="button"
value="Focus the text input"
onClick={handleClick}
/>
</div>
);
}
Refs - Forwarding Refs
- Parents can pass Refs to their children
- Child refs act like they belong to the parent
- Breaks component encapsulation
- Useful in re-usable components (General vs Specific)
// Basic React function component
function FancyButton(props) {
return (
<button className="FancyButton">
{props.children}
</button>
);
}
// React component that can receive a Ref
const FancyButton = React.forwardRef((props, ref) => (
<button ref={ref} className="FancyButton">
{props.children}
</button>
));
// You can now get a ref directly to the DOM button:
const ref = React.createRef();
<FancyButton ref={ref}>Click me!</FancyButton>;
Refs - Create with Callbacks
- Alternative to using
React.createRef()
- Allows for arbitrary JavaScript logic for Ref binding
- React calls the callback on
componentDidMount
and componentDidUpdate
- Ref is set to Null on
ComponentWillUnmount
class CustomTextInput extends React.Component {
constructor(props) {
super(props);
this.textInput = null;
this.setTextInputRef = element => {
this.textInput = element;
};
this.focusTextInput = () => {
// Focus the text input using the raw DOM API
if (this.textInput) this.textInput.focus();
};
}
componentDidMount() {
// autofocus the input on mount
this.focusTextInput();
}
render() {
// Use the `ref` callback to store a reference to the text input DOM
// element in an instance field (for example, this.textInput).
return (
<div>
<input
type="text"
ref={this.setTextInputRef}
/>
<input
type="button"
value="Focus the text input"
onClick={this.focusTextInput}
/>
</div>
);
}
}
Refs - Passing Refs from Callbacks
- Parents can pass a ref to children inline
- Note that inline callbacks are called twice
function CustomTextInput(props) {
return (
<div>
<input ref={props.inputRef} />
</div>
);
}
// Parent instance this.inputElement will be
// equal to the CustomTextInput <input> element
class Parent extends React.Component {
render() {
return (
<CustomTextInput
inputRef={el => this.inputElement = el}
/>
);
}
}