Skip to content

Instantly share code, notes, and snippets.

View mjackson's full-sized avatar

Michael Jackson mjackson

View GitHub Profile
mjackson / download-counts.mjs
Last active November 11, 2022 05:43
Download counts for react-router
const npmApiUrl = "";
async function fetchDownloadCounts(packageName, year) {
let range = `${year}-01-01:${year}-12-31`;
let response = await fetch(`${npmApiUrl}/${range}/${packageName}`);
return (await response.json()).downloads;
async function getDownloads(startYear, endYear = startYear) {
if (endYear < startYear) {
mjackson /
Last active March 12, 2024 08:39
Notes on route composition in React Router v6, along with a suggested improvement you can make today to start upgrading

Composing <Route> in React Router v6

Composition of <Route> elements in React Router is changing in v6 from how it worked in v4/5 and in Reach Router. React Router v6 is the successor of both React Router v5 and Reach Router.

This document explains our rationale for making the change as well as a pattern you will want to avoid in v6 and a note on how you can start preparing your v5 app for v6 today.


In React Router v5, we had an example of how you could create a element]( to restrict access to certain routes on the page. This element was a simple [wrapper around an actual element that made a simple decision: is the user authenticated or not? If so, ren

mjackson /
Last active November 12, 2023 07:32
Notes on handling redirects in React Router v6, including a detailed explanation of how this improves on what we used to do in v4/5

Redirects in React Router v6

An important part of "routing" is handling redirects. Redirects usually happen when you want to preserve an old link and send all the traffic bound for that destination to some new URL so you don't end up with broken links.

The way we recommend handling redirects has changed in React Router v6. This document explains why.


In React Router v4/5 (they have the same API, you can read about why we had to bump the major version here) we had a <Redirect> component that you could use to tell the router when to automatically redirect to another URL. You might have used it like this:

import React from "react";
export type ColorScheme = "light" | "dark";
export default function useColorSchemePreference(
defaultColorScheme: ColorScheme = "light"
) {
let darkQuery = "(prefers-color-scheme: dark)";
let [colorScheme, setColorScheme] = React.useState<ColorScheme>(
typeof window === "object" && window.matchMedia
import React from 'react';
let DataContext = React.createContext();
// A higher-order component for pairing preload function + component ...
function withData(preloadData, Component, autoPreloadOnRender = true) {
let needsPreload = !!autoPreloadOnRender;
let promise;
let value;
let feed = {
type: 'rss',
props: {
'xmlns:blogChannel': 'https://...',
version: '2.0',
children: [
type: 'channel',
props: {
title: 'Remix Blog',
function useControl(defaultValue, value, onChange) {
let [localValue, setLocalValue] = React.useState(defaultValue)
let isControlled = value != null // the key
let activeValue = isControlled ? value : localValue
let setActiveValue = nextValue => {
if (isControlled) {
if (onChange) {
} else {
toContainElement(instance, targetElement) {
let matchingElements = instance.findAllByProps(targetElement.props);
if (matchingElements.length === 0) {
return {
message() {
let props = JSON.stringify(targetElement.props);
return `expected to find element with props ${props}`;
import React from 'react';
import { lazy } from 'react-suspense-resource';
let Courses = lazy(() => import('./Courses.js'));
let CoursesIndex = lazy(() => import('./CoursesIndex.js'));
let routes = [
path: "courses",
element: <Courses />,
let routes = (
<RankedSwitch> picks the best child <Route> that matches
the path. Like <Switch>, it does not match deeply, so you
need to use /* on the path if you want to do that. Like
@reach/router's <Router>, it ranks the paths so you don't
have to think about ordering.
Con: You have to use /* to do deep matching