React.useRef() plays two roles Creates mutable variable, that persists over component renders, but does not trigger a render if it is changed, like state Keeps reference to a DOM element if it is passed to ref attribute of html element Mutable variable It is kind of global variable. In our example we count number of clicks and stores it into clickRef.current variable The click counter will not trigger a render, but will survive through renders, even if it is defined inside the component. Clicks variable is rendered not with every click, but only when the component renders when we change the state. Html reference We pass div element into domRef variable via ref={domRef} and can access the element later with domRef.current In our example we change color of html element with button click.
const style = { border: '2px solid grey', padding: '10px', margin: '10px', maxWidth: '500px' }
function Component() {
const [clicksState, setClicksState] = React.useState(0)
const addCounter = () => setClicksState(clicksState + 1)
const clickRef = React.useRef(0)
const countClicks = () => clickRef.current++
const domRef = React.useRef(null)
const changeBorderColor = () => {
domRef.current.style.borderColor = domRef.current.style.borderColor === 'red' ? 'grey' : 'red'
}
return (
<div style={style} onClick={countClicks} ref={domRef} >
<div>Clicks inside the box: <b>{clickRef.current}</b></div>
<div>Counter: <b>{clicksState}</b></div>
<button onClick={addCounter}>Add +1 to re-render component</button><br />
<button onClick={changeBorderColor}>Change border color</button>
{console.log('render happened')}
</div>
)
}
Pass ref in props useRef() can be passed in props, like any other variable ref attribute can not be used, because this name is reserved by React We use myRef attribute
function PassRefInProps() {
const myRef = useRef()
return (
<>
<Input myRef={myRef} />
<button onClick={() => myRef.current.focus()}>Focus</button>
</>
)
}
function Input(props) {
return <input ref={props.myRef} placeholder='Custom input'/>
}
React.forwardRef() We still can use ref attribute to pass a ref But need to wrap our component into React.forwardRef() high order component
function PassRefViaReactForwardRef() {
const ref = useRef()
return (
<>
<MyInputWrappedInForwardRef ref={ref} placeholder='I am a placeholder'/>
<button onClick={() => ref.current.focus()}>Focus</button>
</>
)
}
function MyInput(props, ref) {
return <input ref={ref} {...props}/>
}
const MyInputWrappedInForwardRef = React.forwardRef(MyInput)