useRef
How to persist values between renders?
Use useref
/*
If we tried to count how many times our application renders using the useState Hook, we would be caught in an infinite loop since this Hook itself causes a re-render.
To avoid this, we can use the useRef Hook.
*/
import { useState, useEffect, useRef } from "react";
import ReactDOM from "react-dom";
function App() {
const [inputValue, setInputValue] = useState("");
const count = useRef(0);
useEffect(() => {
count.current = count.current + 1;
});
return (
<>
<input
type="text"
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
/>
<h1>Render Count: {count.current}</h1>
</>
);
}
ReactDOM.render(<App />, document.getElementById('root'));
How to store an array of elements using useRef?
Problem: I could not simply assign my ref to the element because the ref was being assigned within a map during the render. This would mean that the very last item in the array would be the element assigned to item.current
Solution:
const itemEls = useRef({})
{items.map((item, index)) => (
<p key={item} ref={(element) => itemEls.current[index] = element}>{item}</p>
))
const itemsEls = useRef(new Array())
return (
{items.map((item) => {
const getRef = (element) => (itemsEls.current.push(element))
return <p key={getRef}>{item}</p>
})}
)
How to access DOM elements?
Use useref
function TextInputWithFocusButton() {
const inputEl = useRef(null);
const onButtonClick = () => {
// `current` points to the mounted text input element
inputEl.current.focus();
};
return (
<>
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>Focus the input</button>
</>
);
}
How to keep track of previous state values?
Use react_useref
import { useState, useEffect, useRef } from "react";
import ReactDOM from "react-dom";
function App() {
const [inputValue, setInputValue] = useState("");
const previousInputValue = useRef("");
useEffect(() => {
previousInputValue.current = inputValue;
}, [inputValue]);
return (
<>
<input
type="text"
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
/>
<h2>Current Value: {inputValue}</h2>
<h2>Previous Value: {previousInputValue.current}</h2>
</>
);
}
ReactDOM.render(<App />, document.getElementById('root'));
forwardRef
How to pass ref into our custom components?
- Create custom component with forwardRef
function Button(props, ref) {
return (
<button ref={ref}>
{props.children}
</button>
);
}
export default forwardRef(Button);
- Pass ref from parent component to child component
const ref = React.createRef();
<Button ref={ref}>Click me!</Button>;
useImperativeHandle
How to expose limited properties on a ref?
- App.tsx
function App() {
const buttonRef = useRef(null);
const handleClick = () => {
console.log(Object.keys(buttonRef.current)); // ['someExposedProperty']
console.log("click in index.tsx");
buttonRef.current.someExposedProperty();
};
return (
<div>
<Button onClick={handleClick} ref={buttonRef} />
</div>
);
}
- Button.tsx
import React, { useRef, useImperativeHandle, forwardRef } from "react";
function Button(props, ref) {
const buttonRef = useRef(); // To use useImperativeHandle you need to work with another ref instance
useImperativeHandle(ref, () => ({
someExposedProperty: () => {
console.log(`we're inside the exposed property function!`);
// Do something with "buttonRef.current", for example "buttonRef.current.blur()"
}
}));
return (
<button ref={buttonRef} {...props}>
Button
</button>
);
}
export default forwardRef(Button);
Leave a Reply