GitHub Link : MERN-app-using-graphql-apollo-client
So finally we are done with our express server in part-2 of this series. Now we will focus on client(frontend) of this MERN app.
MERN App using GraphQL via Apollo-Client,(React Hooks). (Part-1)
MERN App using GraphQL via Apollo-Client,(React Hooks). (Part-2)
To create our client we will choose 'create-react-app' library to create a react application for us.
To install 'create-react-app' : npm install -g create-react-app
In the Vehicle-Management System in which we have earlier created our backend 'server' folder, hit the following command in terminal.
npx create-react-app my-client
cd my-client
//Delete each and every file in 'src' folder except //'app.js','index.css','index.js'
//App.js
import React from "react";
function App() {
return (
<div className="App">
<h1>List of Cars</h1>
</div>
);
}
export default App;
To run react-app hit : npm start
Above command will open react-app on browser using localhost:3000.
Before Implementing our frontend we need to install our dependencies of apollo-client & graphql.
npm install apollo-boost react-apollo graphql --save.
Right now we are in a good shape to start our client implementation.
apollo-boost
It provide us ApolloClient which help us to connect express-graphQL server which is running on 'localhost:4000/graphql'.
react-apollo
It provide us ApolloProvider which help react app to connect with data retrieved by ApolloClient.
//app.js
import React from "react";
import ApolloClient from "apollo-boost"; //connect with our server which is running at backend
import { ApolloProvider } from "react-apollo"; // Connect react with apollo.
//Using ApolloClient to connect with server
const client = new ApolloClient({
uri: "http://localhost:4000/graphql"
});
function App() {
return (
<ApolloProvider client={client}>
<div className="App">
<h1>List of Cars</h1>
</div>
</ApolloProvider>
);
}
export default App;
In above code, If you have worked on 'React-Redux' then you can simply understand how data is transferred from parent to it child devices. Those who don't know about the React-Redux, dont worry child-components will get this client data as props.
To understand about React-Redux : React-Redux Basic Understanding
Crud-Operation in React-Redux : Crud in React-Redux
a) Create 'CarList' component.
First of all create a 'components' folder inside 'src' folder. And inside 'components' folder create file 'CarList.js'
import React from "react";
const CarList = props => {
return (
<>
<ul id="carList">
<li>CarName</li>
</ul>
</>
);
};
export default CarList;
Import this component in App.js file to show it in our app.
//App.js
import React from "react";
import ApolloClient from "apollo-boost"; //connect with our server which is running at backend
import { ApolloProvider } from "react-apollo"; // Connect react with apollo.
import CarList from "./components/CarList";
//Using ApolloClient to connect with server
const client = new ApolloClient({
uri: "http://localhost:4000/graphql"
});
function App() {
return (
<ApolloProvider client={client}>
<div className="App">
<h1>List of Cars</h1>
<CarList></CarList>
</div>
</ApolloProvider>
);
}
export default App;
b) Create Graphql Query and embed result it in CarList component.
At first, create a folder name 'queries' inside src folder. Inside 'queries' folder create a new file 'queries.js'.
We will use 'gql' const from 'apollo-boost'.
//queries.js
import { gql } from "apollo-boost";
const getCarsQuery = gql`
{
cars {
name
id
}
}
`;
export default getCarsQuery;
In above file, We make a same query which we are creating in graphql tool on 'localhost:4000/graphql' server to get the list of cars with details.
Now connect 'getCarsQuery' in CarList component
//CarList
import React from "react";
import { graphql } from "react-apollo";
import getCarsQuery from "./../queries/queries";
const CarList = props => {
console.log(props); //check in the browser to see this values.
return (
<>
<ul id="carList">
<li>CarName</li>
</ul>
</>
);
};
export default graphql(getCarsQuery)(CarList); //HOC
Look at the bottom of the file, we are passing our query in graphql function to process it and get data from server.
If you guys dont know how this thing work or What it is called? Then look for my article on this High Order Components in React
Right now our console is giving errors and the main reason is we need cors() implementation on our server which is running in other terminal.
In our server code, open app.js file.
//Add two lines
const cors = require("cors");
/**
* Cors added as middleware
*/
app.use(cors());
It will restart again and now see in frontend app console to see data.
props.data.loading is true when server hitting the mongodb and it become 'false' when data is loaded'.
c) Iteration of cars datalist
import React from "react";
import { graphql } from "react-apollo";
import getCarsQuery from "./../queries/queries";
const CarList = props => {
console.log(props);
const displayCars = () => {
var data = props.data;
if (data.loading) {
return <div>Loading Cars...</div>;
} else {
return data.cars.map(car => {
return <li key={car.id}>{car.name}</li>;
});
}
};
return (
<>
<ul id="carList">{displayCars()}</ul>
</>
);
};
export default graphql(getCarsQuery)(CarList);
d) Add new Car
To add a new Car create 'AddCar' component in components folder.
import React from "react";
import { getOwnersQuery } from "./../queries/queries";
import { graphql } from "react-apollo";
const AddCar = props => {
const getOwners = () => {
var data = props.data;
if (data.loading) {
return <option disabled>Owner loading...</option>;
} else {
return data.owners.map(owner => {
return (
<option key={owner.id} value={owner.id}>
{owner.name}
</option>
);
});
} //esle ends here
};
return (
<>
<form>
<div className="field">
<label>Car Name</label>
<input type="text" name="carName"></input>
</div>
<div className="field">
<label>Model</label>
<input type="number" name="model"></input>
</div>
<div className="field">
<label>Company:</label>
<input type="text" name="company"></input>
</div>
<div className="field">
<label>Owner:</label>
<select>
<option>Select Owner</option>
{getOwners(props)}
</select>
</div>
<button>AddCar</button>
</form>
</>
);
};
export default graphql(getOwnersQuery)(AddCar);
Create getOwnersQuery in queries.js file
import { gql } from "apollo-boost";
const getCarsQuery = gql`
{
cars {
name
id
}
}
`;
const getOwnersQuery = gql`
{
owners {
name
id
}
}
`;
export { getCarsQuery, getOwnersQuery };
** Now add entry of AddCar.js file in app.js**
function App() {
return (
<ApolloProvider client={client}>
<div className="App">
<h1>List of Cars</h1>
<CarList></CarList>
<AddCar></AddCar>
</div>
</ApolloProvider>
);
}
e) Make CustomHook to handle Form Data
Create a folder 'hooks' inside the 'src' folder.
// handleFormHook.js
import React from "react";
const HandleFormHook = callback => {
const [inputs, setInputs] = React.useState({});
const handleSubmit = event => {
if (event) {
event.preventDefault();
console.log(inputs);
}
callback();
};
const handleInputChange = event => {
event.persist();
setInputs(inputs => ({
...inputs,
[event.target.name]: event.target.value
}));
};
return {
handleSubmit,
handleInputChange,
inputs
};
};
export default HandleFormHook;
Now Update AddCar.js component to use this Custom Hook.
//AddCar.js
import React from "react";
import { getOwnersQuery } from "./../queries/queries";
import { graphql } from "react-apollo";
import HandleFormHook from "./../hooks/handleFormHook";
const AddCar = props => {
const getFormData = () => {
console.log(`${inputs}`);
};
const { inputs, handleInputChange, handleSubmit } = HandleFormHook(
getFormData
);
const getOwners = () => {
var data = props.data;
if (data.loading) {
return <option disabled>Owner loading...</option>;
} else {
return data.owners.map(owner => {
return (
<option key={owner.id} value={owner.id}>
{owner.name}
</option>
);
});
} //esle ends here
};
return (
<>
<form onSubmit={handleSubmit}>
<div className="field">
<label>Car Name</label>
<input
type="text"
name="carName"
onChange={handleInputChange}
value={inputs.carName}
></input>
</div>
<div className="field">
<label>Model</label>
<input
type="number"
name="model"
onChange={handleInputChange}
value={inputs.model}
></input>
</div>
<div className="field">
<label>Company:</label>
<input
type="text"
name="company"
onChange={handleInputChange}
value={inputs.company}
></input>
</div>
<div className="field">
<label>Owner:</label>
<select
name="owner"
onChange={handleInputChange}
value={inputs.owner}
>
<option>Select Owner</option>
{getOwners(props)}
</select>
</div>
<button>AddCar</button>
</form>
</>
);
};
export default graphql(getOwnersQuery)(AddCar);
getFormData() will get all the values of the form data.Check console for result.
To understand about hooks : Hooks (Make Custom Hooks)
f) Hit Mutation code.
Install > npm install recompose --save
Add Mutation query in queries.js file
//queries.js
//mutation function getting arguments from calling function and passing to //addCar.
const AddCarMutation = gql`
mutation($name: String!, $model: Int!, $company: String!, $ownerId: ID!) {
addCar(name: $name, model: $model, company: $company, ownerId: $ownerId) {
name
id
}
}
`;
export { getCarsQuery, getOwnersQuery, AddCarMutation };
Now change the AddCar.js file to hit the addCar mutation on server and add updated list.
import React from "react";
import { compose } from "recompose";
import {
getOwnersQuery,
AddCarMutation,
getCarsQuery
} from "./../queries/queries";
import { graphql } from "react-apollo";
import HandleFormHook from "./../hooks/handleFormHook";
const AddCar = props => {
const getFormData = () => {
console.log(`${inputs}`);
//Hitting AddCarMutation with arguments.
props.AddCarMutation({
variables: {
name: inputs.carName,
model: parseInt(inputs.model),
company: inputs.company,
ownerId: inputs.owner
},
refetchQueries: [{ query: getCarsQuery }] // to update carsQuery on CarList.js
});
};
const { inputs, handleInputChange, handleSubmit } = HandleFormHook(
getFormData
);
const getOwners = () => {
var data = props.getOwnersQuery;
if (data.loading) {
return <option disabled>Owner loading...</option>;
} else {
return data.owners.map(owner => {
return (
<option key={owner.id} value={owner.id}>
{owner.name}
</option>
);
});
} //esle ends here
};
return (
<>
<form onSubmit={handleSubmit}>
<div className="field">
<label>Car Name</label>
<input
type="text"
name="carName"
onChange={handleInputChange}
value={inputs.carName}
></input>
</div>
<div className="field">
<label>Model</label>
<input
type="number"
name="model"
onChange={handleInputChange}
value={inputs.model}
></input>
</div>
<div className="field">
<label>Company:</label>
<input
type="text"
name="company"
onChange={handleInputChange}
value={inputs.company}
></input>
</div>
<div className="field">
<label>Owner:</label>
<select
name="owner"
onChange={handleInputChange}
value={inputs.owner}
>
<option>Select Owner</option>
{getOwners(props)}
</select>
</div>
<button>AddCar</button>
</form>
</>
);
};
//For hitting two queries we need compose library.
export default compose(
graphql(getOwnersQuery, { name: "getOwnersQuery" }),
graphql(AddCarMutation, { name: "AddCarMutation" })
)(AddCar);
In below screenshot, you can see I add a new car 'Ciaz'.
g) Now add CarDetails.js component to show car details.
Add new Query in queries.js file
const getCarQuery = gql`
query($id: ID!) {
car(id: $id) {
id
name
model
company
owner {
id
name
age
cars {
name
company
id
}
}
}
}
`;
export { getCarsQuery, getOwnersQuery, AddCarMutation, getCarQuery };
Now add CarDetails.js
import React from "react";
import { graphql } from "react-apollo";
import { getCarQuery } from "./../queries/queries";
const CarDetails = props => {
console.log(props.carId.Id);
const getCarDetails = () => {
const { car } = props.data;
console.log(car);
if (car) {
return (
<div>
<h2>{car.name}</h2>
<p>model : {car.model}</p>
<p>company : {car.company}</p>
<p>owner : {car.owner.name}</p>
<p>All cars by this owner :</p>
<ul>
{car.owner.cars.map(item => {
return <li key={item.id}>{item.name}</li>;
})}
</ul>
</div>
);
} else {
return <div>No Car Selected</div>;
}
};
return <div id="carDetails">{getCarDetails()}</div>;
};
//Passing carId in getCarQuery
export default graphql(getCarQuery, {
options: props => {
return {
variables: {
id: props.carId.Id
}
};
}
})(CarDetails);
Finally update the CarList.js from where we can select the cars.
//CarList.js
import React from "react";
import { graphql } from "react-apollo";
import { getCarsQuery } from "./../queries/queries";
import CarDetails from "./CarDetails";
const CarList = props => {
console.log(props);
const [Id, setCar] = React.useState(0);
const displayCars = () => {
var data = props.data;
if (data.loading) {
return <div>Loading Cars...</div>;
} else {
return data.cars.map(car => {
return (
<li key={car.id} onClick={e => setCar({ Id: car.id })}>
{car.name}
</li>
);
});
}
};
return (
<>
<ul id="carList">{displayCars()}</ul>
<CarDetails carId={Id}></CarDetails>
</>
);
};
export default graphql(getCarsQuery)(CarList);
Click on any Car and you will get details of that car and its owner.
Final Output
Sorry guys for not adding any Css part here.
Whoaaa! we have just completed our MERN app using graphql via apollo-client.
Hope you learnt something from this articles.
Top comments (4)
Thanks for the series @vinodchauhan7 ~
You can link the series with
series
tag in the front matter.You can refer to the Editor Guide 😉.
Ok Kim, will do that surely.
tks so much guy!
Please add update functionality