Skip to content

Instantly share code, notes, and snippets.

@leomiranda
Last active March 22, 2024 15:43
Show Gist options
  • Save leomiranda/73190eb91fbf868c1cc5ef2280b2d5e6 to your computer and use it in GitHub Desktop.
Save leomiranda/73190eb91fbf868c1cc5ef2280b2d5e6 to your computer and use it in GitHub Desktop.
Remix
// Helper: check data and throw error (loader and action)
/**
* Provide a condition and if that condition is falsey, this throws a 400
* Response with the given message.
*
* inspired by invariant from 'tiny-invariant'
*
* @example
* invariantResponse(typeof value === 'string', `value must be a string`)
*
* @param condition The condition to check
* @param message The message to throw
* @param responseInit Additional response init options if a response is thrown
*
* @throws {Response} if condition is falsey
*/
export function invariantResponse(
condition: any,
message?: string | (() => string),
responseInit?: ResponseInit,
): asserts condition {
if (!condition) {
throw new Response(
typeof message === 'function'
? message()
: message ||
'An invariant failed, please provide a message to explain why.',
{ status: 400, ...responseInit },
)
}
}
// Hook: check if is submitting (current route's form)
/**
* Returns true if the current navigation is submitting the current route's
* form. Defaults to the current route's form action and method POST.
*/
export function useIsSubmitting({
formAction,
formMethod = 'POST',
}: {
formAction?: string
formMethod?: 'POST' | 'GET' | 'PUT' | 'PATCH' | 'DELETE'
} = {}) {
const contextualFormAction = useFormAction()
const navigation = useNavigation()
return (
navigation.state === 'submitting' &&
navigation.formAction === (formAction ?? contextualFormAction) &&
navigation.formMethod === formMethod
)
}
// Type: get data from another route (type safety)
import { type loader as projectDetailsLoader } from './$pid'
export async function loader({ params }: LoaderArgs) {
return json({ task: await getTask(params.tid) })
}
export const meta: MetaFunction<
typeof loader,
{ 'routes/project/$pid': typeof projectDetailsLoader }
> = ({ data, matches }) => {
const project = matches.find(
match => match.id === 'routes/project/$pid',
).project
const task = data.task
return [{ title: `${project.name}: ${task.name}` }]
}
// Hook: check if the component already hydrated. Return true when the javascript on the client has actually run.
function useHydrated() {
const [hydrated, setHydrated] = useState(false);
useEffect(() => setHydrated(true), []);
return hydrated;
}
// helper: check if error has a message
/**
* Does its best to get a string error message from an unknown error.
*/
export function getErrorMessage(error: unknown) {
if (typeof error === 'string') return error
if (
error &&
typeof error === 'object' &&
'message' in error &&
typeof error.message === 'string'
) {
return error.message
}
console.error('Unable to get error message for error', error)
return 'Unknown Error'
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment