Interacting With The DOM
One of the best things about using a framework like React is that we don't have to fuss with the DOM directly. We tell React what the DOM should look like, and React takes care of creating/modifying/moving/deleting the DOM nodes for us.
That said, I believe it's still worth knowing a little bit about how these operations work. React is using them under-the-hood for us, after all!
In this lesson, we'll dig into some of the most common DOM operations.
Selecting nodes
Let's say we want to grab a reference to an element that already exists on the page.
We can do this with the querySelector
method:
// Grab the <body> tag:const body = document.querySelector('body');
querySelector
uses CSS selectors like .some-class
and #some-id
. If you've written it in CSS, it will work with querySelector
:
const enabledButton = document.querySelector('button:not(:disabled)');
const thirdNavLink = document.querySelector('.nav-link:nth-of-type(3)');
It's common to call this method on document
, since it's the top-level DOM node on the page, but we can actually call it on any DOM node! This allows us to search in a more-precise way:
// Grab the headerconst header = document.querySelector('#header');
// Find the first `<a>` tag inside the headerconst firstLink = header.querySelector('a');// ^^^^^^ header, not document!
Sometimes, multiple elements on the page will match the provided query. querySelector
will grab the very first one it finds. There's another method, querySelectorAll, which will collect an array-like object of all the matched elements.
If querySelector
can't find a matching element, it'll return null
.
Once we've captured a reference to a DOM node, we can do a bunch of stuff with it. Let's examine some of the operations at our disposal.
Editing nodes
Let's imagine that we have a list of users in our HTML. If the user is currently online, a little green dot is shown. The markup looks like this:
<ul> <li id="user-andrew" class="offline"> Andrew <li> <li id="user-beatrice" class="offline"> Beatrice <li> <li id="user-chen" class="online"> Chen <li></ul>
Suppose we want to toggle the first user, Andrew, from offline to online, by changing the class
attribute. We can do this with the setAttribute
method:
Code Playground
What if we want to change the text within an element? For example, maybe we want to change Andrew's username to Andrew (online)
.
We can do that with the innerText
property:
const node = document.querySelector('#user-andrew');
node.innerText = 'Andrew (online)';
innerText
is a writeable property, not a method. Instead of calling it as a function, we re-assign its value to the text content we want to include.
Creating and appending nodes
Finally, let's talk about creating brand-new DOM nodes from scratch!
We can do that using the document.createElement
:
const element = document.createElement('div');
createElement
takes 1 parameter, which serves as the tag to be created. We can pass any valid HTML tag (eg. 'a'
, 'ul'
, 'footer'
).
A newly-created element has no attributes and no content. We can enhance it using the methods and tools we've seen so far. For example:
Code Playground
Something curious is happening here, though… We've created an element, but we don't see it anywhere on the page!
The reason for this is that while we've created a DOM node, we haven't attached it anywhere. It's in limbo right now, floating in space.
We can fix this with the appendChild
method:
const body = document.querySelector('body');body.appendChild(element);
Try copying this code to the playground above, underneath the code that's already there. The red "Hello world!" text should show up!
Most of the methods we've seen, like querySelector
and appendChild
, can be called on any DOM node. createElement
is different: it can only be called on the document
object.
In order for a DOM node to be visible to the user, it needs to be within the <body>
tag. The user won't see any HTML tags in other parts of the page. And so when we create an element, it's associated with the document, but it won't be visible until we append it somewhere within the <body>
.
Destroying nodes
We can destroy a node using the remove
method:
const elem = document.querySelector('#some-element');elem.remove(); /* No more element! 💨 */
Letting React do it for us
It's good to know that these sorts of methods exist, to give us a sense of what React is doing under-the-hood. Ultimately, though, we generally don't need to do a ton of DOM manipulation with React.
And that's a very good thing. I've worked on large projects that involved a lot of hands-on DOM manipulation, and inevitably, we'd wind up with sticky spaghetti code. It becomes really hard to keep track of which code is doing which manipulations.