Skip to content

Instantly share code, notes, and snippets.

View tannerlinsley's full-sized avatar

Tanner Linsley tannerlinsley

View GitHub Profile
@tannerlinsley
tannerlinsley / useBroadcastLeader.ts
Created June 4, 2021 14:37
A React Hook to determine if a tab of your application is the "leader" using BroadcastChannel and leader election
import { BroadcastChannel, createLeaderElection } from 'broadcast-channel'
import React from 'react'
const channels = {}
export function useBroadcastLeader(id = 'default') {
const [isBroadcastLeader, setIsBroadcastLeader] = React.useState(false)
React.useEffect(() => {
if (!channels[id]) {
@tannerlinsley
tannerlinsley / React Query v4 (Ezil Amron) RFC.md
Last active June 4, 2021 15:07
An RFC to rewrite React Query's API to allow for opt-in normalization

React Query v4 (Ezil Amron) RFC

Preface: This is an RFC, which means the concepts outlined here are a work in progress. You are reading this RFC because we need your help to discover edge cases, ask the right questions and offer feedback on how this RFC could improve.

What are we missing today without normalization?

Today, React Query uses unstructured query keys to uniquely identify queries in your application. This essentially means RQ behaves like a big key-value store and uses your query keys as the primary keys. While this makes things conceptually simple to implement and reason about on the surface, it does make other optimizations difficult (and a few others impossible):

  • Finding and using Initial/placeholder single-item queries from list-like queries. While this is possible today, it's very manual, tedious, and prone to error.
  • Manual optimistic updates that span multiple query types and shapes (eg. single-item queries, list queries and infinitely-paginated queries) are tedious and pr
@tannerlinsley
tannerlinsley / examples.ts
Last active January 22, 2021 19:28
Generic Mapping in Typescript Example
import { Merge } from 'type-fest'
type MergeGenerics<TDefaultGenerics, TUserGenerics> = Merge<
Required<TDefaultGenerics>,
TUserGenerics
>
interface Person {
name: string
@tannerlinsley
tannerlinsley / createCrudHooks.js
Created November 29, 2020 06:39
A naive, but efficient starter to generate crud hooks for React Query
export default function createCrudHooks({
baseKey,
indexFn,
singleFn,
createFn,
updateFn,
deleteFn,
}) {
const useIndex = (config) => useQuery([baseKey], indexFn, config)
const useSingle = (id, config) =>

So this is kind of a multi stage plugin system. Let me explain:

Plugins get sent to the makeUseTable constructor, which then type the available options usable on useTable.

const useTable = makeUseTable({
  plugins: [myPlugin],
})

function App() {
@tannerlinsley
tannerlinsley / README.md
Last active July 25, 2025 16:15
Replacing Create React App with the Next.js CLI

Replacing Create React App with the Next.js CLI

How dare you make a jab at Create React App!?

Firstly, Create React App is good. But it's a very rigid CLI, primarily designed for projects that require very little to no configuration. This makes it great for beginners and simple projects but unfortunately, this means that it's pretty non-extensible. Despite the involvement from big names and a ton of great devs, it has left me wanting a much better developer experience with a lot more polish when it comes to hot reloading, babel configuration, webpack configuration, etc. It's definitely simple and good, but not amazing.

Now, compare that experience to Next.js which for starters has a much larger team behind it provided by a world-class company (Vercel) who are all financially dedicated to making it the best DX you could imagine to build any React application. Next.js is the 💣-diggity. It has amazing docs, great support, can grow with your requirements into SSR or static site generation, etc.

So why

@tannerlinsley
tannerlinsley / useGlobalMemo.js
Created August 28, 2020 23:45
useGlobalMemo is a React hook that lets you share memoizations across an entire app using a unique key.
const cache = {}
export default function useGlobalMemo (key, fn, deps) {
if (!cache[key]) {
cache[key] = {
subs: 0,
deps,
value: fn(),
}
// Scenario 1
const { data } = useQuery(
'jointKey1and2',
() => Promise.all([fetch1(), fetch2()]),
{
refetchInterval: 1000,
}
)
import React from 'react'
import immer from 'immer'
//
export default function makeStore() {
// Create a context for this store
const context = React.createContext()
let store = {}
@tannerlinsley
tannerlinsley / README.md
Created July 22, 2020 20:38
Why I still don't use GraphQL

Some thoughts I've gathered over the years on what I think about GraphQL. All of this is subject to change of course, and some of it may be "hot-take"-ish, but at the end of the day, I've made decisions regarding GraphQL with my customers, users, and fellow developers in mind and with the mantra that if it ultimately doesn't make a big difference for any of those people and justify the work that it requires, it's not the best investment of time. It's more important to please your users, ship products in a timely manner, and use tools that keep processes simple and familiar.

  • A majority of the world still runs on REST and probably will for a while.
  • The challenges of larger companies that originally benefitted from GQL are not everyones challenges and they likely never will be.
  • I don't want to require my API users to have knowledge of GQL.
  • Strongly typed APIs are good, but I don't particularly enjoy the tools in the ecosystem right now to use them via GQL
  • GraphQL seems to have been born out of the req