Last active
March 22, 2024 15:43
-
-
Save leomiranda/73190eb91fbf868c1cc5ef2280b2d5e6 to your computer and use it in GitHub Desktop.
Remix
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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