Skip to content

Instantly share code, notes, and snippets.

@brettinternet
Last active June 18, 2023 04:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save brettinternet/5968fdf2e229e4ef0cfdcff22ff24a50 to your computer and use it in GitHub Desktop.
Save brettinternet/5968fdf2e229e4ef0cfdcff22ff24a50 to your computer and use it in GitHub Desktop.
Derive data result from nullable with data selection - useful when you use react query as a state tool
// Nullable user example:
type MaybeUser = UserQuery['user']
/**
* Possibly null user, such as on an auth page
* Here's a description on why these overloads are required: https://stackoverflow.com/a/67640634
*/
export function useMaybeUser<UserData = MaybeUser>(
select: (user: MaybeUser) => UserData
): UserData
export function useMaybeUser(select?: undefined): MaybeUser
export function useMaybeUser<UserData = MaybeUser>(
select?: (user: MaybeUser) => UserData
): UserData | MaybeUser
export function useMaybeUser<UserData = MaybeUser>(
select?: (user: MaybeUser) => UserData
): UserData | MaybeUser {
return useUserQuery(gqlClient, {}, { select }).data
}
const Component: React.FC = () => {
const userId = useMaybeUser(user => user?.id)
if (userId) {
return <User id={userId} />
}
return null
}
// Non nullable user example:
type User = NonNullable<UserQuery['user']>
/**
* Returns non nullable value in a nested part of the React tree where you're sure to have the data
*/
export function useUser<UserData = User>(
selectUser: (user: User) => UserData
): UserData
export function useUser(select?: undefined): User
export function useUser<UserData = User>(
selectUser?: ((user: User) => UserData) | undefined
): UserData | User
export function useUser<UserData = User>(
selectUser?: ((user: User) => UserData) | undefined
): UserData | User {
const select = useCallback(
(user: User) => {
if (!user) {
throw Error('User not found.')
}
if (select) {
return select(user)
}
return user
},
[selectUser]
)
const user = useUserQuery(gqlClient, {}, { select }).data
if (!user) {
throw Error('User not found.')
}
return user
}
// `useUserQuery` is queried higher up in the react tree, so data should be present at this level
const Component: React.FC = () => {
// Now, despite being nullable, user arg and return values will be non null in the select callback
const userId = useUser(user => user.id)
return <User id={userId} />
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment