Exploring the Browser Environment through Routing
Published: 2021-08-04 17:59:16

For better or worse, the npm library has changed the day-to-day life of devs the world over. While NPM can be host to poorly maintained, un-documented, and even malicious packages - there are just as many helpful, well-intentioned libraries and frameworks designed to get the job done better and faster. 

Some libraries are so well supported, and so good at doing their job, they become a standard. React Router, with over 4 million weekly downloads at the time of this writing, is a great example of just such a library. 

Unfortunately, even well-supported libraries experience deprecations and breaking changes. The only difference is that when a library like React Router breaks, many pages across the world-wide-web break with it. 

By peering under the hood to see how React Router works, we can mend future breaks faster and gain a deeper understanding of how it interacts with the browser environment - a rich resource available to us at all times. 

----

### Prerequisites: The Browser Environment, the DOM, and the BOM 

React is written in JavaScript, a language initially constructed to exist inside the browser environment, and in many ways the browser was built around JS, as well. 

Though terms like *environment* can sometimes sound elusive, we only need to understand that an environment is nothing more than a collection of bindings and their values. These values are often objects or functions that store information and help us do a job. Their bindings are their names - the ways in which we must call them so that we can use the value they contain.

To get a better understanding of the structure of the browser environment, let's take a very broad look from the top level. 

![screenshot](https://i.ibb.co/XLKPHNM/5.png)

The top-level, or root, object of the browser environment is known as the `window` object. This massive object houses all the properties and methods of the browser environment. With the data, logic, and behavior that lives here, JS is able to execute on the screen. Beyond that, the JS can *borrow* from this object to accomplish tasks.

This is exemplified by the first child seen in the diagram above, called the `document` object or DOM. The DOM provides us with a virtual, tree-like representation of the elements on the page, along with ways to isolate and manipulate them. You might be familiar with some of these functions, like `document.body.getElementByID()` or `document.body.getElementByClassName()`.

The DOM is a subject covered early, and often so exhaustively when first learning to work with JS that it is often taken for granted. The `document` property of the `window` object did not always exist as it does now, in a standardized form. In the early days of the Web, every browser followed a different set of ideas and implementations, and cross-browser support simply wasn't a thing. 

In those days the DOM was more similar to our next subject - the *browser object model*, or BOM. To make things more confusing, the BOM is also commonly known as *Web APIs*, or the hybridized *BOM APIs*. 

Whatever you call it, the BOM serves as the core of JS in the browser. It's host to a collection of objects and interfaces that are always there, waiting to be used. We could get information about the user's display with `screen`, their browser OS with `navigator`, and, what we'll be most concerned with today, their destination with the `location` object.

As evidenced by its many names, the BOM is not well defined or standardized - meaning every browser provides a different set of BOM objects. Which explains why we won't find this functionality on a handy parent object, like `document`, but rather stuck directly onto the root `window` object. 

Thankfully, though while not officially standardized, most browsers today are more alike than different. We work around differences in varying BOM implementations with supplemental pieces of code, like WebKit, language wrappers like jQuery, and utilizing cross-browser supports built into each.

----

### Project Introduction

> The example repo for this post can be found [here](https://github.com/ash-bergs/react-routing)

This project explores routing by keeping things simple. There are 4 main, pre-built components - App, About, Home, and Contact. App will serve as the parent component, initially rendering all 3 children simultaneously. 

![project hierarchy](https://i.ibb.co/3pv1ddp/NODE-BLOG-graphic-6.png)

We're going to handle building our own routing from the ground up, discussing *Reactive* patterns and exploring the browser environment along the way. We'll build 2 more components, Link and Route, to do that. We'll also construct a Nav component and briefly discuss navigation.

----

### Brute Force Routing 

> If you're following along on the repo, the starter code for this section can be found on branch `section-one/setup`. The final code can be found on branch`section-two/brute-force-routing`.

The basic premise of routing is simple: When the user is at a certain location, show a certain component or page. To do that we need to know the user's url at any given moment. Lucky for us, that information is always available to us in the browser environment on the `window.location` object.

To take a look at the `location` object in the App component, we'll log it at the top of the App component:

```jsx
src/App.js

import About from './components/About';
import Contact from './components/Contact';
import Home from './components/Home';

function App() {
  // ⭐
  console.log(window.location);

  return (
    <div className="App">
      <h1 className="headline">Routing in React</h1>
      <Home />
      <About />
      <Contact />
    </div>
  );
}

export default App;
```

The console should return an object with a lot of properties and a few methods.

![console screenshot](https://i.ibb.co/rbHrR6W/window-Location.jpg)

This is the entire `location` object. Most of the properties found here hold information directly concerned with the current url, a standardized string that specifies a virtual resource's location and content. The `location` object includes a separate key-value pair for each of its constituent parts.

![anatomy of a url graphic](https://i.ibb.co/Jc910ky/URLanatomy.png)

To accomplish routing for pages within the same app we're only really concerned with the `pathname` property. By watching the `pathname` we can decide when we should or should not render a component.

We'll start by removing the component instances from the return, and defining a function named `showHome` at the top of the App component:

```jsx
src/App.js

import About from './components/About';
import Contact from './components/Contact';
import Home from './components/Home';

function App() {
	// ⭐
  const showHome = () => {
    if (window.location.pathname === '/') {
      return <Home />;
    }
  };

  return (
    <div className="App">
      <h1 className="headline">Routing in React</h1>
			{showHome()}
    </div>
  );
}

export default App;
```

The `showHome` function's job is simple: If the `window.location.pathname` contains the the string "/" (that is, when it is empty) return the Home component.

To use the function, we've simply called it in the JSX. Opening the project you should see the Home component rendering. If we update the url to something like [`http://localhost:3000/about`](http://localhost:3000/about), the Home component will be removed.

We'll create and call 2 more functions, `showAbout` and `showContact`, for the remaining components:

```jsx
src/App.js

import About from './components/About';
import Contact from './components/Contact';
import Home from './components/Home';

function App() {
  // routing functions
  const showAbout = () => {
    if (window.location.pathname === '/about') {
      return <About />;
    }
  };

  const showContact = () => {
    if (window.location.pathname === '/contact') {
      return <Contact />;
    }
  };

  const showHome = () => {
    if (window.location.pathname === '/') {
      return <Home />;
    }
  };

  return (
    <div className="App">
      <h1 className="headline">Routing in React</h1>
      {showAbout()}
      {showContact()}
      {showHome()}
    </div>
  );
}

export default App;
```

A quick save and a visit to the browser, and we can see that when the url is updated, and we spell everything correctly, the About and Contact components render at their corresponding `pathname`. 

Just like that - we've created brute force routing, and all we had to do was look to the surrounding environment and read the information found there. However, there are some holes in this approach. 

For starters, the url has to be manually updated when the user wants to see a different component. Furthermore, each of the `show` functions is very similar. We could easily refactor, combining all of the `show` functions into one function capable of receiving multiple arguments... but this entire approach is decidedly un-Reactive. 

Instead, we'll build a reusable component with the logic to decide when it should and shouldn't show its children. We'll call it the same thing it's known as in React Router: The Route component.

----

### The Route Component

> If you're following along on the repo, the code for this section can be found on branch `section-three/Route-component`.

To begin building the Route component, create another directory inside the `src` folder named `routing`. Inside of `routing` create a file named `Route.js` with the following code:

```jsx
src/routing/Route.js

const Route = ({ children, path }) => {
  return window.location.pathname === path ? children : null;
};

export default Route;
```

The Route component is a simple function component. So simple that because it's not returning any JSX, there's no need to explicitly have React in scope. Meaning we don't need to `import React from 'react'`. 

The component requires 2 props - `children` and `path`. The `path` is checked against the `window.location.pathname` value, while `children` represents a React-specific compositional principle.

When creating components we intend to use as "generic boxes", like the Route component, they likely will not know their children ahead of time. Will it be a component? A dataset? A link? An image? 

Passing the `children` prop and consuming it in the return allows us to work around that unknown. Using it ensures the component can effortlessly consume any child we provide - be that another component, a string, or any other piece of data. To see how the `children` prop is used, import and use the Route component in `App.js`.

After importing, remove the `show` functions and their instances from the JSX, and add an opening and closing `<Route>` tag in their place. The Route component requires a `path` attribute and value, which we'll set to `"/"`. Finally, provide a basic string between tags:

```jsx
src/App.js

import About from './components/About';
import Contact from './components/Contact';
import Home from './components/Home';

import Route from './routing/Route';

function App() {
  return (
    <div className="App">
      <h1 className="headline">Routing in React</h1>
         <Route path="/">
	     "I'm being passed on the `children` prop!"
         </Route>
    </div>
  );
}

export default App;

```

Back in `Route.js` add a log statement at the top of the component, save, and run the project.

```jsx
src/routing/Route.js

const Route = ({ children, path }) => {
  console.log(children);
  return window.location.pathname === path ? children : null;
};

export default Route;
```

In the browser we should see the passed string both on the webpage, and in the console. 

This shows us that using the `children` prop is pretty simple and straightforward: The content passed between opening and closing JSX tags, like `<Route>` and `</Route>`, will be available to the parent component on the special `children` prop. 

The children prop can be used to pass one, or more, components, strings, elements, and more. Which we can see by adding all 3 components between `<Route>` tags:

```jsx
src/App.js 

import About from './components/About';
import Contact from './components/Contact';
import Home from './components/Home';

import Route from './routing/Route';

function App() {
  return (
    <div className="App">
      <h1 className="headline">Routing in React</h1>
      <Route path="/">
        <Home />
        <About />
        <Contact />
      </Route>
    </div>
  );
}

export default App;
```

Save and refresh the project, and the console should return an array of 3 objects, each with the type of `react.element`.

![console screenshot](https://i.ibb.co/3r4vJDC/react-Routing-Children-ALL.jpg)

Because we want each Route to conditionally render one child at a time, we'll finish by giving each component its own `path` and `<Route>`:

```jsx
src/App.js 

import About from './components/About';
import Contact from './components/Contact';
import Home from './components/Home';

import Route from './routing/Route';

function App() {
  return (
    <div className="App">
      <h1 className="headline">Routing in React</h1>
      <Route path="/">
        <Home />
      </Route>
      <Route path="/about">
        <About />
      </Route>
      <Route path="/contact">
        <Contact />
      </Route>
    </div>
  );
}

export default App;
```

On the webpage we'll have essentially the same functionality we had in the brute force routing approach, but we're no longer repeating ourselves. Additionally, this new approach takes better advantage of key principles and patterns in React.

By updating the url we can see each of the components at their respective `path`, but we're still missing an important and expected feature - navigation.

----

### The Nav Component 

> If you're following along on the repo, the code for this section can be found on branch `section-four/navigation`.

When users arrive at a webpage, especially one with subsequent inner pages and resources, they expect the app to have some type of navigation in place. That could be a dropdown menu, a navigation bar, or any one of the many patterns for organizing a collection of links. At the end of the day, navigation, be it good or bad, can be the "make it or break it" feature of an app. 

Because our app is basic, we'll use the nav bar approach to implement and discuss navigation. Inside the `components` directory make a new file named `Nav.js`. Nav will return some basic JSX: 

```jsx
src/components/Nav.js

import React from 'react';

const Nav = () => {
  return (
    <div className="nav">
      <a href="/">Home</a>
      <a href="/about">About</a>
      <a href="/contact">Contact</a>
    </div>
  );
};

export default Nav;
```

This component resembles any basic, run-of-the-mill nav bar you might come across in the wild. It works just like one too - meaning the anchor element, `<a>`, has pre-defined, default behavior coming from the browser environment. 

To explore why this presents problems in React, we'll import and use the Nav component in `App.js`:

```jsx
src/App.js 

import About from './components/About';
import Contact from './components/Contact';
import Home from './components/Home';
import Nav from './components/Nav';

import Route from './routing/Route';

function App() {
  return (
    <div className="App">
      <Nav />
      <h1 className="headline">Routing in React</h1>
      <Route path="/">
        <Home />
      </Route>
      <Route path="/about">
        <About />
      </Route>
      <Route path="/contact">
        <Contact />
      </Route>
    </div>
  );
}

export default App;
```

Though the problems surrounding a full-page reload are less obvious in small projects like ours, in more robust programs this behavior can cause a cascade of costly network requests, unexpected state changes, and other less-than-desirable consequences. 

Furthermore, when the user *first* arrives at the page their machine and browser have already taken care of loading the CSS, the JS, the html and more. There's simply no reason to do this over and over again as they navigate through the app. 

To solve for this, we'll need to stop the anchor's default behavior from ever being triggered and provide custom logic in its place. In React we can do that by wrapping the anchor element in a component, where we will have full control. We'll call this component the Link component.

----

### The Link Component 

> The code for this section can be found on branch `section-four/navigation`.

In the `routing` directory, make a new a file named `Link.js`. To start, declare a function component that returns a pair of `<a>` tags, with a `href` value of `"/"`, and text "Link" between:

```jsx
/src/routing/Link.js

import React from 'react';

const Link = () => {
	return <a href="/">Link</a>;
};

export default Link;
```

> 👆 Because the component only returns a single element we can omit the smooth parentheses with a single line return!

In `Nav.js` import the Link component and provide it in place of the anchor tags:

```jsx
src/components/Nav.js

import React from 'react';

import Link from '../routing/Link';

const Nav = () => {
  return (
    <div className="nav">
      <Link>Home</Link>
      <Link>About</Link>
      <Link>Contact</Link>
    </div>
  );
};

export default Nav;
```

After saving, the project should reveal a set of three identical Link elements on the page.

![Link screenshot](https://i.ibb.co/b1J1WXB/link-Component.jpg)

All the links navigate to the same location, that is `http://localhost:3000/`. Therefore they will all lead to the Home component view. 

To make the Link component reusable we can pass props as placeholders for values that can be changed with each instantiation. The Link component requires a few props: a `href` attribute, the `children`, and a `className`. 

Back in `Link.js` we'll start by passing `href`: 

```jsx
src/routing/Link.js

import React from 'react';

const Link = ({ href }) => {
	return <a href={href}>Link</a>;
};

export default Link;
```

The `href` address is no longer hardcoded, so the Link *must* explicitly receive a passed `href` value at the time of instantiation. Saving this update will break the app, but we can quickly fix this by providing the `href` prop to each Link back in `Nav.js`:

```jsx
src/components/Nav.js

import React from 'react';

import Link from '../routing/Link';

const Nav = () => {
  return (
    <div className="nav">
      <Link href="/">Home</Link>
      <Link href="/about">About</Link>
      <Link href="/contact">Contact</Link>
    </div>
  );
};

export default Nav;
```

In the browser we'll see that the app is back up, and the Links are working again - mostly. They all still say "Link", rather than "Home", "About", or "Contact". This doesn't help the user much. They can probably already tell that the Link is, in fact, a link simply because it's a blue, underlined piece of text. 

To pass a destination description, we'll use the React `children` prop as we did in the Route component:

```jsx
src/routing/Link.js

import React from 'react';

const Link = ({ href, children }) => {
  return <a href={href}>{children}</a>;
};

export default Link;
```

Using the `children` prop, any text we pass between Link tags will be passed and consumed by the Link component. No updates are required in `Nav.js`, saving now will show all of the Links restored with no question as to where they lead. 

![Link update screenshot](https://i.ibb.co/Sy5wQtx/link-Component02.jpg)

Finally, we'll pass an optional `className` prop. This step isn't strictly necessary, but it's a good idea to "future-proof" code with this kind of foresight. 

```jsx
src/routing/Link.js

import React from 'react';

const Link = ({ href, children, className = 'link' }) => {
  return <a href={href} className={className}>{children}</a>;
};

export default Link;
```

We used [ES6 destructuring assignment syntax](https://dev.to/ash_bergs/apb-demystified-destructuring-4gaf) to provide a default value. That way, if a Link is used without a given `className` nothing will break. By default it will receive the class name "link", or it can be provided by us in the instance that we need a special link in the future. 

Now, you may be thinking "Great, we're back to where we started." To some degree you're correct, but we've installed ourselves in a much greater seat of power. On the component-level we can now begin wrapping the Link in custom logic and behavior.

----

### Preventing Default Behavior

> The code for this section can be found on branch `section-four/navigation`.

We discussed why the browser's default behavior for anchor elements presents a problem in React. By wrapping the anchor element in a React component we started providing it dynamic data. Now we can begin re-wiring its behavior, cherry-picking functionality from the browser environment that fits our needs.

To handle user interactions anchor elements wait for an event (e.g. clicking) to occur. Once this happens, an event object containing all sorts of information about what the event was, where it occurred, and what's to happen next is emitted. In React we have access to all of this within the anchor's `onClick` property, where we can attach a *handler* function.

At the top of `Link.js`, we'll declare our own click handler, called `onClick` to keep things simple, and connect it in the JSX:

```jsx
src/routing/Link.js

import React from 'react';

const Link = ({ href, children, className = 'link' }) => {
	// ⭐
	const onClick = (e) => {
		// ...
	};

  return (
		<a 
			onClick={onClick} 
			href={href} 
			className={className}
		>
				{children}
		</a>;
	);
};

export default Link;
```

The `onClick` function takes in the event object, `e`. To stop default behavior the first thing we'll do is use the browser-provided `preventDefault()` method on the event: 

```jsx
src/routing/Link.js

import React from 'react';

const Link = ({ href, children, className = 'link' }) => {

	const onClick = (e) => {
	    // ⭐
		e.preventDefault();
	};

  return (
		<a 
			onClick={onClick} 
			href={href} 
			className={className}
		>
				{children}
		</a>;
	);
};

export default Link;
```

In the browser if we click a Link we'll see there is no full-page reload, the url is not updated, and well... nothing happens. One line of code has effectively "shut off" the anchor element's behavior, and presented the opportunity to step in a redefine it ourselves.

----

### Implementing Custom Behavior

> If you're following along on the repo, the code for this and the next section can be found on branch `section-five/custom-PopStateEvent`.

We know that our Route component relies on the url `pathname` property. So our first concern is finding a way to update this piece of information. Luckily, we don't have to look too far or hard to find it.

Nestled not-so-deeply in the BOM, alongside the `location` object, is the `history` object. As its name suggests, the `history` object contains information regarding *session history*. This includes an array of visited urls, known as the *history stack*, a `forward()`, `back()`, and `go()` function, and several other methods, including `pushState()`. 

The `pushState()` method can be used to add to the history stack, but not trigger a full-page reload. The method comes with a couple of caveats - first, `pushState()` can only be used to add a new url to the history stack *if* that url shares the same origin as the current url. 

The pages we are routing between belong to the same `document`, and originate from the same host, or origin. They're simply small pieces of a larger whole, making `pushState` a perfect option for our use case. 

In `Link.js`, we'll update the `onClick` handler right below the call to `preventDefault()`: 

```jsx
src/routing/Link.js

import React from 'react';

const Link = ({ href, children, className = 'link' }) => {

	const onClick = (e) => {
		e.preventDefault();
	        // ⭐
		window.history.pushState({}, '', href);
	};

  return (
		<a 
			onClick={onClick} 
			href={href} 
			className={className}
		>
				{children}
		</a>;
	);
};

export default Link;
```

There are three values passed to the `pushState()` method - a state object, a title, and the url destination, which we have access to through the `href` prop. 

![pushState graphic](https://i.ibb.co/fk33prT/NODE-BLOG-graphic-5.png)

In the project you'll now notice that while clicking a Link does not update the render, it does update the url, and that means we're halfway there.

Using the environment, we found a way to update the url, but avoid costly reloads and network requests - but we've run up against the other caveat of using `pushState()`. This one surrounds a special type of event that occurs in the browser known as a `popstate` event. 

----

### Creating a Custom PopStateEvent

By definition a `popstate` event is a special type of event dispatched on the `window` *whenever the active history entry changes*,  but only when that change is a consequence of a *browser action*. Browser actions include clicking the back and forward buttons, and changing the url manually. Our call to `pushState()` is not a browser action, so a `popstate` event is not emitted. 

Because the `popstate` event, which inherits from the parent `Event` object, is built perfectly for our needs we still want to use it, and we can. 

Below the call to `pushState()`, we can explicitly create our own `popstate` event using the `new` keyword and the `PopStateEvent` constructor:

```jsx
src/routing/Link.js

import React from 'react';

const Link = ({ href, children, className = 'link' }) => {
	
	const onClick = (e) => {
		e.preventDefault();
		window.history.pushState({}, '', href);
		// ⭐
		const navEvent = new PopStateEvent('popstate');
	};

  return (
		<a 
			onClick={onClick} 
			href={href} 
			className={className}
		>
				{children}
		</a>;
	);
};

export default Link;
```

We've constructed a synthetic event, named `navEvent` with a type of `popstate`. Once created, the `navEvent` must be manually "turned on", or emitted.  This is done using the browser-provided `dispatchEvent()` method:

```jsx
src/routing/Link.js

import React from 'react';

const Link = ({ href, children, className = 'link' }) => {
	
	const onClick = (e) => {
		e.preventDefault();
		window.history.pushState({}, '', href);
		const navEvent = new PopStateEvent('popstate');
		// ⭐
		window.dispatchEvent(navEvent);
	};

  return (
		<a 
			onClick={onClick} 
			href={href} 
			className={className}
		>
				{children}
		</a>;
	);
};

export default Link;
```

Unfortunately, in the browser we won't find our app magically working. The links still update the url, but fail to change the render. Because we dispatched the `navEvent` to the `window` object, all of its children *should* be aware of it. So what gives? 


In this instance components are a lot like us as humans. Simply being aware of an occurrence doesn't guarantee that we know what to do about it, or in response to it. We could freeze and do nothing, act uncharacteristically, or need to be told how to respond. 

So, while the Link component successfully sends of an event object when clicked, the problem lies with the Route component. While aware of the event, it needs help to understand what to do next.

----

### Updating the Route Component

In the first iteration of the Nav component all of the links were working - that is to say clicking one brought us to a new page. But this was because the anchor elements triggered a full-page reload, re-initializing everything in the app all over again at the correct destination. We've disabled this costly process, but lost some expected functionality along the way. To reinstate some of that behavior we created our own navigation event by borrowing the `popstate` event type from the browser environment. 

The last step requires clueing in the Route component, coaching it to handle the `popstate` event using an event listener. The browser provides 2 self-explanatory methods you're probably familiar with, `addEventListener()` and `removeEventListener()`, to accomplish this. 

Performing tasks with event listeners in the confines of React is typically a good indication that we'll require the `useEffect` hook. This special hook gives us the power to reach into the lifecycle of a component - opening windows wherein we can turn listeners on and off. 

To start, import the `useEffect` hook directly from React. At the top of the component set up the `useEffect` function with an empty callback and dependency array: 

```jsx
src/routing/Route.js

import { useEffect } from 'react';

const Route = ({ children, path }) => {
	// ⭐
	useEffect(() => {},[]);

  return window.location.pathname === path ? children : null;
};

export default Route;
```

[React hooks](https://dev.to/ash_bergs/a-quick-guide-to-understanding-react-hooks-4o1) come with their own pre-defined behavior and purpose, and the choice to employ `useEffect` here is no accident. The code placed in the hook's first argument, the callback function, will run *after first render* - the perfect moment in time to turn on the event listener.

Inside the callback function we'll declare an arrow function, called `onPathChange()`, which will serve as the event handler. Then we'll bind an event listener to the `window` object: 

```jsx
src/routing/Route.js

import { useEffect } from 'react';

const Route = ({ children, path }) => {
	// ⭐
	useEffect(() => {
		// 1️⃣ handler function
		const onPathChange = () => {
			console.log("URL path changed!");
		};
		// 2️⃣ event listener
		window.addEventListener('popstate', onPathChange);
	},[]);

  return window.location.pathname === path ? children : null;
};

export default Route;
```

The `onPathChange` function is passed as the second argument to `addEventListener()`, the first argument is a string indicating the event type. 

Back in the browser, with the console open, clicking a link should return 3 log statements of "URL path changed!" We get 3 statements because there are 3 instances of the Route component currently rendering and now listening for a `popstate` event. 

![project screenshot](https://i.ibb.co/Xp6xjkV/pathLog.jpg)

Now that Route has started listening for a `popstate` event, it's aware when the url pathname changes, but it is not privy to what the pathname change to. To isolate this information we'll use another React hook, called `useState`. 

The `useState` hook returns a slice of state, which we'll call `currentPath`, and its setter function, named `setCurrentPath` by convention. Finally `useState` requires one argument, the initial state value - which we'll set to the browser-maintained `window.location.pathname` property. To finish, we'll consume `currentPath` in the return: 

```jsx
src/routing/Route.js

import { useEffect, useState } from 'react';

const Route = ({ children, path }) => {
	// ⭐
	const [currentPath, setCurrentPath] = useState(window.location.pathname);

	useEffect(() => {
		const onPathChange = () => {
			console.log("URL path changed!");
		};
		window.addEventListener('popstate', onPathChange);
	},[]);
  // ⭐
  return currentPath === path ? children : null;
};

export default Route;
```

While `window.location.pathname` is kept constantly up-to-date by the browser, it's important to note that our `currentPath` piece of state is a separate variable. Upon render it is given the value of whatever `window.location.pathname` is at that moment, but to change the `currentPath` any time after render we must use its setter function, `setCurrentPath`. Only then can the Route component know when and what the url pathname has changed to. 

To update `currentPath` in response to a `popstate` event, call the `setCurrentPath` function in the event handler - setting it to now updated `window.location.pathname`: 

```jsx
src/routing/Route.js

import { useEffect, useState } from 'react';

const Route = ({ children, path }) => {

	const [currentPath, setCurrentPath] = useState(window.location.pathname);

	useEffect(() => {
		const onPathChange = () => {
      // ⭐
			setCurrentPath(window.location.pathname);
		};
		window.addEventListener('popstate', onPathChange);
	},[]);

  return currentPath === path ? children : null;
};

export default Route;
```

In short, the `popstate` event lets the Route component know that a change has been made to `window.location.pathname`, its event listener then goes about retrieving those changes. After that, it can figure out which of its children, i.e. Home, About, or Contact, should be rendered. 

In the browser the links should be working again. The Route and Link components are working together with the browser environment to track a user's location in the app and update as needed. Crucially, they do all of this without triggering a full-page reload... But we're not quite done yet.

In the case that any of the Route or Link components is removed from render at any time in the future, we must turn the event listener off. Failing to do so will result in a breaking error. 

Thankfully the `useEffect` hook has a special feature known as a *cleanup function*. The cleanup function can be optionally returned from the hook, and will execute before the component is removed from the render. 

To use this feature in `Route.js`, we'll update the `useEffect` hook found there to return an anonymous function:

```jsx
src/routing/Route.js

import { useEffect, useState } from 'react';

const Route = ({ children, path }) => {

	const [currentPath, setCurrentPath] = useState(window.location.pathname);

	useEffect(() => {
		const onPathChange = () => {
			setCurrentPath(window.location.pathname);
		};
		window.addEventListener('popstate', onPathChange);
      // ⭐
      // 🧼 anonymous cleanup function
		return () => {
			window.removeEventListener('popstate', onPathChange);
		};
	},[]);

  return currentPath === path ? children : null;
};

export default Route;
```

The cleanup function turns off the listener with the `removeEventListener()` method, completing the circle. Basic routing, from beginning to end, is now in place. 

----

Though it seems nebulous, the browser environment wraps everything we do in React, Vue, Angular, and JS at large. In fact, beneath the interfaces of many npm libaries, we'll find the foundations for the framework often belong to the browser, proving that understanding it is essential to truly understanding and working with JavaScript.  

I hope this post has helped dispel some of the magic around not just React Router, but the browser environment, and the workings of npm libraries at large. 

### Resources:

- [Link Behavior](https://accessibility.oit.ncsu.edu/it-accessibility-at-nc-state/developers/accessibility-handbook/mouse-and-keyboard-events/links/link-behavior/) - NC State University 

- [Browser Environment](https://javascript.info/browser-environment) - javascript.info

- [JavaScript BOM](https://www.javascripttutorial.net/javascript-bom/) - javascripttutorial.net

- [Browser and Web APIs](https://medium.com/@antwan29/browser-and-web-apis-d48c3fd8739) - Antoine Leclercq, Medium.com

- [Using the HTML5 History API](https://css-tricks.com/using-the-html5-history-api/) - Robin Rendle, CSS-tricks.com

- [Moden React with Redux](https://www.udemy.com/course/react-redux/) - Stephen Grider, Udemy 🏛

##### 🦄 As always - thank you for reading! 🕶