20200707のReactに関する記事は4件です。

ざっくり Apollo

Apollo のチュートリアルをやったので、そこから分かったことをざっくりまとめ

時間がある人は Apollo がとても丁寧にチュートリアルを作ってるので、実際に手を動かしてやるととても理解が深まります
https://www.apollographql.com/docs/tutorial/introduction/

動機

GraphQL とはなんぞやということが知りたかった

概要

サーバーサイドでやること

GraphQL ではまず下記の三つを定義

  • スキーマ(js のオブジェクト go の構造体みたいなの)
  • Query(REST で言うとこの GET のメソッドたち)
  • Mutation(REST で言うとこの POST, PUT, DELETE のメソッドたち)

DB(データソース)へのコネクトの conf 書いて
Resolver(GET でどんな処理をするかとか POST でどんな処理するかとか)を定義する

クライアントサイドでやること

Apollo Client を使って GrapQL をかく
(他にもクライアントサイドでの state の管理とかできるけど今回は割愛)

詳細

サーバーサイド

※チュートリアルで使ってた ApolloServer(すなわち node)前提

まず GraphQL で扱うスキーマを定義

const { gql } = require("apollo-server");

const typeDefs = gql`
  type Anime {
    id: ID!
    title: String
    charactor: [Charactor]
  }

  type Charactor {
    id: ID!
    name: String
    age: String
    description: String
  }
`;

Query(REST でいうところの GET を定義)

type Queryの中に GET のメソッド書く感じ

const typeDefs = gql`
  # ↑のコードの続き

  type Query {
    animes: [Anime]
    anime(id: ID!): Anime
  }
`;

Mutation(REST でいうところの POST PUT DELETE を定義)

type Mutationの中にメソッド書く感じ
今回は Anime を delete するメソッドと Anime の title を更新するメソッドを追加

const typeDefs = gql`
  # ↑のコードの続き

  # mutation実行時用のschemaを作る
  type AnimeUpdateResponse {
    success: Boolean!
    message: String
    anime: [Anime]
  }

  type Mutation {
    deleteAnime(animeId: ID!): AnimeUpdateResponse
    updateTitle(animeId: ID!, title: string!): AnimeUpdateResponse
  }
`;
Query の resolver の定義

今回の場合、Query で定義した animes と anime メソッドの処理内容

module.exports = {
  Query: {
    animes: async (_, __, { dataSources }) =>
      await dataSources.animeAPI.getAllAnimes(),
    anime: async (_, { id }, { dataSources }) =>
      await dataSources.animeAPI.getAnimeById({ animeId: id }),
  },
};

dataSources.animeAPIが DB とのやり取りする adapter 的な感じ

こんな graphql がかけるようになる
GetAnimes は任意のクエリ名。

query GetAnimes {
  animes() {
    id
    title
    charactor {
      name
      description
    }
  }
}

これはこんな感じのレスポンスを返してくれる
(イメージです。現実には違うかもしれません)

{
  "data": {
    "animes": {
      "anime": [
        {
          "id": "1",
          "charactor": [
            {
              "name": "高須 竜児",
              "description": "目つきが悪い。家事がうまい。"
            },
            {
              "name": "逢坂 大河",
              "description": "元祖ツンデレ"
            }
          ]
        }
      ]
    }
  }
}

必要なカラムだけ指定すれば良きなの、とても便利ですよねぇ

Mutation の resolver の定義

今回の場合、anime の update と delete
面倒なので delete のみ

module.exports = {
  // Query: {
  // ...
  // },
  Mutation: {
    deleteAnime: async (_, { id }, { dataSources }) => {
      const result = await dataSources.animeAPI.delete({ id });
      // AnimeUpdateResponseに合わせる
      if (!result)
        return {
          success: false,
          message: "faild delete anime",
        };

      const animes = await dataSources.animeAPI.getAllAnimes();
      return {
        success: true,
        message: "success delete anime",
        animes,
      };
    },
  },
};

こんな graphql がかける

query DeleteAnimes {
  deleteAnime(id: 1) {
    success
    message
    animes {
      id
    }
  }
}

apollo server の起動

const { ApolloServer } = require("apollo-server");
const typeDefs = require("./schema");
const { createStore } = require("./utils");
const resolvers = require("./resolvers");

// DBのコネクト
const store = createStore();

// DBのadapter的な
const AnimeAPI = require("./datasources/anime");

const server = new ApolloServer({
  typeDefs,
  resolvers,
  dataSources: () => ({
    animeAPI: new AnimeAPI({ store }),
  }),
});

server.listen().then(({ url }) => {
  console.log(`? Server ready at ${url}`);
});

クライアントサイド

チュートリアルが React なので React で

ApolloClient の import

ApolloClient は ApolloProvider に渡す

import { ApolloClient } from "apollo-client";
import { InMemoryCache, NormalizedCacheObject } from "apollo-cache-inmemory";
import { HttpLink } from "apollo-link-http";
import { ApolloProvider } from "@apollo/react-hooks";
import React from "react";
import ReactDOM from "react-dom";
import Pages from "./pages";

const cache = new InMemoryCache();
const link = new HttpLink({
  uri: "http://localhost:4000/",
});

const client: ApolloClient<NormalizedCacheObject> = new ApolloClient({
  cache,
  link,
});

ReactDOM.render(
  <ApolloProvider client={client}>
    <Pages />
  </ApolloProvider>,
  document.getElementById("root")
);

GraphQL の実行

hooks(useQuery, useMutation) を使って grapql 実行する

import React from "react";
import { useQuery } from "@apollo/react-hooks";
import gql from "graphql-tag";

export const GET_ANIMES = gql`
  query GetAnimes {
    animes() {
      id
      title
      charactor {
        name
        description
      }
    }
  }
`;

export const Animes: React.FC = () => {
  // GET_ANIMESで定義したqueryを実行する
  // <GetAnimes>はdataの型(apolloで自動生成される)
  const { data } = useQuery<GetAnimes>(GET_ANIMES);

  return (
    <Div>
      {data.animes.map((anime) => (
        <AnimeList title={anime.title} />
      ))}
    </Div>
  );
};

所感

大元のスキーマや Query、Mutation さえサーバサイド側で決めとけば
あとはよしなにクライアントサイド側で好きなスキーマで Query や Mutation かけるのは便利ぃ

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

React npm ERR! 解消メモ

はじめに

暑くなってきて季節はもう夏ですね。
そんな暑い中エラーが出ると汗がだらだら。自分の代謝を恨みます。
就職を目指す駆け出しエンジニアの記事ですが、見てくださると嬉しいです!

npm ERR!

React学習途中、npm startを実行するとnpm ERR!が吐かれました。
スクリーンショット 2020-07-07 16.55.38.png

解消までに試したこと

To fix the dependency tree, try following the steps below in the exact orderに従ってみる

解決のための手順を示してくれているので、とりあえず1から4まで実行してみました。
1.package-lock.jsonをprojectフォルダーから消去
2.同じくnode-modulesも消去
3.package.jsonのdevDependenciesのjestを消去
4.パッケージマネージャーを基にnpm install

解決されませんでした。

jest??

ここで、少しじっくりみるとこの部分が気になりました
スクリーンショット 2020-07-07 17.14.02.png
jestがエラーを起こしていそうですね。
( jestはテストに利用していました。)
スクリーンショット 2020-07-07 17.22.03.png
どうやらcreate-react-appを実行した際に、既にnode-modulesのなかにjestがインストールされており、手動でinstallしたjestとバージョン違いが発生していたのかもしれません。
package.jsonからjestとbabel-jestを消去して、node-modulesも消去後もう一度npm installしてみます。

npm startが通りました
スクリーンショット 2020-07-07 17.27.42.png

まとめ

早く解決できて良かった!!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

SPA(シングルページアプリケーション)って何者

はじめに

以前React.jsで開発していた際に、SPAについて調べる機会がありましたので、記載していきます。

SPAとは

「単一ページでアプリケーションを構成すること」
なんだかよくわかりませんね。。。。

まずは従来のアプリケーションとSPAを比較してみましょう。

◇従来のアプリケーション
image.png
 1.ユーザ操作
 2.サーバーにリクエスト
 3.サーバーでWEBページを生成
 4.クライアント側へWEBページを送信
 5.サーバーから受け取ったWEBページを描画

特徴
ユーザがリクエストする度にWEBページ全てが読み込まれることです。

◇SPA
image.png
 1.初期ページ読み込み(初期描画)
 2.ユーザ操作
 3.サーバーにリクエスト
 4.サーバーからクライアント側へ差分データを送信
 5.差分のみを更新

特徴
最初のリクエストのみWEBページ全体を読み込む
その後は差分データ(JSONなど)を受け取りJavaScriptで必要な場所だけを更新する
※従来のものと違い、毎回ページ全体の更新をする必要がなくなる

要するにSPAでは、ページ全体をロードするのは初回のみで
それ以降は、JavaScriptで差分のみを更新するということ。

これが「単一ページでアプリケーションを構成すること」とどうつながるのかというと、
一つのHTMLに対してJavaScriptを用いて更新しているというのがポイントです。

※おまけ
 SPAを作成できるフレームワークとして「React」「Vue」などがあります。
 これらは「仮想DOM」を用いて差分更新を実現しています。よければ調べてみてください。

SPAのメリット/デメリット

◇メリット
・画面全体のロードが最初の描画のみなので、通信負荷や通信容量が削減されて画面表示の高速化につながる
・画面を表示したまま、コンテンツの変更が可能になる
 (更新対象のみを変更するので「待ち」ストレスが無くなる)
・サーバー側でWEBページを生成する必要がなくなり、クライアント側とサーバー側が疎結合になる

◇デメリット
・初期ページを読み込むのに時間がかかる
  JavaScriptの記述量が増えるため、初期描画に時間がかかる
・開発の複雑化
  表示側の多くをJavaScriptで制御する必要があるため  

以前感じていた疑問

SPAとして作ったアプリケーションでもボタン押下等のアクション後にURLが変更され、
画面遷移しているのではと思ったことはないでしょうか。

あれは動的にURLをJavaScriptで変更し、画面の一部を更新しているだけで
擬似的な画面遷移を実現しているのです。
(ユーザ目線では画面遷移しているように見える。)

例として簡単にあげます
Vue.jsでは「vue-router」を使用して、動的にURLを変更しています。
(一部抜粋)

app.vue
<template>
  <div>
    <p>テスト</p>
    <router-view/>
  </div>
</template>

「router-view」と記載されている箇所のみがURLによって
動的に「component」(画面のパーツのようなもの)を切り替えています。

なので実際に画面遷移をしているのではなく、画面の一部がURLによって更新されているということです。
(ちょっと長くなってしまいそうなのでこの辺にさせていただきます。)

まとめ

SPAはユーザへのストレスを減らし、UXをより良いものにしてくれると思います。
そのためにもちゃんと理解をして実装をする必要があります。

ここまでずっとSPAを推しましたが、なんとなくSPAを選んだではダメです。
一つの手段にすぎないため、自分の知識を深め最適かどうかを判断することも重要です。
(自分にも言い聞かせてます。。。。。。。。)

参考文献

参考にさせていただきました。
【qiita】
https://qiita.com/takanorip/items/82f0c70ebc81e9246c7a

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

SPA(シングルページアプリケーション)っていったいなんだ

はじめに

以前React.jsで開発していた際に、SPAについて調べる機会がありましたので、記載していきます。

SPAとは

「単一ページでアプリケーションを構成すること」
なんだかよくわかりませんね。。。。

まずは従来のアプリケーションとSPAを比較してみましょう。

◇従来のアプリケーション
image.png
 1.ユーザ操作
 2.サーバーにリクエスト
 3.サーバーでWEBページを生成
 4.クライアント側へWEBページを送信
 5.サーバーから受け取ったWEBページを描画

特徴
ユーザがリクエストする度にWEBページ全てが読み込まれることです。

◇SPA
image.png
 1.初期ページ読み込み(初期描画)
 2.ユーザ操作
 3.サーバーにリクエスト
 4.サーバーからクライアント側へ差分データを送信
 5.差分のみを更新

特徴
最初のリクエストのみWEBページ全体を読み込む
その後は差分データ(JSONなど)を受け取りJavaScriptで必要な場所だけを更新する
※従来のものと違い、毎回ページ全体の更新をする必要がなくなる

要するにSPAでは、ページ全体をロードするのは初回のみで
それ以降は、JavaScriptで差分のみを更新するということ。

これが「単一ページでアプリケーションを構成すること」とどうつながるのかというと、
一つのHTMLに対してJavaScriptを用いて更新しているというのがポイントです。

※おまけ
 SPAを作成できるフレームワークとして「React」「Vue」などがあります。
 これらは「仮想DOM」を用いて差分更新を実現しています。よければ調べてみてください。

SPAのメリット/デメリット

◇メリット
・画面全体のロードが最初の描画のみなので、通信負荷や通信容量が削減されて画面表示の高速化につながる
・画面を表示したまま、コンテンツの変更が可能になる
 (更新対象のみを変更するので「待ち」ストレスが無くなる)
・サーバー側でWEBページを生成する必要がなくなり、クライアント側とサーバー側が疎結合になる

◇デメリット
・初期ページを読み込むのに時間がかかる
  JavaScriptの記述量が増えるため、初期描画に時間がかかる
・開発の複雑化
  表示側の多くをJavaScriptで制御する必要があるため  

以前感じていた疑問

SPAとして作ったアプリケーションでもボタン押下等のアクション後にURLが変更され、
画面遷移しているのではと思ったことはないでしょうか。

あれは動的にURLをJavaScriptで変更し、画面の一部を更新しているだけで
擬似的な画面遷移を実現しているのです。
(ユーザ目線では画面遷移しているように見える。)

例として簡単にあげます
Vue.jsでは「vue-router」を使用して、動的にURLを変更しています。
(一部抜粋)

app.vue
<template>
  <div>
    <p>テスト</p>
    <router-view/>
  </div>
</template>

「router-view」と記載されている箇所のみがURLによって
動的に「component」(画面のパーツのようなもの)を切り替えています。

なので実際に画面遷移をしているのではなく、画面の一部がURLによって更新されているということです。
(ちょっと長くなってしまいそうなのでこの辺にさせていただきます。)

まとめ

SPAはユーザへのストレスを減らし、UXをより良いものにしてくれると思います。
そのためにもちゃんと理解をして実装をする必要があります。

ここまでずっとSPAを推しましたが、なんとなくSPAを選んだではダメです。
一つの手段にすぎないため、自分の知識を深め最適かどうかを判断することも重要です。
(自分にも言い聞かせてます。。。。。。。。)

参考文献

参考にさせていただきました。
【qiita】
https://qiita.com/takanorip/items/82f0c70ebc81e9246c7a

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む