We're finally creating the app itself. The challenge require us to create a list which different users can access and add objects. At first, I thought about creating a selling used items list, however we shall create an event list instead.
Our event will be composed of a Title, a Date, a Description and an Author.
Event components
Let's start by creating EventCard
and EventList
components and updating the query to get more information from events. Note whenever you change a graphql query, you must run yarn relay
// packges/app/src/components/EventList.js
import React from 'react';
import {ScrollView, Text} from 'react-native';
import {graphql} from 'babel-plugin-relay/macro';
import {QueryRenderer} from 'react-relay';
import Environment from '../relay/Environment';
import EventCard from './EventCard';
const EventList = ({query}) => {
const {events} = query;
return (
<>
<Text>Event List</Text>
<ScrollView>
{events.map(event => (
<EventCard key={event.id} event={event} />
))}
</ScrollView>
</>
);
};
const EventListQR = () => {
return (
<QueryRenderer
environment={Environment}
query={graphql`
query EventListQuery {
events {
id
title
date
description
}
}
`}
variables={{}}
render={({error, props}) => {
console.log('qr: ', error, props);
if (error) {
return <Text>{error.toString()}</Text>;
}
if (props) {
return <EventList query={props} />;
}
return <Text>loading</Text>;
}}
/>
);
};
export default EventListQR;
/// packages/app/src/components/EventCard.js
import React from 'react';
import {Text} from 'react-native';
const EventCard = ({event}) => {
return (
<>
<Text>Title: {event.title}</Text>
<Text>Date: {event.date}</Text>
<Text>Description: {event.description}</Text>
<Text>Author: {event.author}</Text>
</>
);
};
export default EventCard;
You'll also need an updated schema.graphql
. Create an Event Type and Event Model in the server's package as you did with Product. Run yarn update-schema
and copy the server's graphql.schema
to the app's graphql.schema
. Check this commit to some details.
Run yarn relay
to compile the graphql query's code.
Then we can import the EventList component into our App component and render it
// packages/app/src/App.js
const App = ({query}) => {
const {products} = query;
return (
<Fragment>
<EventList />
</Fragment>
);
};
EventCreate with Formik
First we have to configure our Mutation root type in our server
// packages/server/graphql/schema.js
const {
GraphQLSchema,
GraphQLObjectType,
GraphQLID,
GraphQLList,
GraphQLNonNull,
GraphQLString
} = require("graphql");
const { fromGlobalId, mutationWithClientMutationId } = require("graphql-relay");
const eventGraphQLType = require("./eventType");
const Event = require("../models/Event");
const Query = new GraphQLObjectType({
name: "Query",
fields: {
event: {
type: eventGraphQLType,
args: { id: { type: GraphQLNonNull(GraphQLID) } },
resolve(parent, args) {
return Event.findById(fromGlobalId(args.id).id);
}
},
events: {
type: GraphQLList(eventGraphQLType),
resolve() {
return Event.find();
}
}
}
});
const EventCreate = mutationWithClientMutationId({
name: "EventCreate",
inputFields: {
title: {
type: new GraphQLNonNull(GraphQLString)
},
date: {
type: new GraphQLNonNull(GraphQLString)
},
description: {
type: new GraphQLNonNull(GraphQLString)
}
},
outputFields: {
id: {
type: GraphQLID,
resolve: payload => payload.id
}
},
mutateAndGetPayload: async ({ title, date, description }) => {
const newEvent = new Event({
title,
date,
description
});
const returnedObject = await newEvent.save();
const eventId = await returnedObject._id;
console.log(`New Event created with id: ${eventId}`); //this will be in a subscription
return {
id: eventId
};
}
});
const Mutation = new GraphQLObjectType({
name: "Mutation",
fields: {
EventCreate: EventCreate
}
});
module.exports = new GraphQLSchema({
query: Query,
mutation: Mutation
});
(we might want to split this code soon)
We're creating the root Mutation type and a EventCreate mutation type. This new type receives a title, date and description string and returns the new event's id.
Run yarn update-schema
to create schema.graphql
in the server's package. It should be looking like this.
type Event {
id: ID!
_id: String
title: String
date: String
description: String
author: String
}
input EventCreateInput {
title: String!
date: String!
description: String!
clientMutationId: String
}
type EventCreatePayload {
id: ID
clientMutationId: String
}
type Mutation {
EventCreate(input: EventCreateInput!): EventCreatePayload
}
type Query {
event(id: ID!): Event
events: [Event]
}
Now copy schema.graphql
to replace the same file in the app's package.
Then create an EventCreate
component with Formik as it follows:
// packages/app/components/EventCreate.js
import React from 'react';
import {TextInput, Button, ButtonText} from 'react-native';
import {Formik} from 'formik';
import EventCreateMutation from './EventCreateMutation';
const EventCreate = () => {
const handleSubmit = values => {
const {title, date, description} = values;
const input = {
title,
date,
description,
};
const onCompleted = id => {
// Some implementation that requires the id from
// the new event created
alert(JSON.stringify(id));
// Redirect
// this.props.navigation.navigate('UserList');
};
const onError = err => {
console.error(err);
};
EventCreateMutation.commit(input, onCompleted, onError);
};
return (
<Formik
initialValues={{title: '', date: '', description: ''}}
onSubmit={values => handleSubmit(values)}>
{({values, handleChange, handleSubmit}) => (
<>
<TextInput
placeholder="Title"
onChangeText={handleChange('title')}
value={values.title}
/>
<TextInput
placeholder="Date"
onChangeText={handleChange('date')}
value={values.date}
/>
<TextInput
placeholder="Short description"
onChangeText={handleChange('description')}
value={values.description}
/>
<Button onPress={handleSubmit} title="Add Event"></Button>
</>
)}
</Formik>
);
};
export default EventCreate;
To use mutations, you have to create a mutation file and commit it as you can see above.
// packages/app/components/EventCreateMutation.js
import {commitMutation, graphql} from 'react-relay';
import Environment from '../relay/Environment';
const mutation = graphql`
mutation EventCreateMutation($input: EventCreateInput!) {
EventCreate(input: $input) {
id
}
}
`;
function commit(input, onCompleted, onError) {
return commitMutation(Environment, {
mutation,
variables: {
input,
},
onCompleted,
onError,
});
}
export default {commit};
We now can add new Events and after reloading (via yarn shake
for example) we can see that our new event is in the list. We might not worry about live update and subscriptions yet.
Navigation
In React we could use react-router, but in React-Native we're going to use react-navigation
install it and its dependencies by running the following inside packages/app
:
yarn add react-native-reanimated react-native-gesture-handler react-native-screens
And add the navigator we're going to use:
yarn add react-navigation-tabs
Now edit App.js
as it follows:
import React from 'react';
import {createAppContainer} from 'react-navigation';
import { createMaterialTopTabNavigator } from 'react-navigation-tabs';
import EventList from './EventList';
import EventCreate from './EventCreate';
const App = createMaterialTopTabNavigator(
{
EventCreate: {screen: EventCreate},
EventList: {screen: EventList},
},
{
initialRouteName: 'EventList',
},
);
export default createAppContainer(App);
And then we can navigate between our screens.
Later we migth change this navigator to another one.
Debugging tips
Run yarn relay
always after adding/changing a graphql query
Run yarn update-schema
always after changing schema.js
Keep both schema.graphql
files identical
Run yarn android
after changing app's dependencies
Try yarn start:app --reset-cache
Run yarn redirect
Close and open app in the smartphone
References
React Native + Formik + Yup ❤️
Formik documentation
React Navigation documentation
GraphQL.js documentation
Top comments (0)