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