using react's ref today can be a little confusing. back to the days of class components, it was very clear in the docs.
we should use refs mostly for DOM elements :
https://reactjs.org/docs/refs-and-the-dom.html
But today we have hooks together with functional components.
and we are using useRef hook.
also, this brings to us new patterns. using ref to contain callbacks, or any data we want to preserve (kind of state) but without the need to rerender. its a powerful API and also shows up in the docs:
https://reactjs.org/docs/hooks-faq.html#is-there-something-like-instance-variables
so now ref can be used for:
store mutable data
kind of memoization
but these docs contradict each other. and causing many mistakes, and conflicts in development teams.
the doc says 2 different things and its a problem.
so, what is the "right" thing to do in a scenario like that?
const MyComponent = (props) => {
const [myMap1, _] = useState(new Map()); // 1.
const myMap2 = useMemo(()=> new Map(), []); // 2.
const myMap3 = useRef(new Map()); // 3.
...
};
useMemo is a declarative performance optimization technique.
Declarative, as it relies on state or props dependencies from the surrounding scope belonging to a particular render and automatically (re)creates the memoized value. We don't have to tell useMemo to do that.
useRef is a mutable storage box for any values, e.g. value updates independent from current render scope.
useRef does not have any dependencies, so no value is automatically changed. You have to do that manually by writing ref.current = ... (DOM nodes are an exception).
That is why you could see useRef as an escape hatch into the imperative world.
// instead of
const val = useMemo(() => 42, [myDep]); // 42 stands for some complex calculation
// do this
const ref = useRef();
ref.current = 42 // assign 42 imperatively to ref somewhere in render
Or even replace useRef by useState:
const [ref] = useState({current:null});
ref.current = "hello";
Disadvantage: we are back in old jQuery age :-). Operations have to be set imperatively, meaning more manual work and possible mistakes. Immutable value manipulations are also much more predictable than mutations (incl. other benefits). That is, why nearly everything in React is immutable.
Instead, it makes sense to stay declarative when possible (React idiomatic) and use the intended, optimized tools for their specific case:
useState for immutable values in a declarative manner, triggers re-renderuseMemo for declarative memoization of costly values derived from state and propsuseRef for mutable values or DOM nodes - independent of render closure scope, no need for deps, doesn't trigger re-render, more manual imperative workIf you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With