One of the defining features of React is that it has the ability to avoid re-rendering the entire DOM whenever an individual component has been changed. To accomplish this, React needs to be able to reliably and consistently identify each individual component so that when a component changes, React is then able to isolate and re-render only that specific component. It also needs to be able to identify exactly which components are firing handlers or onChange methods, and see them as unique from the others around them, even if they were all generated dynamically from some ever-changing array in the back end. The ‘id’ and ‘class’ attributes won’t get the job done here. Let’s talk about ‘key’ and ‘ref’.
Many of us just know the key attribute as “that thing you’re supposed to give to components when you generate those components from an array of objects.” But what is that attribute actually, and why is it important to set it when we generate components from iteration?
So as we know, React always needs to be able to uniquely identify every component on the page. And, as it turns out, it uses the ‘key’ attribute to do exactly that. No key attribute, no identification of individual components. No identification of individual components, no Virtual DOM. No Virtual DOM, no React.
“But David” you say. “I write components without the key attribute all the time. Surely React still works without every single component in the app having a key attribute.”
Nope. Thing is, whether you define a value for the key attribute or not, React gives a key attribute to every single component in the app. And the way it does it is by index – i.e., it’s place in position among its siblings that are nested at the same level in the HTML. Now, though that works enough to get the app running, it’s far from ideal. Let’s say you generate a list of components from an array. You work hard to carefully configure and style everything so that it’s just perfect. Then someone unshifts an object onto the beginning of your array on the backend, and the index of every generated component goes up by one. That’s why, when you generate a bunch of components without key values, React throws a warning. It’s not because the components have no key attributes – it’s because they have those attributes, and they’re set equal to their indexes, which is fragile and code smelly.
Some people don’t know this and get rid of the warning by iterating through their collection of objects and generating components where they manually set the key equal to ‘index.’ As we now know, that does nothing but repeat what React already does by default. It’ll get rid of the warning, but the problem React is telling us about is still there, so setting keys equal to indexes like this is a recognized anti-pattern. It’s recommended that you use an id or some other unique property of your objects to reliably distinguish your components from each other.
Refs are a way to store a reference to a React element or component returned by the render( ) function, and make them accessible elsewhere in the component.
First. a warning – if you run into any tutorials that set the ref attribute to a string value and access the DOM node later from
this.refs, you’re running into an old version of refs, which has been deprecated in favor of what we’ll be discussing today.
Second, another warning – the recommended use cases for refs are narrow. If you find that you’re using refs to handle all of your events and make a lot of things happen in your code, there’s a problem and you’re no longer doing declarative programming. Overuse of
ref kind of flies in the face of Reactive programming, but it’s a good option to have on the table, and is often referred to as an ‘escape hatch.’ The only uses of
ref that are recommended by the official React docs are 1) accessing the DOM API, 2) integrating 3rd-party libraries that are designed to hook into the DOM, and 3) imperatively triggering animations.
Alright, enough moping about what refs can’t do. We’re not defined by our limitations and neither are refs!
Tony Robbins is refs.
Seeing how refs are great for accessing DOM nodes, here’s a good example of a use case for refs: Say a user makes a mistake filling out a form, and we need her to re-enter some of the fields. We don’t want her to have to hunt all around the page looking for said field, so we decide that after she hits submit we want to immediately focus on the field where the problem is, saving the user some stress.
To accomplish this, we’ll need to access an
input element using
ref. Now again, once we do that, we could easily start abusing that reference by making use of it all over our code. Instead we’ll just call the focus( ) method on it. Let’s get started with an
input tag and give it a
As we can see,
ref gets set equal to a callback function. The callback takes, as it’s input the tag (i.e. the DOM node) itself. It then creates a property on the component class called myInput and sets it equal to the node with the
this.myInput can now be used anywhere in the component to access that input element, and
this.myInput.value could be used to get it’s value. Again, we do not want to use this reference to power the basic functionality of our app – that’s better left to state. But for our little use case, calling
this.myInput.focus() is an awesome idea, and a perfect use of
ref. Alright refs!
So hey, we’ll get back into our CSS discussion next week, but I think I might start writing more about React in the future – keep an eye out for more posts like this down the line!