GraphQL

Create GraphQL Apollo Client using React Part 2

January 29, 2018

author:

Create GraphQL Apollo Client using React Part 2

In the previous post, we had a detail look at read and insert operation in React for GraphQL API. In this one, we will now work on remaining update and delete operation.

# Refactors

For the purpose of simplicity, let us add the create and insert links on the home page that is post list component itself. Add following snippets in list_company.js:

# src/app/components/list_company.js
...
import { Link } from "react-router-dom";

class CompaniesList extends Component {
	...
  
  render() {	
    ...
    return (
      <div>
        <div className="text-right">
          <Link className="btn btn-primary" to="/company/create">
            Add a Company
          </Link>
        </div>
        <ul className = "list-group" > {
          Companies.map(c => <li className = "list-group-item" key = { c.id }> 
            <div className="company-list">
              <div className="company-name">
                ...
              </div>
              <div className="company-btn">
                <Link className="btn btn-primary" to={`company/${c.id}/update`}>
                  Update
                </Link>                
              </div>
            </div>
          </li> 
          ) } 
        </ul> 
    </div>
    );
  };
}
...

Also, add delete button which we wire in a moment:

# src/app/components/list_company.js
...

class CompaniesList extends Component {
	...
  
  render() {	
    ...
    return (
      ...
        <div className="company-btn">
          <Link className="btn btn-primary" to={`company/${c.id}/update`}>
            Update
          </Link>
          <button type="submit" className="btn">Delete</button>
        </div>
      ...
    );
  };
}
...

You can notice the changes:
Add Buttons in React App

# Update Mutation in React GraphQL API

To add update feature to our company list application, let us add a fresh udpate_company.js file in src/app/components namespace. Honestly, insert and update are very similar. So let us straightly move to the difference between both the files. The basic and most obvious change is in the mutation schema:

# src/app/components/update_comapny.js
...

const updateCompany = gql`
  mutation updateCompany($id: ID!, $name: String!) {
    updateCompany (id: $id, name: $name){
      id
      name
    }
  }
`;

const CompanyUpdateWithMutations =  compose(
  graphql(updateCompany, {
    name: 'updateCompany'
  })
)(EditCompany)

export default CompanyUpdateWithMutations;

And wire the same with onSubmit handler.

onFormSubmit(event) {
  event.preventDefault();
  const { name } = this.state;
  console.log(this.props);
  this.props.updateCompany({
    variables: { id: this.props.match.params.cId, name }
  })
  .then(() => {
    this.setState({ name: "" });
    this.props.history.push("/");
  });
}

Rest of the logic and code remains same as create_company. Note that you would also create a separate form component for insert and update input fields to reuse prevent code duplication. But since we are focusing on implementation of react-apollo in this example, we will skip that and get back to graphql implications. Here’s the complete EditCompany component:

# src/app/components/update_company.js

import React, { Component } from 'react';
import { withRouter } from 'react-router'
import { gql, graphql, compose } from 'react-apollo';

import { Link } from "react-router-dom";

class EditCompany extends Component {
  constructor(props) {
    super(props);
    this.state = { name: "" };
    this.onNameChange = this.onNameChange.bind(this);
    this.onFormSubmit = this.onFormSubmit.bind(this);
  }

  onNameChange(event) {
    this.setState({ name: event.target.value });
  }

  onFormSubmit(event) {
	  event.preventDefault();
	  const { name } = this.state;
	  console.log(this.props);
	  this.props.updateCompany({
		  variables: { id: this.props.match.params.cId, name }
		})
		.then(() => {
		  this.setState({ name: "" });
		  this.props.history.push("/");
		});
  }
  
	render() {	
		 return (		  
			   <div>
        <h3> Update Company </h3>
        <div className="form-holder">
          <form onSubmit={this.onFormSubmit}>
            <input
            type="text"
            className="form-control post-control"
            placeholder="Name"
            value={this.state.name}
            onChange={this.onNameChange}
            />

            <ul className='list-inline company-actions'>            
              <li><button type="submit" className='btn btn-primary'>Update</button></li>
              <li><Link to="/" className='btn btn-danger'>Cancel</Link></li>
            </ul>
          </form>
        </div>
      </div>
		);
	};
}

const updateCompany = gql`
  mutation updateCompany($id: ID!, $name: String!) {
    updateCompany (id: $id, name: $name){
      id
      name
    }
  }
`;

const CompanyUpdateWithMutations =  compose(
  graphql(updateCompany, {
    name: 'updateCompany'
  })
)(EditCompany)

export default CompanyUpdateWithMutations;

Also, wire this component to the root component:

# src/app/app.js
...
import EditCompany from './components/update_company';

...

render(
<ApolloProvider client={client}>
  ...
    <Switch>
      <Route path="/company/create" component={CreateCompany} />
      <Route path="/company/:cId/update" component={EditPost} />
      <Route path="/" component={CompaniesList} />	  
    </Switch>
  ...
</ApolloProvider>,
app
)

# Testing

Let us quickly test the update operation on react application:

http://localhost:7800
React Update Form for GraphQL Apollo API

# Delete Mutation in React GraphQL API

For the delete operation, we will tweak the list_company.js further. Add a new mutation deleteCompany:

const DeleteCo = gql`
  mutation deleteCompany($id: ID!) {
    deleteCompany(id: $id) {
      id
      name
    }
  }
`;

Next, wire an onClick event to the delete button.

<button type="submit" className="btn" onClick={() => this.handleDelete(c.id)}>Delete</button>

Also, add relevant event handler :

handleDelete (cId)  {
  this.props.DeleteCo({variables: { id: cId }})
    .then(console.log('deleted'));
}

Until now everything was quite self-explanatory. Now let us inject this mutation with graphql apollo. But wait, haven’t we already injected the CompanyList query?

const CompanyListQuery = gql `
  query CompanyList{
    Companies {
      id
      name
    }
  }
`;

const CompanyListWithData = graphql(CompanyListWithData)(CompaniesList);

To inject multiple graphql elements, we can use react-apollo’s compose function. Replace the graphql query injection with:

# src/app/components/list_company.js
...
import { gql, graphql, compose } from 'react-apollo';
class CompaniesList extends Component {
 ...
}

//Replace this
const CompaniesListWithData = graphql(CompanyListQuery )(CompaniesList);
export default CompaniesListWithData;

//with
const CompanyListWithMutations = compose(
  graphql(CompanyListQuery),
  graphql(DeleteCo, {
 name: 'DeleteCo'
  })
)(CompaniesList)
export default CompanyListWithMutations;

# Testing

Let us test the post application for the final time.

http://localhost:7800

Press the delete button on any post.

Parting Thoughts:

In this post, we took the last tutorial forward and worked around update and delete operations for GraphQL API. We used Apollo Client for the same. But currently, the application flow isn’t really smooth. In the coming sessions, we will also add a feature for realtime UI updates which will improve UX to a much greater level.

Questions or Comments:

Was it useful? Got any issues/questions in implementing GraphQL Apollo Client with Query and Mutation in your application? Share them in comment section below.

Leave a comment

Your email address will not be published. Required fields are marked *