GraphQL(React + Apollo)を使ってみました②(データ更新編)



下記記事の続きです。
前回はデータを取得して画面に表示するところまでだったので、今回はデータを更新できるようにします。




*参考



*環境

  • MacOS
  • react 16.9.0
  • graphql 14.4.2
  • react-apollo 3.0.0
  • react-router 5.0.1
  • react-router-dom 5.0.1


*データの更新

CreateLinkコンポーネントを新規作成します。
画面から入力される値はstateで管理し、setState()で更新します。
<Mutation />を使ってデータ更新の API リクエストを行います。プロパティではmutationに実行したいクエリ、variablesに更新する値を渡します。<button /><Mutation />で囲むことで、ボタンをクリックするとリクエストが実行されるようになります。
<react-app/src/components/CreateLink.js>
import React, { Component } from "react";
import { Mutation } from "react-apollo";
import gql from "graphql-tag";

// ---- gqlでGraphQLのクエリを作成 ----
const POST_MUTATION = gql`
  mutation PostMutation($description: String!, $url: String!) {
    post(description: $description, url: $url) {
      id
      createdAt
      url
      description
    }
  }
`;

class CreateLink extends Component {
  state = {
    description: "",
    url: ""
  };

  render() {
    const { description, url } = this.state;
    return (
      <div>
        <div className="flex flex-column mt3">
          <input
            className="mb2"
            value={description}
            onChange={e => this.setState({ description: e.target.value })}
            type="text"
            placeholder="A description for the link"
          />
          <input
            className="mb2"
            value={url}
            onChange={e => this.setState({ url: e.target.value })}
            type="text"
            placeholder="The URL for the link"
          />
        </div>
        // ---- 更新リクエスト -----
        <Mutation mutation={POST_MUTATION} variables={{ description, url }}>
          {postMutation => <button onClick={postMutation}>Submit</button>}
        </Mutation>
      </div>
    );
  }
}

export default CreateLink;

初期表示の画面でCreateLinkを表示するようApp.jsを修正します。
<react-app/src/components/App.js>
import React, { Component } from "react";
// ---- ↓修正 ----
import CreateLink from "./CreateLink";

class App extends Component {
  render() {
    // ---- ↓修正 ----
    return <CreateLink />;
  }
}

export default App;

サーバーをそれぞれ起動します。
## Reactアプリ側
/react-app/
$ npm start

## サーバー側
/react-app/server
$ npm start

下記リンクにアクセスすると、リンク先の説明とURLを入力する画面が表示されます。
http://localhost:3000/


入力欄に任意の値を入力して「Submit」ボタンを押します。
The best learning resource for GraphQL
www.howtographql.com

Playground で下記を実行してデータを取得すると、更新されていることが確認できます。
query GetLink{
  feed {
    links {
      id
      description
      url
      createdAt
    }
  }
}

<実行結果>
{
  "data": {
    "feed": {
      "links": [
        ...
        {
          "id": "cjz96btz68n1b0b53mgc0en37",
          "description": "The best learning resource for GraphQL",
          "url": "www.howtographql.com",
          "createdAt": "2019-08-13T01:55:24.930Z"
        }
      ]
    }
  }
}

<Playground>


*ルーティングの実装

新規作成画面と更新画面にそれぞれアクセスできるよう、ヘッダーを作成します。
Apollo でルーティング機能を実装するためにはreact-routerが必要なのでインストールします。
$ npm install react-router react-router-dom --save

Headerコンポーネントを新規作成します。
<react-app/src/components/Header.js>
import React, { Component } from "react";
import { Link } from "react-router-dom";
import { withRouter } from "react-router";

class Header extends Component {
  render() {
    return (
      <div className="flex pal justify-between npwrap orange">
        <div className="flex flex-fixed black">
          <div className="fw7 mr1">Hacker News</div>
          <Link to="/" className="ml1 no-underline black">
            new
          </Link>
          <div className="ml1">|</div>
          <Link to="/create" className="ml1 no-underline black">
            submit
          </Link>
        </div>
      </div>
    );
  }
}

export default withRouter(Header);

初期表示の画面でヘッダーを表示させるようApp.jsを修正します。
<Route />pathで対応させたいURL、componentに描画したいコンポーネントを指定します。exactを指定するとpathが完全一致したときのみマッチしたことになります。(指定しないと前方一致した全てに適用されてしまいます)
そして<Switch /><Route />をグループ化します。
<react-app/src/components/App.js>
import React, { Component } from "react";
import CreateLink from "./CreateLink";
import LinkList from "./LinkList";
// ---- ↓追加 ----
import Header from "./Header";
import { Switch, Route } from "react-router-dom";

class App extends Component {
  render() {
    return (
      // ---- ↓修正 ----
      <div className="center w85">
        <Header />
        <div className="ph3 pv1 background-gray">
          <Switch>
            <Route exact path="/" component={LinkList} />
            <Route exact path="/create" component={CreateLink} />
          </Switch>
        </div>
      </div>
    );
  }
}

export default App;

データ登録後、最初の画面に自動で遷移するよう修正します。
<Mutation>onCompletedを追加します。onCompletedは更新が正常完了したときに実行される処理です。
<react-app/src/components/CreateLink.js>
import React, { Component } from "react";
import { Mutation } from "react-apollo";
import gql from "graphql-tag";

const POST_MUTATION = gql`
  mutation PostMutation($description: String!, $url: String!) {
    post(description: $description, url: $url) {
      id
      createdAt
      url
      description
    }
  }
`;

class CreateLink extends Component {
  state = {
    description: "",
    url: ""
  };

  render() {
    const { description, url } = this.state;
    return (
      <div>
        <div className="flex flex-column mt3">
          <input
            className="mb2"
            value={description}
            onChange={e => this.setState({ description: e.target.value })}
            type="text"
            placeholder="A description for the link"
          />
          <input
            className="mb2"
            value={url}
            onChange={e => this.setState({ url: e.target.value })}
            type="text"
            placeholder="The URL for the link"
          />
        </div>
        // ---- ↓onCompletedを追加 ----
        <Mutation
          mutation={POST_MUTATION}
          variables={{ description, url }}
          onCompleted={() => this.props.history.push("/")}
        >
          {postMutation => <button onClick={postMutation}>Submit</button>}
        </Mutation>
      </div>
    );
  }
}

export default CreateLink;

アプリケーションを起動するとヘッダーが追加され、新規登録と更新ができるようになっています。

<初期表示>






<新規登録>









<更新>








*所感

更新の実装をするのも非常に簡単でした。簡単であるがゆえに、内部ではどう動いているのか、どういった部分に使うべきなのかといった考慮が必要かと感じました。
このチュートリアルでは Apollo を使った実装方法を学ぶと同時に React についても勉強になりました。まだ認証などの続きがあるので時間のあるときに取り組みたいと思います。

Previous
Next Post »

1 コメント:

Write コメント
maya
AUTHOR
2019年11月4日 16:43 delete

Thank you for the comment.
I'm glad to say that. I will study and post more.

Reply
avatar

人気の投稿