Skip to content

Instantly share code, notes, and snippets.

View louis-young's full-sized avatar
💻
Probably building something with React 😄

Louis Young louis-young

💻
Probably building something with React 😄
View GitHub Profile
@louis-young
louis-young / index.tsx
Last active February 24, 2023 09:49
Generic React component with render prop
import type { ReactNode } from "react";
export type ObjectWithIdentifier = {
id: number;
};
export type ListProps<TItem> = {
items: TItem[];
render: (item: TItem) => ReactNode;
};
@louis-young
louis-young / index.ts
Last active March 31, 2023 10:22
TypeScript invariant assertion function
export function invariant(condition: unknown, message: string): asserts condition {
if (!condition) {
throw new Error(message);
}
}
@louis-young
louis-young / index.tsx
Created November 7, 2022 14:35
useImperativeHandle with TypeScript and function components
import { forwardRef, useImperativeHandle, useRef } from "react";
export interface VideoProps {
source: string;
}
export interface VideoRef {
play: () => void;
pause: () => void;
}
@louis-young
louis-young / index.ts
Created February 24, 2023 09:47
Safe context hook creator function
import { type Context, useContext } from "react";
import { invariant } from "../invariant";
export const createSafeContextHook = <TContextValue>(
context: Context<TContextValue>,
displayName: string
) => {
return () => {
const contextValue = useContext(context);
@louis-young
louis-young / index.tsx
Created March 22, 2023 14:07
useIntersectionObserver
import { useEffect } from "react";
import type { UseIntersectionObserverParameters } from "./types";
export const useIntersectionObserver = ({
observableRef,
callback,
options,
}: UseIntersectionObserverParameters) => {
useEffect(() => {
const intersectionObserver = new IntersectionObserver(
@louis-young
louis-young / index.tsx
Created March 22, 2023 14:08
Infinite Scroll
import { useRef } from "react";
import { useIntersectionObserver } from "../../hooks/useIntersectionObserver";
import type { InfiniteScrollProps } from "./types";
export const InfiniteScroll = ({
loadMoreFunction,
isLoadingMore,
loadingMoreMessage,
hasLoadedEverything,
loadedEverythingMessage,
@louis-young
louis-young / index.ts
Last active May 25, 2023 16:32
useDebouncedValue
import { useEffect, useState } from "react";
export const useDebouncedValue = <TValue>(value: TValue, delay: number) => {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const timeout = setTimeout(() => {
setDebouncedValue(value);
}, delay);
@louis-young
louis-young / index.tsx
Created July 19, 2023 15:01
Asynchronous React component
import type { ReactNode } from "react";
interface AsynchronousComponentProps<TData> {
children: (data: NonNullable<TData>) => ReactNode;
data: TData;
isLoading: boolean;
loadingFallback: ReactNode;
hasError: boolean;
errorFallback: ReactNode;
}
@louis-young
louis-young / index.ts
Last active July 25, 2023 21:24
Lunchtime LINQ challenges
/**
* https://markheath.net/post/lunchtime-linq-challenge
*/
interface GetSecondsFromMinutesAndSecondsParameters {
minutes: number;
seconds: number;
}
const getSecondsFromMinutesAndSeconds = ({
@louis-young
louis-young / index.ts
Last active September 6, 2023 16:53
C# LINQ method analogs in TypeScript
const singleOrDefault = <TElement, TDefaultValue>(
array: ReadonlyArray<TElement>,
predicate: (element: TElement) => boolean,
defaultValue: TDefaultValue
): TElement | TDefaultValue => {
if (array.length === 0) {
throw new Error("The source sequence is empty.");
}
const element = array.find(predicate);