フルテキストのWebアプリケーションをnextjsと

38182 ワード

フルテキストのWebアプリケーションをnextjsと


reactjsでフロントエンドアプリケーションを開発することについて話すとき、我々は3つの主要なオプションを見つけることができます.CRA これは、単一のページのWebアプリケーションを構築するが、CEOの位置決めに苦労している.Gatsby これは、優れたパフォーマンスと静的サイト生成に焦点を当て、クールなCEOとデータのフェッチ.それから我々はNextJS , 私の意見では、最近のREACTJS Webアプリケーションを書くための最良の方法は、サーバー側のレンダリングは、クライアント側、クールな組み込みのルーティング、0の設定の哲学、およびnextjs 9以来、このフレームワークは、我々の反応のアプリにバックエンドを提供するために本当に簡単な方法であり、このポストのために使用するつもりですAPIルートを提供しています.このポストでは、APIルートを走らせているGraphSQL APIをどのように実装するかを学びます.

基本的なNextJSアプリ


nextjsが0構成の哲学に焦点を合わせる前に言及したように、我々は簡単にそれを設定することができますnpx create-next-app todo-app 私たちの端末で使用する準備ができている.プロジェクトが設定されたらcd todo-app とタイプyarn dev サーバーを実行し、すべてが実行されていることを確認します.

APIルート


クール!我々は今、我々のNextJS Webアプリをアップロードしている.新しいファイルを作りましょうpages/api/ 呼ばれるgraphql.js 次のコードを追加します.
export default (req, res) => {
  res.statusCode = 200

  res.send("GRAPHQL")
}
そして、我々が行くならばlocalhost:3000/api/graphql 私たちは書かれたテキスト・グラフを見ることができます.簡単に!さあ、GraphSQLを設定しましょう!

グラフィカルセットアップ


インストール


まず、依存関係を追加しましょうapollo-server-micro 書面でyarn add apollo-server-micro

スキーマ


GraphSQLと一緒に動作する必要があるのは、スキーマを記述していることです.これはクエリと突然変異を定義し、データをどのように構成するかを定義します.今のところ、私たちはhello を返します.ルートの上部に次のように加えましょう.
import { ApolloServer, gql } from 'apollo-server-micro'

const schema = gql`
  type Query {
    hello: String!
  }
`;

レゾルバ


私たちはちょうどスキーマを書きましたが、ここでGraphqlは我々のスキーマのリゾルバを必要とします.スキーマの下に、リゾルバを追加しましょう.
const resolvers = {
  Query: {
    hello: (_parent, _args, _context) => "world!"
  }
}

サーバ


では、スキーマとリゾルバを使ってサーバを作りましょう.
const apolloServer = new ApolloServer({
  typeDefs: schema,
  resolvers,
  context: () => {
    return {}
  }
})
このインスタンスを使用すると、すべてのリクエストやレスポンスを処理するためにハンドラにアクセスすることができます.そして、実際にNextJSと一緒に動作しているので、必要としないことを指定する必要がありますbodyParser 我々の要請で.
最後を取り除きましょうexport default そして、次のためにそれを変えてください
const handler = apolloServer.createHandler({ path: "/api/graphql" });

export const config = {
  api: {
    bodyParser: false
  }
};

export default handler;
さて、今ではGraphSQLサーバーの基本的な設定がありますlocalhost:3000/api/graphql そして、我々が今持っているものを見てください!

そして、我々が以下を走らせるならば
query {
    hello
}
我々はResolverから我々の反応を持ちます.

コア


フロントエンドからこのAPIを使用する別のものが必要なので、タイピングで新しいパッケージを追加しましょうyarn add micro-cors , 以下を加えましょう.
import  Cors  from  "micro-cors";  

const cors =  Cors({ 
    allowMethods:  ["POST",  "OPTIONS"]
});  

// Here is how we connect our handler with cors.
export default cors(handler);

KONEXによるPostgresからのデータ。


いくつかの点では、我々のアプリはいくつかのデータを保持するためにデータベースへのアクセスの何らかの種類を必要とするでしょう.このために、いくつかのものを設定する必要がありますので、それをしましょう!最初にKEXとPostgresを加えましょうyarn add knex pg
さあ、ファイルを作りましょうknexfile.js 我々のデータベース構成で.
module.exports = {
  development: {
    client: "postgresql",
    connection: "postgres://postgres@localhost:5432/todo",
    migrations: {
      tableName: "knex_migrations"
    }
  },
};
次に、最初のマイグレーションを作成しましょう.Postgresはどのようにテーブルを作成するかを入力します.yarn run knex migrate:make create_todo フォルダ内migrations 新しいファイルを生成し、オープンしましょう.
exports.up = function(knex) {
  return knex.schema.createTable("todos", function(table) {
    table.increments("id");
    table.string("description", 255).notNullable();
    table.boolean("done").defaultTo(false).notNullable();
  });
};

exports.down = function(knex) {
  return knex.schema.dropTable("todos");
};
そして、私たちのテーブルを構築しましょう!ランyarn run knex migrate:up
ここで定数を作成し、データベース内のデータベースを管理するのに役立ちます.開きましょう/pages/api/graphql.js を追加します.
import knex from "knex";

const db = knex({
  client: "pg",
  connection: "postgres://postgres@localhost:5432/todo"
});

スキーマの更新


クール、我々は今働くことができます.スキーマとリゾルバを変更しないか.
const schema = gql`
  type Query {
    todos: [Todo]!
    todo(id: ID!): Todo
  }

  type Todo {
    id: ID!
    description: String!
    done: Boolean!
  }
`;

const resolvers = {
  Query: {
    todos: (_parent, _args, _context) => {
      return db
        .select("*")
        .from("todos")
        .orderBy("id")
    },
    todo: (_parent, { id }, _context) => {
      return db
        .select("*")
        .from("todos")
        .where({ id })
        .first()
    }
  }
}
そして、我々が現在行くならばlocalhost:3000/api/graphql 我々は最終的に取得し、我々のデータと遊ぶことができるよ!

でもちょっと待ってください.どのようにデータを作成するつもりですか?
まあ
我々がどのように加えることができるかについて見に行きましょうMutation これは我々のデータベース内のデータを作成するのに役立ちます!

データの作成


まず、スキーマ内に新しい型を追加する必要があります.この場合、突然変異の名前を指定する必要がありますcreateTodo そして、私たちが受け取る値の名前と型の括弧の中で、最後に、私たちは突然変異が戻るものを指定する必要がありますTodo 種類
const schema = gql`
  ...

  type Mutation {
    createTodo(description: String!, done: Boolean): Todo
    completeTodo(id: ID!): Todo
  }
`;
現在我々の内部resolvers オブジェクトを追加しますMutation キーとcreateTodo
const resolvers = {
  ...

  Mutation: {
    createTodo: async (_, { description, done }, _c) => {
      return (await db("todos").insert({ description, done }).returning("*"))[0]
    },
    completeTodo: async (_, { id }, _c) => {
      return (await db("todos").select("*").where({ id }).update({ done: true }).returning("*"))[0];
    }
  }
}
そして、これで、我々は作成することができますし、データベースの完全なtodos


しかし、フロントエンドについてはどうですか?

クライアント


今まで我々はAPIルートでGraphSQLを統合することによって我々のアプリケーションのサーバー側を構築している、なぜ我々は我々のアプリのクライアント側を統合しないのですか?

依存


GraphSQLに接続するために必要な2つの依存関係を追加することから始めましょうyarn add @apollo/react-hooks apollo-boost

プロバイダ


まず最初に我々のアプリのアポロクライアントを設定しましょう.このためにオープンしましょうpages/_app.js 次の行を追加します.
import '../styles/globals.css'
import { ApolloProvider } from '@apollo/react-hooks';
import ApolloClient, { gql } from 'apollo-boost';


function MyApp({ Component, pageProps }) {
  const client = new ApolloClient({
    uri: "http://localhost:3000/api/graphql"
  })

  return (
    <ApolloProvider client={client}>
      <Component {...pageProps} />
    </ApolloProvider>
  )
}

export default MyApp

クエリ


さあ開けましょうpages/index.js そして、我々が必要とするものを輸入してください
import React, { useState } from 'react';
import { useQuery, useMutation } from "@apollo/react-hooks";
import { gql } from 'apollo-boost';
さて、まず、GraphSQLのプレイグラウンド内で行うように、GraphSQLクエリを宣言する必要があります
const GET_TODOS = gql`
  query {
    todos {
      id
      description
      done
    }
  }
`
我々のコンポーネントの中で、我々はアプリでそれらをレンダリングするためにクエリとマップを使用するつもりです
export default function Home() {
  const { loading, error, data, refetch } = useQuery(GET_TODOS);

  if(loading) return <p>Loading...</p>
  if(error) return <p>ERROR :(</p>

  return (
    <div>
      <h1>My TODO list</h1>

      {
        data.todos.map((todo) => (
          <div key={todo.id}>
            {todo.description}
            <button
              disabled={todo.done}
            >
              {todo.done ? "Done" : "Complete"}
            </button>
          </div>
        ))
      }

    </div>
  )
}
クール、今我々はブラウザでtodosを見る必要があります.さあ、TODOSを作成する方法を追加しましょう.を始めましょうcreateTodo 突然変異
const CREATE_TODO = gql`
  mutation CreateTodo($description: String!) {
    createTodo(description: $description) {
      id
      description
      done
    }
  }
`
コンポーネントの内部では、状態管理、突然変異、およびフォームを追加して突然変異を実行します.
export default function Home() {
  ...
  const [todo, setTodo] = useState("");
  const [createTodo] = useMutation(CREATE_TODO);

  const saveTodo = async (e) => {
    e.preventDefault();
    await createTodo({variables: { description: todo }});
    refetch();
    setTodo("")
  }

  ...

  return (
    <div>
      <h1>My TODO list</h1>

      <form onSubmit={saveTodo}>
        <label>
          New todo
          <input onChange={e => setTodo(e.target.value)} value={todo} />
        </label>
        <button type="submit">Save</button>
      </form>

      ...

    </div>
  )
}

完成する


かなり簡単!我々を加えない理由completeTodo 突然変異と我々のボタンに機能を追加?
ここでは突然変異宣言を行います.
const COMPLETE_TODO = gql`
  mutation CompleteTodo($id: ID!) {
    completeTodo(id: $id) {
      id
    }
  }
`
コンポーネントの内部には以下があります:
export default function Home() {
  const [todo, setTodo] = useState("");
  const { loading, error, data, refetch } = useQuery(GET_TODOS);
  const [createTodo] = useMutation(CREATE_TODO);
  const [completeTodo] = useMutation(COMPLETE_TODO)

  const saveTodo = async (e) => {
    e.preventDefault();
    await createTodo({variables: { description: todo }});
    refetch();
    setTodo("")
  }

  const onComplete = async (id) => {
    await completeTodo({variables: { id }});
    refetch();
  }


  if(loading) return <p>Loading...</p>
  if(error) return <p>ERROR :(</p>

  return (
    <div>
      <h1>My TODO list</h1>

      <form onSubmit={saveTodo}>
        <label>
          New todo
          <input onChange={e => setTodo(e.target.value)} value={todo} />
        </label>
        <button type="submit">Save</button>
      </form>

      {
        data.todos.map((todo) => (
          <div key={todo.id}>
            {todo.description}
            <button
              disabled={todo.done}
              onClick={() => onComplete(todo.id)}
            >
              {todo.done ? "Done" : "Complete"}
            </button>
          </div>
        ))
      }

    </div>
  )
}
そして今我々は我々のアプリに取り組んで見ることができる我々のブラウザに行く場合!

結論


Graphqlは、過去数年間で多く成長しているので、nextjsを持っている技術です.そして今、我々は我々のNextJSアプリでAPIルートを持つことができます我々は、楽しいスタックを構築し、モノリスとして完全なスタックのWebアプリケーションを持つことができるように、それらを統合することができますが、サーバーなしで実行することができますて🤔?
写真でAlina Grubnyak on Unsplash