React useRef
useRef
returns a mutable ref object whose.current
property is initialized to the passed argument (initialValue
). The returned object will persist for the full lifetime of the component.
source
The ref object is extremely powerful as it stores a mutable object that changes and does not trigger a component render. This can help our component performance!
Before hooks we had createRef
which has the same functionality as useRef
but for class components.
import React, { Component, createRef } from "react";
class EmailInput extends Component {
emailInput = createRef();
focusEmailInput = () => this.emailInput.current.focus();
render() {
return (
<>
<input type="email" ref={this.emailInput} />
<button onClick={this.focusEmailInput}>Focus on the email input!</button>
</>
);
}
}
import React, { useRef } from "react";
const EmailInput = () => {
const emailInput = useRef();
const focusEmailInput = () => emailInput.current.focus();
return (
<>
<input type="email" ref={emailInput} />
<button onClick={focusEmailInput}>Focus on the email input</button>
</>
);
}
Let's have a look at a real-world situation.
Imagine you need to design a custom upload button and the default input type file doesn't meet all your requirements but it does have the file system dialog and extension configuration.
<input type="file"
id="avatar" name="avatar"
accept="image/png, image/jpeg">
We want to use a material-ui icon button for uploading a file and we are going to use useRef
to do that.
import { useRef, ChangeEventHandler } from 'react'
import { IconButton } from '@mui/material'
import InsertPhotoOutlinedIcon from '@mui/icons-material/InsertPhotoOutlined'
export default function MyCustomUploadButton() {
const fileInputRef = useRef<HTMLInputElement>(null)
const onFileChange: ChangeEventHandler<HTMLInputElement> = (e) => {
const reader = new FileReader();
reader.onload = function (event) {
//@ts-ignore
var imgObj = new Image();
//@ts-ignore
imgObj.src = event.target.result;
imgObj.onload = function () {
dispatch(addImg(imgObj))
}
}
//@ts-ignore
reader.readAsDataURL(e.target.files[0]);
}
const openFileDialog = () => {
fileInputRef.current?.click()
}
return (
<IconButton color={'primary'} >
<InsertPhotoOutlinedIcon onClick={openFileDialog} width={'100%'} />
<input onChange={onFileChange} style={{ display: 'none' }} ref={fileInputRef} type={'file'} />
</IconButton>
)
}
As you can see in our MyCustomUploadButton
component, we defined material icon button that triggers input file click on click. the rest of the functionality is handled by the input file onChange
. The input itself is never displayed on the screen.
This example above is 1 of many use cases where useRef
can come in handy!.
Hope this article helped you and best of luck!