Skip to content

Instantly share code, notes, and snippets.

View simonrelet's full-sized avatar
🏠
Working from home

Simon Relet simonrelet

🏠
Working from home
  • Paris
View GitHub Profile
import { useLocation, useNavigation, useSearchParams } from "@remix-run/react";
import { useCallback, useMemo } from "react";
export function useOptimisticSearchParams() {
const location = useLocation();
const [searchParams, setSearchParams] = useSearchParams();
const navigation = useNavigation();
const nextSearchParams = useMemo(() => {
if (navigation.location?.pathname === location.pathname) {
import { useSearchParams } from "@remix-run/react";
import isEqual from "lodash.isequal";
import { useCallback, useMemo } from "react";
import type { NavigateOptions } from "react-router";
export function useParsedSearchParams<
TOutput extends object,
TInput extends object,
>(delegate: URLSearchParamsDelegate<TOutput, TInput>) {
const [searchParams, setSearchParams] = useSearchParams();
import { useMemo } from "react";
export function useComposedRef<TElement>(handlers: RefHandler<TElement>[]) {
// We actually want the handlers to be the dependency list.
// eslint-disable-next-line react-hooks/exhaustive-deps
return useMemo(() => composeRefs(handlers), handlers);
}
function composeRefs<TElement>(
handlers: RefHandler<TElement>[],
@simonrelet
simonrelet / index.page.tsx
Created February 3, 2023 18:17
URL query validation and typing with NextJs and Zod
// Shared URL query that can be imported from anywhere.
const PaginationUrlQuerySchema = z.object({
// Use .catch() in order to return a default value when validation fails.
// See https://zod.dev/?id=catch
page: z.coerce.number().min(0).catch(0),
});
// Page specific URL query combined with shared ones.
const MyPageUrlQuerySchema = PaginationUrlQuerySchema.extend({
enum: z.enum(["foo", "bar"]).catch("foo"),
@simonrelet
simonrelet / types_and_values.md
Created January 21, 2022 13:53
Types and Values

Extracted from https://stackoverflow.com/a/50396312

TypeScript: A world of Types and Values

As you are likely aware, TypeScript adds a static type system to JavaScript, and that type system gets erased when the code is transpiled. The syntax of TypeScript is such that some expressions and statements refer to values that exist at runtime, while other expressions and statements refer to types that exist only at design/compile time. Values have types, but they are not types themselves. Importantly, there are some places in the code where the compiler will expect a value and interpret the expression it finds as a value if possible, and other places where the compiler will expect a type and interpret the expression it finds as a type if possible.

The compiler does not care or get confused if it is possible for an expression to be interpreted as both a value and a type.

import throttle from 'lodash.throttle'
const DEFAULT_HISTORY_CAPACITY = 50
const DEFAULT_PUSH_THROTTLE_TIMEOUT = 500
/**
* The object defining the internal state of a History returned by
* `History.getState`.
*
* @template T
import invariant from 'invariant'
import warning from 'warning'
function identity(state) {
return state
}
function parse(serializedJSON) {
if (serializedJSON) {
try {
/** Geohashes are in base32. */
const MAX_CHILDREN_COUNT = 32
/**
* Compress an array of Geohashes using Hash Tree compression.
*
* @param {string[]} geohashes Array of Geohashes.
* @param {number} [minChildrenCount=32] The minimum number of children to concider a node full.
* @returns {string[]} A compressed version of the Geohashes.
*/
@simonrelet
simonrelet / apiMappers.js
Last active May 2, 2019 17:00
Bidirectional object mapping
/**
* @typedef {object} Mapper
* @property {function(any): any} fromAPI
* @property {function(any): any} toAPI
*
* @typedef {object} Config
* @property {string} [name]
* @property {Mapper} [mapper]
*
* @typedef {Object.<string, string | Config>} MixedMappings