useRef: Use Cases & Best Practices

devfish·2023년 2월 22일
0

React

목록 보기
4/10
post-thumbnail

Why use useRef?

Adapted from w3schools & Pavlutin's guide to useRef & Demystifying react hooks

  • useRef only returns one item: an Object called current.

    • Initializing useRef: const testRef = useRef(1) means testRef = { current: 1 }
      useRef stores an object that contains an attribute called current, which stores the passed value (1 in this example)
  • useRef will assign a reference for each component, while a variable defined outside a function component scope will only assigned once.

Useful traits:

  • Persistent values between renders

    • useRef does not trigger a re-render when its reference is updated, unlike useState. Counting how many times our app renders with the useState Hook would would be impossible since the hook itself would cause a re-render each time the count state is updated, and get stuck in an infinite loop. This is why we need to use useRef for storing mutable values instead.

    • Useful for keeping track of previous state values and state changes (that does not need to be updated on the screen)

    • Use cases: logging button clicks, stopwatch, media playback (play/pause)

    • Key difference between using outer scope variables and useRef for keeping track of mutable values: an outer scope variable would be global for all components, whereas useRef would only reference/track the state of that one component instance (click here to see the difference)

  • DOM manipulation

    • While we generally want to let React handle DOM manipulation, there are some instances in which useRef can be aptly used to directly access the DOM without causing problems. useRef can be used to reference the DOM node, element, and address.
    • Use cases: focus & blur (putting/removing focus on an input element), text selection, applying animation, utilizing DOM-based libraries such as d3.js, greensock

useRef vs. useState

TLDR: Use useRef when you need information that is available regardless of component lifecycle and whose changes should NOT trigger rerenders. Use useState for information whose changes should trigger rerenders.

There are two key differences between reference and state:

  • Updating a reference doesn't trigger re-rendering, while updating the state does.
  • The reference update is synchronous (the updated reference value is available right away), while the state update is asynchronous (the state variable is updated after re-rendering).

From a higher point of view, references store infrastructure data of side-effects, while the state stores information that is directly rendered on the screen.

4 Possible Scenarios of Storing Variables (from StackOverflow)

https://stackoverflow.com/questions/57444154/why-need-useref-and-not-mutable-variable

Use Cases (Templates)

Accessing DOM Elements

const address_container = useRef(reference_data_type)
return (
    <div>
      <input ref={address_container} type="text" />
    </div>);

When we assign address_ container to the input ref property, it creates a pointer reference to the input DOM element. This reference can also be used in other components. For instance, a reference can be passed down from parent to child via forwardRef (R1, R2).)

Text Focus Example

function TextInputWithFocusButton() {
  const inputEl = useRef(null);
  const onButtonClick = () => {
    inputEl.current.focus();
  };
  return (
    <>
      <input ref={inputEl} type="text" />
      <button onClick={onButtonClick}>Focus the input</button>
    </>);
}

Focus & Blur Example

const { useRef } = React;

const MyComponent = () => {
  const nameRef = useRef();
  
  const focus = () => {
    nameRef.current.focus();
  }
  
  const blur = () => {
    nameRef.current.blur();
  }
  
  return (
    <section className="box">
      <label for="name">Enter a name:</label>
      <input ref={nameRef} type="text" name="name" id="name"/>
      <button onClick={focus}>Focus!</button>
      <button onClick={blur}>Remove Focus</button>
    </section>
  );
}

ReactDOM.render(<MyComponent />, document.getElementById('root'))

Use with Uncontrolled Elements

https://medium.com/technofunnel/react-uncontrolled-elements-with-useref-hooks-9c5873476c6f

Controlled vs. Uncontrolled Components

Definition of a controlled component -

...in the controlled component the form input element’s values and mutations are totally driven by event handlers and the value of the input element is always inferred from the state

whereas an uncontrolled component -

doesn't use any states on input elements or any event handler ... doesn't care about an input element’s real-time value changes.

In short, the state of controlled components are controlled by React, vs. the state of uncontrolled components which are controlled by the DOM. Connecting a managed state with input value makes that input value a controlled component. Refs are used in uncontrolled components to access the input values. Uncontrolled components may be easier to use for smaller applications, but controlled components offer more effective control and consistency which is advantageous for bigger applications. React recommends using controlled components for implementing forms.

When a controlled input value is undefined, it essentially becomes uncontrolled, which triggers this error:

useRef: A Necessary Evil

...refs are a necessary evil that helps us take the liberty of solving problems for which React itself can’t provide solutions due to its data-driven design philosophy ~Sameer Kumar

React uses a declarative/functional approach to programming. Apparently React hooks are an "aberration" to this approach, but necessary since components need a way to manage states and change events, which aren't possible just with pure functions. Using them still helps separate the relatively pure and impure parts of your code. But we need to be mindful of the correct scenarios to be using useRef so it does not descend into chaos.

It is important to refrain from directly manipulating the DOM while using React, since React uses a virtual DOM system (a lightweight copy of the actual DOM.) React syncs state changes in the virtual DOM with the actual DOM, but not the other way around. React will behave unpredictably if direct DOM changes are made without properly notifying React (is there a way to notify React though? TBD.)

Virtual DOM vs actual DOM

https://www.geeksforgeeks.org/difference-between-virtual-dom-and-real-dom/

Imperative vs Declarative Programming

The following screenshots are excerpts from this link.

var numbers = [1, 2, 3, 4, 5, 6];
var sum;

// Imperative
sum = 0;
for (let i = 0; i < numbers.length; i++) {
  if (i % 2 === 0) {
    sum += numbers[i] * 2;
  }
  
}

console.log(sum); // 18

// Declarative
sum = numbers
  .filter(i => i % 2)
  .map(i => i * 2)
  .reduce((acc, next) => acc + next);

console.log(sum); // 18 

// Even more declarative
const isPair = i => i % 2;
const double = i => i * 2;
const sum = (a, b) => a + b;
sum = numbers.filter(isPair).map(double).reduce(sum);// 18

Functional Programming

Functional programming is a form of declarative programming that builds software by composing pure functions, avoiding side-effects and using immutable data.(1) It is declarative as "a computation's logic is expressed without describing its control flow". (2) This stackoverflow post describes SQL as "a great example of the functional way of programming, which is a restricted subset of declarative programming in which the desired computation is specified by composing functions."

References

useRef

React useRef Hook
The Complete Guide to useRef() and Refs in React

6 Practical Applications for useRef
React useRef Hook Focus Example
Why need useRef and not mutable variable?
React Uncontrolled Elements With “useRef” Hooks

New React Documentation: Do Not Abuse Ref
React v18: useRef — What, When and Why? : Taming React’s necessary evil — useRef
Demystifying React Hooks: useRef

Controlled vs. Uncontrolled Elements

*What are controlled and uncontrolled components in React JS? Which one to use?
Controlled vs uncontrolled React components - why not both?

Programming Paradigms

Imperative and Declarative Programming: In-depth comparison with examples
React is Declarative - What Does it Mean?
선언형 VS 명령형, 리액트가 선언형인 이유
Practical Functional Programming with Javascript: Great overview of core principles
Functional Programming with React/Redux

profile
la, di, lah

0개의 댓글