Building a Navbar with React-Router, React-Bootstrap, and TypeScript

I’m building a React SPA and using react-router-dom for routing, and react-bootstrap as a component library. For a simple header, I had several goals:

  1. Active nav links are styled (you can tell which one you’re on, and hovering the link to the page you’re on does not show a pointer or hover style; but links to other pages do)
  2. Clicking the active link (or the Navbar.Brand component, when on the home page) should not reload the page you’re already on
  3. On mobile, clicking a nav menu item should collapse on click
  4. Use TypeScript

These three goals seemed very straightforward and not contradictory; but I had a hard time making them play nicely together.

The Problem

To detect the active links, the NavLink component of react-router-dom has an isActive property you can reference in an inline style, for example:

style={({ isActive }) => ({ cursor: isActive ? 'default' : 'pointer' })}

However, to get the react-bootstrap Navbar menu to collapseOnSelect, you have to use the react-bootstrap Nav.Link component, not NavLink.

You also can’t nest a Nav.Link within a NavLink; nesting <a> tags breaks the HTML standards.

I tried many iterations; getting one to work using “as” to render a different component than I specified:

<Nav.Link as={NavLink} eventKey="1" style={({ isActive }) => ({ cursor: isActive ? 'default' : 'pointer' })} to="/">

…until I tried to add TypeScript. Then it was just barking about the conflicting properties between those two definitions.

The Solution

Enter another library:

import { LinkContainer } from 'react-router-bootstrap';

Then the code was blissfully simple, working properly, and conforming to TypeScript! I had to add in the forced active={false} since both libraries apply an “active” property, which leaves multiple links appearing “active” after navigating. Best to disable the Nav.Link ones and just let LinkContainer do the work.

    <LinkContainer to="/">
        <Nav.Link active={false}>Home</Nav.Link>
    <LinkContainer to="/about">
        <Nav.Link active={false}>About</Nav.Link>

Fixing 404 error for a React SPA on a subdomain

The problem:

I have WordPress installed on my website’s root domain; I wanted to deploy an unrelated React SPA to a subdomain on the same site. The root of the SPA loaded fine, but if I tried to access any routes deeper than the root, I was being served the 404 from my wordpress page.

What I already did:

I set up the application to be served from a subdirectory according to the React Router guidelines:

  1. Updated package.json to have a line for:
    "homepage": ""
  2. Updated the Router component to have a basename:
    <Router basename={'/myApp'}>
  3. Confirmed any links within my app are using the react-router-dom Link component (or useNavigate) instead of a direct “href”
  4. Updated my image source to: img src={`${process.env.PUBLIC_URL}/icon.png`}

This had everything working from localhost, serving from localhost:3000/myApp and looking good; but I was still having this 404 error after deploying a build and navigating to a route.

The solution:

The .htaccess file at my primary domain’s root was taking over and redirecting any unknown (to the server) routes to my 404 page.

I needed to add a new .htaccess file (filename: .htaccess) in my application’s directory on the server (I used cPanel to do this, but you could use FTP or anything you normally use to move files to your server) with the following contents:

RewriteEngine on
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
RewriteRule ^ index.html [L]

Now I can access without getting a 404 error 🙌

How to avoid getting your Facebook account hacked

I am a tech-savvy person, and of no importance or influence, haha; so I was very surprised (and annoyed) to have become a victim of a recent Facebook hacker. No idea if this was an individual, bot, organization, whatever. All I know is I already had 2-factor authentication set up (which means, you need to confirm your identity on a separate method when logging in on a new device), but my backup method was by SMS text message, which apparently can be intercepted and used by the hacker to gain access to your account.

I received an email overnight that said someone was trying to log in from a new location, followed by a text at 3:30 AM with a confirmation code. They somehow used that code to get access to my account, add their email as a secondary email (I see it when I try to log in, but it’s mostly obfuscated so I don’t know the actual email address), and changed the 2-factor authentication to use a separate encrypted app, so now I no longer receive the codes to log in; they do. They also cleared my recent logins, so I don’t have any active logins anywhere to reset my settings, and everything is treated like a new device.

First, if this happens to you, report it and secure your account immediately, so they can’t continue logging in. It then has you send them a picture of your Photo ID, but it says it can take weeks to review (if they decide to review it at all).

To avoid this happening, on your Facebook app (not web version), go to your privacy & security settings; under Settings, find the option for 2-factor authentication, and turn it on. Set the Authentication type as Authentication App (NOT SMS).

To finish this process, you’ll need to download a 3rd party encrypted authenticator app. Microsoft has a good one (Microsoft Authenticator), or you can use Google Authenticator or LastPass Authenticator, etc. One that you trust or already use.

Then you say on Facebook to show you a code, copy that code, and paste it into your authenticator app as a new account.

Now, when you log into Facebook for the first time from a new device, you will have to open up your separate Authenticator app to get the 6 digit code to enter. It is far more secure than receiving it over SMS.

NPR had a story about this issue recently; it’s happening to a LOT of people lately so please take a few seconds to upgrade your security, or your account is at risk and you may not get it back.