Coming to Terms with React Router

When I first learned about modern approaches to routing user requests to the appropriate resources I was learning Ruby on Rails and working under a RESTful paradigm. Next, I learned a bit about NodeJS and Express, which seemed to me to work in a very similar fashion. When I started learning React Router it seemed very different from those two, and I finally concluded that that’s because it is!

First of all, let me explain what I think the purpose of a router is in a web application. A router is the collection of tools that interprets a request from a user, usually by parsing a URL, and directs the server to the controller or method that is designated to respond to that request. Usually, this results in a server response to the user that provides the requested resource. In a RESTful app, this would look something like this:

But with React Router, there is no back end server at all, so everything is handled in the user’s browser. Since it always seemed to me that the key feature of a router was the routing part, I found this a bit confusing. I found it useful for myself to think of React Router as more of a filter for components, that does its filtering based on the URL. React Router does more than this, but in terms of how it simulates a traditional Router, this is a key point. New components are shown based on a pattern matching algorithm that matches URLs and updates the browser’s history to simulate page refreshes and different resources loading.

An artificial example will illustrate this point.

See the Pen React Router Example by Bryan Hooper (@bthooper) on CodePen.

If you examine this code, you will notice a list of links working more or less as a navigation menu. The links are created using React Router’s <Link> component, which creates the <a> tag for the link. Each link points to a simple URL. Then, down in the App component, the <Route> components, also from React Router, direct traffic to render content depending on which route you are requesting. It seems simple enough, but React Router does some funny things with matching the URL and the paths. First of all, if you head over to codepen where you can play with this code, you will notice that every route you choose always renders the “/” route - namely the word “Home”.

You might conclude that React Router is just matching whatever meets the minimum requirement to match the route. If it starts with “/”, as all routes do, than the Home route will always match. You can see this behavior again when you click on More About. Here, the URL is “/about/more” and that matches “/” and “/about” as well as “/about/more.”

But when you click on More Yet, things get a little fuzzy. The URL is “/about/moreyet” but only “/”, “/about” and “about/moreyet” are matched. What wasn’t “/about/more” matched? My guess is that React Router doesn’t look at the URL as a string, but rather as a collection of strings separated by “/”. So each string is comparaed aginst the other string within that segment enclosed by “/”s. The other somewhat unexpected behavior is demonstrated when you click on Blog. Two routes are pointing to “/blog” and so, when you click on that link you get both routes back! I guess it isn’t that surprising, but one can see how it might produce unexpected results.

React Router provides a Switch component that can address some of these issues. Switch works by finding the first match and then only rendering the first match. However, it too can produce some surprising results if you aren’t careful. Simply adding the Switch component around our routes will resutl in ONLY the home route displaying, since it is always matched. The “exact” keyword can be used to only match a URL exactly to overcome this problem.

In my mind it was helpful to think of React Router less as a routing tool that loads assets when requested by a user and more as a conditional rendering tool, that renders components based on matching the URL. Instead of a “router” I thought of it more as a conditional render tool. Routes are more like conditions or “if/then” checks that decided when to disply a component based on a given URL. Once I started thinking of React Router this way, it’s behavior made much more sense to me and I was able to build more reliable React Router routes.

React Router is a powerful piece of software that does more than just “direct traffic.” It also manipulates the browser history to maintain the appearance of a true router and preserve your URLs just like a real URL even though it is all rendered in the browser. I have only started scratching the surface of React Router, and I am eager to engage with it some more.

A Lectionary Browser

Recently, I have been working on an interactive Lectionary Browser. A lectionary, in case you do not know, is a collection of scripture readings used in the planning of Chrisitan worship in some Christian communities. The most common lectionary is the Revised Common Lectionary, which is the focus of my little app.

The RCL consists of a three-year cycle. Each year contains a year’s worth of readings for every Sunday of the Christian Year and also some special days. And each day is part of a particular season that corresponds to the time of the year. The seasons are the same every year, but the readings for each day are different.

The RCL names it’s years with a complete lack of creativity. The first year is named “Year A.” Guess what the others are called? Year B and Year C! So clever. But they are somewhat thematic as each year tends to focus on one of the synoptic Gospels (Matthew, Mark and Luke) and all of the years turn to John for special days.

The seasons used by the RCL are Advent, Christmas, Season After Epiphany, Lent, Easter, and Season After Pentecost. The Season After Epiphany and the Season After Pentecost are somtimes referred to as “Ordinary Time” but the use of the word “ordinary” is confusing. It does not mean that they are dull. Rahter, it means they are “ordered” or “ordinal” and thus follow the pattern prescribed by the lectionary.

For my app, I first created a Ruby on Rails back end that served as an API for the lectionary readings. My application supports muliptle lectionaries, though I only modeled the RCL. In the future, I could add additional lectionaries easily. The Lectionary Browser also provides a RESTful interface, so resources are found via logical URL structure. All requests made to the RESTful API are responded to with standard JSON responses.

For the frontend of my app, I wrote a React app that uses Redux for state management. Redux was the most difficult part of this project for me because it is conceptually a little complex, but as I build the app and started using it in a real application, I started understanding how it works.

I made a nice video to show you how the app is supposed to work:

The hardest part of this project for me was getting my head around Redux and how it is supposed to work. Redux is a tool for managing state, which is something React does natively, but the React model is somewhat limiting. With Redux, you can provide pieces of your state to your components as you need to from a centralized store where all your state is stored. In order to accomplish this, the Redux packing provides tools for creating your store and manipulating it. Another package, called “react-redux” makes Redux integrate nicely with your React components by connecting them to your Redux store - with a function cleverly called “connect.”

Once you have your components thought through, and the data they will need discerned, you can connect them to your Redux store and retrieve the data you need for that component. Changes can be made, but you have to be careful that you don’t mess up your state, so Redux uses Actions and a Dispatch function that manages your changes to your state. Your actions are simple functions that describe your changes, and dispatch is a function provided by Redux that safely updates your state. While it sounds complicated, and it is a bit, it actually makes state management much simpler.

I hope to continue working on this project, adding a user model and note taking capability among other features. So, perhaps, if I find time, I will make this app more useful.

A screencapture of our website.

My First Hackathon

Last week I participated in my first ever “hackathon.”

A hackathon is an event where teams of programmers and nerds address a particular problem with a technological solution over a set time period. Often these are 24 hour or weekend spanning experiences that encourage sleep deprivation and poor diet choices. Ours however spanned the whole week since it was conducted virtually to accomodate the COVID age.

The Future of Forestry Hackathon focused on the forestry industry in New England and was partially sponsored by Do North Coworking where I sometimes hang out. I was part of a three-person team randomly put together as part of the hackathon. Getting to know each other and work well together in such a short time frame was one of the challenges of the hackathon, but we ended up working well together over Slack and email. We decided to tackle the first problem statement:

How can environmental and geospatial data be used to evaluate potential logging margins to ensure they are commensurate to the financial risk associated with harvesting wood? Reliable margins in logging can be challenging to come due to unforeseen environmental factors. In many cases, market value of the harvested wood doesn’t reflect the time and risk associated with the harvest for specific trees. Whether the most valuable trees are two miles in through dense forest requiring significant time and fuel or the tree is on steep slope making it very dangerous or challenging to harvest, the market pricing doesn’t reflect these factors, nor do loggers have the tools to do this evaluation.

Our solution focused on providing a core set of tools for assisting in the process of valuing standing timber and risks associated with harvesting that timber. We used GIS data provided for us as part of the challenge to map a small farm and provide information related to the timber on that farm and how to navigate the terrain. We also created a calculator tool that allows for inputs from a harvester to calcuate the potential financial value of a paricular tree.

A number of problems arose as we worked on this project. I was surprised at how difficult it is to find regional pricing information for harvested timber. I assume these prices are confidential and that lumber mills who buy harvested wood don’t really want to share their prices. It would be a neat project to find a way to report pricing information or to work with an industry group to encourage more pricing transperancy. I think more clarity about pricing would assist harvesters in evaluating the potential reward for their efforts and also find suitible buyers for thier produce.

It was a lot of fun for me to work on this project and I look forward to another hackathon in the future. For my contribution to the project, I configured a Linode server and installed the necessary software. I set up NodeJS and used ExpressJS to build out a webserver. I also created the Tiber Tally calculator feature. My partners did the heavy lifting on all the GIS stuff and the CSS/design pieces. There is currently a server up and running, but I won’t be able to leave it up forever since it’s cositng me a little money.

Since we are in the Northeast Kingdom of Vermont, not a lot of teams finished their projects. Despite quite a bit of initial interest, only three teams submitted final projects and one of those teams was not able to present because of internet problems. Nevertheless, I am proud to report that our project was selected the winner! Not bad for my first hackathon.

Burke Mountain has been my go-to spot.

Looking forward to Winter

This year, I am hoping for a long, snowy winter.

Last year our winter was cut short on account of COVID. This year our winter will be different because of COVID. Ski resorts are posting their precautions and rules and though they vary from place to place, the bottom line is that things will be different.

Most resorts, as far as I know, are not opening their indoor spaces. So, you won’t be able to enjoy lunch (at least inside) or an after-ski beer. That will be tough! But if we have good snow, I don’t think I’ll care. I’ll just focus on the positive and enjoy some good skiing.

This will be my third season downhill skiing. I did not grow up doing this as a kid. In Texas, snow was an extremely rare oddity. I remember one year we got a “snow” and the news covered it. A kid had made a respectable snowball, but it required all the snow on his front lawn. The grass was green underneath. That was the biggest snow I remember.

Now, I am pretty used to snow. And I’m excited for season three on the slopes. Here’s hoping for a cold, snowy, long winteer. It will be a welcome distraction from all the other crazy things going on in the world.

Another Overstatement

This is yet another Overstatement.

I am moving my blog again - in part as a learning exercize. This site is now running on Nginx, being createed with Jekyll. I configured the server, so here’s hoping it is all working right…

And maybe with this new set up I’ll post a bit more. That would be good for me.

Thank you to all my fans.