MERN App using GraphQL via Apollo-Client,(React Hooks). (Part-3) FrontEnd
Tags: react, graphql, mern
Published: 2019-09-12 18:47:19

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/cqepkau8mio5hhg4ekoy.png)

[GitHub Link : MERN-app-using-graphql-apollo-client](https://github.com/vinodchauhan7/MERN-app-using-graphql-apollo-client/tree/master)

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)](https://dev.to/vinodchauhan7/mern-app-using-graphql-via-apollo-client-react-hooks-part-1-17p9)**

**[MERN App using GraphQL via Apollo-Client,(React Hooks). (Part-2)](https://dev.to/vinodchauhan7/mern-app-using-graphql-via-apollo-client-react-hooks-part-2-2ifn)**

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.

```javascript
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*.

 

```javascript
//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](https://codesandbox.io/s/reactredux-understanding-slw9n) 

**Crud-Operation in React-Redux** : [Crud in React-Redux] (https://codesandbox.io/s/react-redux-crud-lqopj)


### a) Create 'CarList' component.
First of all create a 'components' folder inside 'src' folder. And inside 'components' folder create file 'CarList.js'
```javascript
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.**
```javascript
//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'.

```javascript
//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
```javascript
//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](https://dev.to/vinodchauhan7/high-order-component-hoc-in-react-what-why-ml6)**

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.
```javascript
//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.

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/n0k3fk6rcbuip1hrtm8y.png)

**props.data.loading is true when server hitting the mongodb and it become 'false' when data is loaded'.**


### c) Iteration of cars datalist
```javascript
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.
```javascript
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**
```javascript
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**
```javascript
function App() {
  return (
    <ApolloProvider client={client}>
      <div className="App">
        <h1>List of Cars</h1>
        <CarList></CarList>
        <AddCar></AddCar>
      </div>
    </ApolloProvider>
  );
}
```
![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/qd8gcttb9ajc0awwatog.png)


### e) Make CustomHook to handle Form Data
Create a folder 'hooks' inside the 'src' folder.
```javascript
// 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.

```javascript
//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)](https://dev.to/vinodchauhan7/react-hooks-usestate-useeffect-useref-usememo-2dj)

> [Advanced Hooks demo](https://codesandbox.io/s/advanced-react-hooks-grf7o)

### f) Hit Mutation code.

> Install > npm install recompose --save

Add Mutation query in queries.js file

```javascript
//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.**

```javascript
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'.
![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/y7nkd9gxw8l285aad2jt.png)

###g) Now add CarDetails.js component to show car details.

Add new Query in queries.js file

```javascript
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
```javascript
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.

```javascript
//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
![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/6615cqjxnk8y0ycoph1t.png)

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.