Skip to content

Instantly share code, notes, and snippets.

@mstewartgallus
Created April 18, 2023 17:25
Show Gist options
  • Save mstewartgallus/a95bf10d37e0b12ab549449eb5ba753e to your computer and use it in GitHub Desktop.
Save mstewartgallus/a95bf10d37e0b12ab549449eb5ba753e to your computer and use it in GitHub Desktop.
Mostly silly because you can just use an error boundary utility based around https://react.dev/reference/react/Component#static-getderivedstatefromerror
import {
lazy, Suspense,
createContext, useCallback, useContext, useEffect, useReducer, useTransition
} from "react";
const initialState = {
poison: false,
throwable: undefined
};
const reducer = (state, throwable) => {
if (state.poison) {
return state;
}
return { poison: true, throwable };
};
const useJump = () => {
const [, startTransition] = useTransition();
const [{ poison, throwable }, dispatch] = useReducer(reducer, initialState);
const jump = useCallback(x => startTransition(() => dispatch(x)), []);
return { poison, throwable, jump };
};
const throwStub = throwable => {
throw throwable;
};
// FIXME use Suspense ?
const createException = (displayName, defaultHandler = null) => {
const Ex = createContext(defaultHandler ?? throwStub);
Ex.displayName = displayName;
const { Provider } = Ex;
const useThrow = throwable => {
const jump = useContext(Ex);
// FIXME slow? You can't update component while inside a
// different component without an indirection like useEffect.
useEffect(() => jump(throwable), [throwable, jump]);
};
const Throw = ({value}) => {
useThrow(value);
return null;
};
const Catch = ({children, fallback}) => {
const { poison, throwable, jump } = useJump();
return poison ?
fallback(throwable) :
<Provider value={jump}>
{children}
</Provider>;
};
return { Throw, Catch };
};
const Foo = createException('Foo');
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment