This is a guide to implement an app with a relay hook which is currently experimental, in expo managed workflow.
We’ve been managing our experiments in an opensource chat app called HackaTalk. Previously, we’ve integrated our app with apollo-client v2 and recently, we were thinking of migrating to apollo-client v3.
Many developers today are suspecting that the relay might possibly be integrated inside react when concurrent mode rises in react v17. Therefore, this time, I took time in reading about react and relay, and the react’s official blog truly helped me to drive my next graphql-client to use the relay.
Since I’ve provided useful articles in the above paragraphs, people might be aware of what react, relay, expo, concurrent mode, and graphql are. Therefore, I’ll just go through how to use the relay in our project HackaTalk. Also, this will help other people to use the relay in their projects.
Let’s look at our work in relay integration in PR done by Eunho Lee 🙌
Since we’d like to use the relay hook, we chose relay experimental and followed the installation guide.
1. Installation
yarn add react@experimental react-dom@experimental react-relay@experimental// dev
yarn add --dev babel-plugin-relay graphql relay-compiler
(Optional) Additional step for typescript users
- Followed by relay-compiler-language-typescript, add below to
babel.config.js
.
plugins: [
['relay', { artifactDirectory: './src/__generated__' }],
...
- Declare module in your environment file.
// environment.d.ts
declare module 'babel-plugin-relay/macro' {
export { graphql } from 'react-relay';
}
- Exclude below in
tsconfig.json
"exclude": ["node_modules", "**/*.test.tsx", "**/*.spec.ts", "src/__generated__"],
- Additional note when a jest is failing. Followed by the issue provided, you can try to remove the brackets.
2. Add relay compile script to package.json
"relay": "relay-compiler --src ./src --schema schema.graphql --language typescript --artifactDirectory ./src/__generated__","relay-watch": "yarn relay-compiler --schema schema.graphql --src ./src/ --extensions ts tsx --language typescript --artifactDirectory ./src/__generated__ --watch",
relay
for compiling once andrelay-watch
for compiling while coding.
3. Install experimental version for react
, react-dom
, and relay
"react": "^0.0.0-experimental-33c3af284",
"react-dom": "^0.0.0-experimental-33c3af284",
"react-relay": "^0.0.0-experimental-94e87455",
"relay-hooks": "^3.4.0",
- Above versions are what we are using to use
relay-hook
4. Add relay.config.js
file
module.exports = {
src: './src',
schema: './schema.graphql',
exclude: [
'**/node_modules/**',
'**/__mocks__/**',
'src/__generated__/**'
],
};
- Above file contains a configuration options accepted by the
relay-compiler
command-line tool andbabel-plugin-relay
.
5. Add relay configuration file in relay
directory
6. Import relay hooks in which you want to put root graphql provider
import { RelayEnvironmentProvider, graphql, preloadQuery, usePreloadedQuery, useRelayEnvironment,} from 'react-relay/hooks';import relayEnvironment from './relay/RelayEnvironment';
Then wrap with RelayEnvironmentProvider
.
<RelayEnvironmentProvider environment={relay}>
<Suspense fallback={<Text>loading app...</Text>}>
<ActionSheetProvider>
<App />
</ActionSheetProvider>
</Suspense>
</RelayEnvironmentProvider>
7. Writing the first mutation
1. Write the mutation query in SignIn.tsx
const signInEmail = graphql`
mutation SignInEmailMutation($email: String!, $password: String!) {
signInEmail(email: $email, password: $password) {
token
user {
id
email
name
photoURL
verified
}
}
}
`;
- Important rule here is that the
mutation
should start with the same name as a component which isSignIn
in here.
2. Running yarn relay
will generate SignInEmailMutation
andSignInEmailMutationResponse
so import them.
import type {
SignInEmailMutation,
SignInEmailMutationResponse,
} from '../../__generated__/SignInEmailMutation.graphql';
3. Inside the SignIn
screen component, add below mutationConfig
const [commitEmail, isInFlight] = useMutation<SignInEmailMutation>(signInEmail);const mutationConfig = {
variables: {
email,
password,
},
onCompleted: async (response: SignInEmailMutationResponse): Promise<void> => {
const { token, user } = response.signInEmail; if (user && !user.verified) {
return navigation.navigate('VerifyEmail', {
email,
});
} await AsyncStorage.setItem('token', token);
await AsyncStorage.setItem('password', password);
initializeEThree(user.id);
setUser(user);
},
onError: (error: any): void => {
showAlertForGrpahqlError(error?.graphQLErrors);
},
};
- The
commitEmail
is where you want to requestsignInEmail
to the server whileisInFlight
judges the loading state.
8. Writing the first query
1. As we did in writing mutation query, write a query in App.tsx
.
const userQuery = graphql`
query AppUserQuery {
me {
id
email
verified
}
}
`;
- Here again, important rule follows as in mutation. The query should start with the same name as a component which is
App
in here.
2. Run yarn relay
and generate AppUserQuery
and AppUserQueryResponse
.
import type { AppUserQuery, AppUserQueryResponse } from './__generated__/AppUserQuery.graphql';
3. Use userPreloadQuery
to query the result.
const result = preloadQuery<AppUserQuery>(
environment,
userQuery,
{},
{ fetchPolicy: 'store-and-network' },
);
const data = usePreloadedQuery<AppUserQuery>(userQuery, result);
- Next to data, it will fetch data and return results.
4. Use useEffect to handle the received data.
useEffect(() => {
// do what you want
}, [data.me]);
9. Testing
1. Install relay-test-utils
yarn add relay-test-utilsyarn add -D @types/relay-test-utils
2. Add below in test/setupTest.js
which is one of jest setupFiles
.
jest.mock('../src/relay/RelayEnvironment', () => {
const { createMockEnvironment } = require('relay-test-utils');
return createMockEnvironment();
});
- Above setting will prevent your tests to fail when running
npx jest
. However, more advanced testing experience will be shared separately.
Thanks for reading 🙏.
Here is the post for testing relay components.