Skip to content

Instantly share code, notes, and snippets.

@AndrewIngram
Created October 25, 2021 13:06
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 AndrewIngram/6ddf907a4c4f762c739162c4c9227f18 to your computer and use it in GitHub Desktop.
Save AndrewIngram/6ddf907a4c4f762c739162c4c9227f18 to your computer and use it in GitHub Desktop.
Yikes
import * as React from "react";
import { graphql, usePreloadedQuery } from "react-relay";
import { Button, Heading, Stack, Text } from "native-base";
import { ProfileScreenQuery } from "~/__generated__/ProfileScreenQuery.graphql";
import useLogout from "~/hooks/useLogout";
import { TabParamListProps } from "~/navigation-types";
import withData, { IScreenContainerProps } from "~/utils/withData";
type Props = TabParamListProps<"Profile"> &
IScreenContainerProps<ProfileScreenQuery>;
function ProfileScreen({ queryRef, query, ...props }: Props) {
const data = usePreloadedQuery(query, queryRef);
const logout = useLogout();
return (
<Stack flex={1} alignItems="center" justifyContent="center" space="4">
<Heading>Profile</Heading>
<Text>{data.user?.email}</Text>
<Button size="lg" rounded="full" colorScheme="blue" onPress={logout}>
Log out
</Button>
</Stack>
);
}
export default withData<ProfileScreenQuery>(ProfileScreen, {
query: graphql`
query ProfileScreenQuery {
user: currentUser {
email
}
}
`,
});
export default withData<ProfileScreenQuery>(ProfileScreen, {
^^^^^^^^^^^^^
Argument of type '({ queryRef, query, ...props }: Props) => Element' is not assignable to parameter of type 'ComponentType<IScreenContainerProps<ProfileScreenQuery>>'.
Type '({ queryRef, query, ...props }: Props) => Element' is not assignable to type 'FunctionComponent<IScreenContainerProps<ProfileScreenQuery>>'.
Types of parameters '__0' and 'props' are incompatible.
Type 'PropsWithChildren<IScreenContainerProps<ProfileScreenQuery>>' is not assignable to type 'Props'.
Type 'IScreenContainerProps<ProfileScreenQuery> & { children?: ReactNode; }' is missing the following properties from type 'TabParamListProps<"Profile">': navigation, routets(2345)
import React, { Suspense, useLayoutEffect } from "react";
import {
PreloadedQuery,
useQueryLoader,
useRelayEnvironment,
} from "react-relay";
import { ActivityIndicator, View } from "react-native";
import ErrorBoundary from "react-native-error-boundary";
import {
CacheConfig,
FetchPolicy,
GraphQLTaggedNode,
OperationType,
VariablesOf,
} from "relay-runtime";
import usePrevious from "~/hooks/usePrevious";
export interface IScreenContainerProps<TQuery extends OperationType> {
queryRef: PreloadedQuery<TQuery, Record<string, unknown>>;
query: GraphQLTaggedNode;
}
interface ICreatePageContainerConfig<
ScreenProps extends IScreenContainerProps<TQuery>,
TQuery extends OperationType,
> {
query: GraphQLTaggedNode;
getVariables?: (props: ScreenProps) => VariablesOf<TQuery>;
options?: {
suspend: boolean;
fetchPolicy?: FetchPolicy | undefined;
networkCacheConfig?: CacheConfig | undefined;
};
}
export default function withData<TQuery extends OperationType>(
Component: React.ComponentType<IScreenContainerProps<TQuery>>,
config: ICreatePageContainerConfig<
React.ComponentProps<typeof Component>,
TQuery
>,
): {
(props: React.ComponentProps<typeof Component>): React.ReactNode | undefined;
} {
function Container(
props: React.ComponentProps<typeof Component>,
): React.ReactNode {
const [queryRef, loadQuery, disposeQuery] = useQueryLoader<TQuery>(
config.query,
null,
);
const environment = useRelayEnvironment();
const previousEnvironment = usePrevious(environment);
useLayoutEffect(() => {
if (previousEnvironment && environment !== previousEnvironment) {
disposeQuery();
}
loadQuery(config.getVariables?.(props) ?? {}, {
fetchPolicy: "network-only",
});
return disposeQuery;
}, [environment]);
if (previousEnvironment && environment !== previousEnvironment) {
return null;
}
if (!queryRef) {
return null;
}
return (
<ErrorBoundary>
{config.options?.suspend ?? true ? (
<Suspense
fallback={
<View
style={{
flex: 1,
alignItems: "center",
justifyContent: "center",
}}
>
<ActivityIndicator size="large" />
</View>
}
>
<Component {...props} queryRef={queryRef} query={config.query} />
</Suspense>
) : (
<Component {...props} queryRef={queryRef} query={config.query} />
)}
</ErrorBoundary>
);
}
return Container;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment