20210110のReactに関する記事は15件です。

React RouterでPrivate RouteをTSで実装する

React RouterのPrivate Route公式サンプルをTypeScriptで記述したバージョンです。

一部は直感的に行かず、React RouterのAPIの構造等を把握する必要がありました。

App.tsx
import React, { useContext, createContext, useState } from 'react';
import './App.css';

import {
  BrowserRouter as Router,
  Switch,
  Route,
  Link,
  Redirect,
  useHistory,
  useLocation,
  RouteProps,
} from 'react-router-dom';

// This example has 3 pages: a public page, a protected
// page, and a login screen. In order to see the protected
// page, you must first login. Pretty standard stuff.
//
// First, visit the public page. Then, visit the protected
// page. You're not yet logged in, so you are redirected
// to the login page. After you login, you are redirected
// back to the protected page.
//
// Notice the URL change each time. If you click the back
// button at this point, would you expect to go back to the
// login page? No! You're already logged in. Try it out,
// and you'll see you go back to the page you visited
// just *before* logging in, the public page.

export default function App() {
  return (
    <ProvideAuth>
      <Router>
        <div>
          <AuthButton />

          <ul>
            <li>
              <Link to="/public">Public Page</Link>
            </li>
            <li>
              <Link to="/protected">Protected Page</Link>
            </li>
          </ul>

          <Switch>
            <Route path="/public">
              <PublicPage />
            </Route>
            <Route path="/login">
              <LoginPage />
            </Route>
            <PrivateRoute path="/protected">
              <ProtectedPage />
            </PrivateRoute>
          </Switch>
        </div>
      </Router>
    </ProvideAuth>
  );
}

const fakeAuth = {
  isAuthenticated: false,
  signin(cb: () => void) {
    fakeAuth.isAuthenticated = true;
    setTimeout(cb, 100); // fake async
  },
  signout(cb: () => void) {
    fakeAuth.isAuthenticated = false;
    setTimeout(cb, 100);
  },
};

/** For more details on
 * `authContext`, `ProvideAuth`, `useAuth` and `useProvideAuth`
 * refer to: https://usehooks.com/useAuth/
 */

type DefaultAuth = {
  user: string | null;
  signin: ((cb: () => void) => void) | null;
  signout: ((cb: () => void) => void) | null;
};

const defaultAuth = { user: null, signin: null, signout: null };

const authContext = createContext<DefaultAuth>(defaultAuth);

function ProvideAuth({ children }: { children: React.ReactNode }) {
  const auth = useProvideAuth();
  return <authContext.Provider value={auth}>{children}</authContext.Provider>;
}

function useAuth() {
  return useContext(authContext);
}

function useProvideAuth() {
  const [user, setUser] = useState<string | null>(null);

  const signin = (cb: () => void) => {
    return fakeAuth.signin(() => {
      setUser('user');
      cb();
    });
  };

  const signout = (cb: () => void) => {
    return fakeAuth.signout(() => {
      setUser(null);
      cb();
    });
  };

  return {
    user,
    signin,
    signout,
  };
}

function AuthButton() {
  let history = useHistory();
  let auth = useAuth();

  return auth.user ? (
    <p>
      Welcome!{' '}
      <button
        onClick={() => {
          if (!auth.signout) return;
          auth.signout(() => history.push('/'));
        }}
      >
        Sign out
      </button>
    </p>
  ) : (
    <p>You are not logged in.</p>
  );
}

// A wrapper for <Route> that redirects to the login
// screen if you're not yet authenticated.
function PrivateRoute({ children, ...rest }: RouteProps & { children: React.ReactNode }) {
  let auth = useAuth();
  return (
    <Route
      {...rest}
      render={({ location }) =>
        auth.user ? children : <Redirect to={{ pathname: '/login', state: { from: location } }} />
      }
    />
  );
}

function PublicPage() {
  return <h3>Public</h3>;
}

function ProtectedPage() {
  return <h3>Protected</h3>;
}


type State = {
  from: {
    pathname: string;
    search: string;
    hash: string;
    state: string | null;
    key: string;
  };
};

function LoginPage() {
  let history = useHistory();
  let location = useLocation();
  let auth = useAuth();

  let { from } = (location.state as State) || { from: { pathname: '/' } };
  let login = () => {
    if (!auth.signin) return;
    auth.signin(() => {
      history.replace(from);
    });
  };

  return (
    <div>
      <p>You must log in to view the page at {from.pathname}</p>
      <button onClick={login}>Log in</button>
    </div>
  );
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【2021年】React / TypeScript使用のためのDocker + Vagrant環境を構築する

目的

下記の技術を使ったフロントのコンポーネントの作成を行うための環境構築を行いました。

  • React
  • TypeScript

目的は上記の利用ですが、本記事としてはReact/TypeScriptを触れることはありませんので、Node.jsを利用する環境の構築には利用が可能かと思います。

DockerだけでなくVagrantを採用している理由としては、自分の開発環境がmacであり、
参考記事に記載の理由で動作が遅いことを解消するためです。

参考記事

DXを大幅に低下させるDocker for Macを捨ててMac最速のDocker環境を手に入れる

前準備/筆者の環境

参考記事に記載のVagrantやMutagenのインストールが必要です。
筆者の環境としては下記となります。

  • MacOS 11.1
  • Vagrant 2.2.7
  • Mutagen 0.11.8

作成するもの

下記の4つのファイルを作成します。
それぞれのファイルは同一のディレクトリの配置でOKです。

  • Vagrantfile
  • mutagen.yml
  • Dockerfile
  • docker-compose.yml

起動をする際にはvagrantから立ち上げて、仮想マシンの中にsshしてdockerの立ち上げとなります。

Vagrantfile

作成する仮想マシンの構成の記載がされているファイルです。

Vagrant.configure('2') do |config|
  config.vm.box = 'ubuntu/focal64'

  config.vm.hostname = 'frontcomponent'

  config.vm.network :private_network, ip: '192.168.60.10'
  config.vm.network 'forwarded_port', guest: 8000, host: 8000

  config.vm.provider :virtualbox do |vb|
    vb.gui = false
    vb.cpus = 2
    vb.memory = 4096
    vb.customize ['modifyvm', :id, '--natdnsproxy1', 'off']
    vb.customize ['modifyvm', :id, '--natdnshostresolver1', 'off']
  end

  config.disksize.size = '15GB'
  config.mutagen.orchestrate = true

  config.vm.synced_folder './', '/home/vagrant/front_component', type: "rsync",
    rsync_auto: true,
    rsync__exclude: ['.git/', 'log/', 'tmp/']

  config.vm.provision 'shell', inline: <<-SHELL
    echo "fs.inotify.max_user_watches = 65536" >> /etc/sysctl.conf && sysctl -p

    curl -fsSL https://get.docker.com -o get-docker.sh
    sh get-docker.sh
    usermod -aG docker vagrant

    # dockerを更新する場合にはverを調整すること
    curl -L "https://github.com/docker/compose/releases/download/1.27.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
    chmod +x /usr/local/bin/docker-compose
  SHELL
end

portの設定は今後に自分が利用する環境に合わせて設定しています。
あと、vm.providerなどスペックの設定に関しては利用しているPCなどでチューニングすると良いかと思います。

他には自分がこれまでにハマったポイントや参考記事を拝見した後に追加した点としては下記となります。利用する場合には注意してください。

hostname

"_"の利用ができないようです。
サービス名などを入れた場合に間違えやすいので注意が必要です。

fs.inotify.max_user_watches

node_modulesなど外部のファイルを引いてくるディレクトリが存在する場合にファイル数が多くなりすぎて、エラーとなることがあります。その場合にはファイルのマウントから除外する方が正しいかとは思いますが、typescriptの方定義ファイルなどローカル上にマウントされてないとコード編集時にnode_modules内の型定義ファイルが見つからず加えました。

良い知見をお持ちの方がいたら意見を伺いたいです

mutagen.yml

sync:
  app:
    mode: "two-way-resolved"
    alpha: "./"
    beta: "frontcomponent:/home/vagrant/front_component"
    ignore:
      vcs: true
      paths:
        - "/log"
        - "/tmp"

vagrantとのファイル同期にmutagenを利用します。
詳細に関しては記事にまとめるほどには理解が追いついていませんので、参考記事を参照していただけると良いかと思います。

Dockerfile

Docker Hubに置いてあるDockerのイメージファイルをベースとして、
今回利用するコンテナのベースイメージを作成します。

FROM node:15.5.1

ENV LANG C.UTF-8
ENV WORKSPACE=/var/www/front_component/

RUN curl -sL https://deb.nodesource.com/setup_15.x | bash - 
RUN apt install -y less build-essential nodejs
RUN apt install -y vim less
RUN npm install n -g
RUN n 14.15.4

WORKDIR $WORKSPACE

Docker Hubに置いてあるイメージを元に、今回の環境構築用のベースイメージを作成します。

今回は、今後にreact/typescriptを入れていくことを想定しているのでnodeのイメージをして、npmのインストールをしています。

docker-compose.yml

version: '3.7'

services:
  front:
    build: .
    image: front:1.0
    container_name: front
    tty: true
    stdin_open: true
    ports:
      - "8000:8000"
    environment: {}
    volumes:
      - .:/var/www/front_component
    # command: "bash -c 'npm i && npm run watch'"

コンテナ作成用の設定になります。
コメントアウト部分は今後にreact/typescriptを入れた後に利用する想定ですが、
ここまでの環境構築では利用をしないのでコメントアウトとしています。

vagrantおよびdockerの立ち上げ

立ち上げ方

# 先にcdコマンドで上記で作成したファイルの置いてあるディレクトリに移動する

vagrant up  # vagrantの立ち上げ
vagrant ssh # vagrant内へsshでアクセス
cd front_component   # vagrantにローカルのファイルをマウントしているディレクトリに移動
docker-compose up -d # dockerの立ち上げ

以上で環境の立ち上げ完了です。

上記のコマンドと合わせて、自分がよく使うコマンドを記載しておきます。
簡易的な説明のみなので、ちゃんと使う場合には調べて使ってください

vagrant系

vagrant up      # vagrantの立ち上げ
vagrant ssh     # 立ち上げたvagrantにsshアクセスする
vagrant halt    # vagrantの終了
vagrant destroy # vagrantで作成した仮装イメージごと削除

docker系

docker ps # 起動中のdockerのimageを確認する
docker exec -ti <コンテナ名> /bin/bash # コンテナの中にssh的にアクセスする
docker attach <コンテナ名> # コンテナで起動中のプロセスを表示する
docker logs <コンテナ名>   # 強制終了したコンテナの終了時のログなどを見るのに利用する

初投稿ε('∞'*)フゥー

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

[React] やっぱりReduxもMobXも気に入らないのでVueのVuexを参考に状態管理ライブラリを自作してみた

はじめに

アウトプットをこちらに載せておきます

Github
NPM
デモ

よろしければTwitterを始めたのでフォローとGithubに☆をしてくださると励みになります!

経緯

Reactを始めてまず思ったのが状態管理ライブラリ多すぎ、非同期するのに追加のミドルウェアもいるの??
という印象でした。

Vueの場合はほとんどの場合Vuexを選択することになるし、TypeScriptとの相性は悪いものの、Vuexは非同期を前提としているのでそれだけで完結できるので余計な気はあまり使わないような気がします。
Reactの場合はどうでしょう? 
まず事実上のデファクトスタンダードのReduxをはじめとして、Flux、Mobx、Recoilなど、無数に存在します。
非同期をするなら、redux-saga、redux-thunkなどこれまたミドルウェアもたくさん存在します。

Vuexと比べたReduxの印象は「記述量多すぎてめんどくさい」、「余計な記述が増えてかえって可読性悪くならないか?」という印象でした。TypeScriptとの相性も良くないし、switch文で分岐するのもなんだかなーという感じ。
Redux ToolkotやRecoilを使えば上記のデメリットを解消できますが、私はオブジェクト指向やDIを多用するので引っかかるものは感じていました。

そこで次の選択肢として、MobXが上がりました。MobXはオブジェクト指向をサポートし、まさに魔法のようにリアクティブを実現してくれます。
ルールの強要もほとんどないので本当に自由に実装できます。
最初はこれだ!と思ってうれしく使ってました。
ただ、これはこれでブラックボックスを作りやすくなるので、デバッグがしにくかったり複数人で利用すると秩序が保たれない可能性が出てきます。(本当にわがままなやつですよね)

要するに、オブジェクト指向で、記述が楽で、かっちりしたルールのある状態管理ライブラリが欲しいんです!
→じゃあ自作するかという流れでした。

そんなこんなで、VuexやElmの良い部分を取り込んで単一方向データフローでオブジェクト指向で記述できる状態管理ライブラリを作成しました。
規模がそこそこ小さい場合や、迅速に単一データフローのアプリを作りたい場合は自分でも積極的に使っていきたいです。

成果物の紹介

早速ですが紹介します。

ライブラリのルール

relux.png

  • 状態は常に読み取り専用にしましょう
  • 状態を変更するにはActionをDispatchしましょう
  • ディスパッチされたActionを処理するすべてのMutationは、Actionに期待される変更と組み合わされた古い状態を反映する新しい状態を作成します
  • UIは新しい状態を使用して表示をレンダリングします

※ここでのActionの概念はVuexを参考にしたためReduxとは少し違います

実装

例としてフィボナッチ数列でカウントアップするカウンタを実装してみます。

デモ

インストール

yarn add relux.js react-relux

または

npm install --save relux.js react-relux

まずは管理したい状態の型を作成

export interface FibState {
    n: number;
    count: number;
}

フィボナッチ数を生成するクラスを作成

export class FibonacciService {
    public fib(n: number) {
        if (n < 3) return 1;
        return this.fib(n - 1) + this.fib(n - 2);
    }
}

状態を更新するためのActionを作成

Actionを作成するにはAction<TState, Tpayload> クラスを継承する必要があります. クラス名がアクション名となります. TStateには状態の型, TPayoadにはペーロードの型を指定してください。 ActionをDispatchした際、invokeメソッドがコールされます.

クラス名がアクション名となりますが, Webpackや静的サイトジェネレータなどで圧縮されて元のクラス名がわからなくなる場合は, name プロパティを定義することでアクション名を上書きできます.

import { Action, Feature } from "relux.js"
import { FibState } from "./FibState";
import { FibonacciService } from "./FibonacciService";

export class IncrementalFibonacciAction extends Action<FibState, undefined> {
    // コンストラクタ引数の定義
    // デコレーターが使える場合はクラスに@Injectableデコレーターを付与するとこのプロパティを定義しなくても自動で解決される
    static parameters = [FibonacciService];
    name = "IncrementalFibonacciAction ";

    constructor(private readonly fibService: FibonacciService) { 
        super();
    }

    public invoke(_: undefined): Feature<FibState> {
        return async ({ dispatch, mutate, state }) => {
            if (state.n < 40 === false) {
                return;
            }

            // ここで非同期処理も可能
            await new Promise(resolve => setTimeout(resolve, 1000));

            const fib = this.fibService.fib(state.n + 1);

            // ここで状態を更新する
            mutate(s => ({
                ...s,
                count: fib,
                n: s.n + 1
            }));
        };
    }
}

Storeインスタンスの作成

1つの状態ツリーを機能ごとに複数に分割することができます。複数のアクションと1つの状態の組み合わせは、スライスと呼ばれます。

import { createStore } from "relux.js";
import { IncrementalFibonacciAction } from "./IncrementalFibonacciAction";
import { FibonacciService } from "./FibonacciService";

export const store = createStore({
    slices: {
        counter: {
            ...
        },
        fib: {
            name: "fib",
            actions: [
                // 先ほど定義したAction
                IncrementalFibonacciAction,
            ],
            // 初期値
            state: {
                n: 0,
                count: 0
            }
        }
    },
    // DIするサービスを登録
    services: [
        // フィボナッチ数を生成するクラス
        FibonacciService
    ]
});

// slice.stateの型を集約して1つの状態ツリーの型を生成します
export type RootState = ReturnType<typeof store.getState>;

React Component

useObserverでほしい状態を取り出して、useDispatchの戻り値を利用してActionをDispatchしています。

import { Provider, useDispatch, useObserver } from "react-relux";
import { store, RootState } from "./store";
import { IncrementalFibonacciAction} from "./IncrementalFibonacciAction";

export default () => {
    return (
        <Provider store={store}>
            <FibCounter />
        </Provider>
    );
};

function FibCounter() {
    const dispatch= useDispatch();
    const counter = useObserver((s: RootState) => s.fib);

    function increment() {
        dispatch(IncrementalFibonacciAction, undefined)
    }

    return (
        <div>
            <h1>Fibonacci counter</h1>
            <button onClick={increment}>Compute</button>
            <p>Compute Fibonacci number when N {"<"} 40</p>
            <div>Fib: {counter.count}</div>
            <div>N: {counter.n}</div>
        </div>
    );
}

おわりに

もしも気に入れば、使っていただけたらなと思います!

Github
NPM
デモ

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

[React] ReduxもMobXも合わなかったのでVueのVuexを参考に状態管理ライブラリを自作してみた

はじめに

アウトプットをこちらに載せておきます

Github
NPM
デモ

よろしければTwitterを始めたのでフォローとGithubに☆をしてくださると励みになります!

経緯

Reactを始めてまず思ったのが状態管理ライブラリ多すぎ、非同期するのに追加のミドルウェアもいるの??
という印象でした。

Vueの場合はほとんどの場合Vuexを選択することになるし、TypeScriptとの相性は悪いものの、Vuexは非同期を前提としているのでそれだけで完結できるので余計な気はあまり使わないような気がします。
Reactの場合はどうでしょう? 
まず事実上のデファクトスタンダードのReduxをはじめとして、Flux、Mobx、Recoilなど、無数に存在します。
非同期をするなら、redux-saga、redux-thunkなどこれまたミドルウェアもたくさん存在します。

Vuexと比べたReduxの印象は「記述量多すぎてめんどくさい」、「余計な記述が増えてかえって可読性悪くならないか?」という印象でした。TypeScriptとの相性も良くないし、switch文で分岐するのもなんだかなーという感じ。
Redux ToolkotやRecoilを使えば上記のデメリットを解消できますが、私はオブジェクト指向やDIを多用するので引っかかるものは感じていました。

そこで次の選択肢として、MobXが上がりました。MobXはオブジェクト指向をサポートし、まさに魔法のようにリアクティブを実現してくれます。
ルールの強要もほとんどないので本当に自由に実装できます。
最初はこれだ!と思ってうれしく使ってました。
ただ、これはこれでブラックボックスを作りやすくなるので、デバッグがしにくかったり複数人で利用すると秩序が保たれない可能性が出てきます。(本当にわがままなやつですよね)

要するに、オブジェクト指向で、記述が楽で、かっちりしたルールのある状態管理ライブラリが欲しいんです!
→じゃあ自作するかという流れでした。

そんなこんなで、VuexやElmの良い部分を取り込んで単一方向データフローでオブジェクト指向で記述できる状態管理ライブラリを作成しました。
規模がそこそこ小さい場合や、迅速に単一データフローのアプリを作りたい場合は自分でも積極的に使っていきたいです。

成果物の紹介

早速ですが紹介します。

ライブラリのルール

relux.png

  • 状態は常に読み取り専用にしましょう
  • 状態を変更するにはActionをDispatchしましょう
  • ディスパッチされたActionを処理するすべてのMutationは、Actionに期待される変更と組み合わされた古い状態を反映する新しい状態を作成します
  • UIは新しい状態を使用して表示をレンダリングします

※ここでのActionの概念はVuexを参考にしたためReduxとは少し違います

実装

例としてフィボナッチ数列でカウントアップするカウンタを実装してみます。

デモ

インストール

yarn add relux.js react-relux

または

npm install --save relux.js react-relux

まずは管理したい状態の型を作成

export interface FibState {
    n: number;
    count: number;
}

フィボナッチ数を生成するクラスを作成

export class FibonacciService {
    public fib(n: number) {
        if (n < 3) return 1;
        return this.fib(n - 1) + this.fib(n - 2);
    }
}

状態を更新するためのActionを作成

Actionを作成するにはAction<TState, Tpayload> クラスを継承する必要があります. クラス名がアクション名となります. TStateには状態の型, TPayoadにはペーロードの型を指定してください。 ActionをDispatchした際、invokeメソッドがコールされます.

クラス名がアクション名となりますが, Webpackや静的サイトジェネレータなどで圧縮されて元のクラス名がわからなくなる場合は, name プロパティを定義することでアクション名を上書きできます.

import { Action, Feature } from "relux.js"
import { FibState } from "./FibState";
import { FibonacciService } from "./FibonacciService";

export class IncrementalFibonacciAction extends Action<FibState, undefined> {
    // コンストラクタ引数の定義
    // デコレーターが使える場合はクラスに@Injectableデコレーターを付与するとこのプロパティを定義しなくても自動で解決される
    static parameters = [FibonacciService];
    name = "IncrementalFibonacciAction ";

    constructor(private readonly fibService: FibonacciService) { 
        super();
    }

    public invoke(_: undefined): Feature<FibState> {
        return async ({ dispatch, mutate, state }) => {
            if (state.n < 40 === false) {
                return;
            }

            // ここで非同期処理も可能
            await new Promise(resolve => setTimeout(resolve, 1000));

            const fib = this.fibService.fib(state.n + 1);

            // ここで状態を更新する
            mutate(s => ({
                ...s,
                count: fib,
                n: s.n + 1
            }));
        };
    }
}

Storeインスタンスの作成

1つの状態ツリーを機能ごとに複数に分割することができます。複数のアクションと1つの状態の組み合わせは、スライスと呼ばれます。

import { createStore } from "relux.js";
import { IncrementalFibonacciAction } from "./IncrementalFibonacciAction";
import { FibonacciService } from "./FibonacciService";

export const store = createStore({
    slices: {
        counter: {
            ...
        },
        fib: {
            name: "fib",
            actions: [
                // 先ほど定義したAction
                IncrementalFibonacciAction,
            ],
            // 初期値
            state: {
                n: 0,
                count: 0
            }
        }
    },
    // DIするサービスを登録
    services: [
        // フィボナッチ数を生成するクラス
        FibonacciService
    ]
});

// slice.stateの型を集約して1つの状態ツリーの型を生成します
export type RootState = ReturnType<typeof store.getState>;

React Component

useObserverでほしい状態を取り出して、useDispatchの戻り値を利用してActionをDispatchしています。

import { Provider, useDispatch, useObserver } from "react-relux";
import { store, RootState } from "./store";
import { IncrementalFibonacciAction} from "./IncrementalFibonacciAction";

export default () => {
    return (
        <Provider store={store}>
            <FibCounter />
        </Provider>
    );
};

function FibCounter() {
    const dispatch= useDispatch();
    const counter = useObserver((s: RootState) => s.fib);

    function increment() {
        dispatch(IncrementalFibonacciAction, undefined)
    }

    return (
        <div>
            <h1>Fibonacci counter</h1>
            <button onClick={increment}>Compute</button>
            <p>Compute Fibonacci number when N {"<"} 40</p>
            <div>Fib: {counter.count}</div>
            <div>N: {counter.n}</div>
        </div>
    );
}

おわりに

もしも気に入れば、使っていただけたらなと思います!

Github
NPM
デモ

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

[React] ReduxもMobXも合わなかったので状態管理ライブラリを自作してみた話

はじめに

Reactを始めて数か月ですが、状態管理ライブラリの選定に血迷ってしまって、結局自作したというはなしです。

アウトプットをこちらに載せておきます!

Github
NPM
デモ

よろしければ、Twitterを始めたのでフォローと、Githubに☆をしてくださると励みになります!

背景

Reactを始めてまず思ったのが状態管理ライブラリ多すぎ、非同期するのに追加のミドルウェアもいるの??
という印象でした。

Vueの場合はほとんどの場合Vuexを選択することになるし、TypeScriptとの相性は悪いものの、Vuexは非同期を前提としているのでそれだけで完結できるので余計な気はあまり使わないような気がします。
Reactの場合はどうでしょう? 
まず事実上のデファクトスタンダードのReduxをはじめとして、Flux、Mobx、Recoilなど、無数に存在します。
非同期をするなら、redux-saga、redux-thunkなどこれまたミドルウェアもたくさん存在します。

Vuexと比べたReduxの印象は「記述量多すぎてめんどくさい」、「余計な記述が増えてかえって可読性悪くならないか?」という印象でした。TypeScriptとの相性も良くないし、switch文で分岐するのもなんだかなーという感じ。
Redux ToolkotやRecoilを使えば上記のデメリットを解消できますが、私はオブジェクト指向やDIを多用するので引っかかるものは感じていました。

そこで次の選択肢として、MobXが上がりました。MobXはオブジェクト指向をサポートし、まさに魔法のようにリアクティブを実現してくれます。
ルールの強要もほとんどないので本当に自由に実装できます。
最初はこれだ!と思ってうれしく使ってました。
ただ、これはこれでブラックボックスを作りやすくなるので、デバッグがしにくかったり複数人で利用すると秩序が保たれない可能性が出てきます。(本当にわがままなやつですよね)

要するに、オブジェクト指向で、記述が楽で、かっちりしたルールのある状態管理ライブラリが欲しいんです!
→じゃあ自作するかという流れでした。

そんなこんなで、VuexやElmの良い部分を取り込んで単一方向データフローでオブジェクト指向で記述できる状態管理ライブラリを作成しました。
規模がそこそこ小さい場合や、迅速に単一データフローのアプリを作りたい場合は自分でも積極的に使っていきたいです。

成果物の紹介

早速ですが紹介します。

ライブラリのルール

relux.png

  • 状態は常に読み取り専用にしましょう
  • 状態を変更するにはActionをDispatchしましょう
  • ディスパッチされたActionを処理するすべてのMutationは、Actionに期待される変更と組み合わされた古い状態を反映する新しい状態を作成します
  • UIは新しい状態を使用して表示をレンダリングします

※ここでのActionの概念はVuexを参考にしたためReduxとは少し違います

実装

例としてフィボナッチ数列でカウントアップするカウンタを実装してみます。

デモ

インストール

yarn add relux.js react-relux

または

npm install --save relux.js react-relux

まずは管理したい状態の型を作成

export interface FibState {
    n: number;
    count: number;
}

フィボナッチ数を生成するクラスを作成

export class FibonacciService {
    public fib(n: number) {
        if (n < 3) return 1;
        return this.fib(n - 1) + this.fib(n - 2);
    }
}

状態を更新するためのActionを作成

Actionを作成するにはAction<TState, Tpayload> クラスを継承する必要があります. クラス名がアクション名となります. TStateには状態の型, TPayoadにはペーロードの型を指定してください。 ActionをDispatchした際、invokeメソッドがコールされます.

クラス名がアクション名となりますが, Webpackや静的サイトジェネレータなどで圧縮されて元のクラス名がわからなくなる場合は, name プロパティを定義することでアクション名を上書きできます.

import { Action, Feature } from "relux.js"
import { FibState } from "./FibState";
import { FibonacciService } from "./FibonacciService";

export class IncrementalFibonacciAction extends Action<FibState, undefined> {
    // コンストラクタ引数の定義
    // デコレーターが使える場合はクラスに@Injectableデコレーターを付与するとこのプロパティを定義しなくても自動で解決される
    static parameters = [FibonacciService];
    name = "IncrementalFibonacciAction ";

    constructor(private readonly fibService: FibonacciService) { 
        super();
    }

    public invoke(_: undefined): Feature<FibState> {
        return async ({ dispatch, mutate, state }) => {
            if (state.n < 40 === false) {
                return;
            }

            // ここで非同期処理も可能
            await new Promise(resolve => setTimeout(resolve, 1000));

            const fib = this.fibService.fib(state.n + 1);

            // ここで状態を更新する
            mutate(s => ({
                ...s,
                count: fib,
                n: s.n + 1
            }));
        };
    }
}

Storeインスタンスの作成

1つの状態ツリーを機能ごとに複数に分割することができます。複数のアクションと1つの状態の組み合わせは、スライスと呼ばれます。

import { createStore } from "relux.js";
import { IncrementalFibonacciAction } from "./IncrementalFibonacciAction";
import { FibonacciService } from "./FibonacciService";

export const store = createStore({
    slices: {
        counter: {
            ...
        },
        fib: {
            name: "fib",
            actions: [
                // 先ほど定義したAction
                IncrementalFibonacciAction,
            ],
            // 初期値
            state: {
                n: 0,
                count: 0
            }
        }
    },
    // DIするサービスを登録
    services: [
        // フィボナッチ数を生成するクラス
        FibonacciService
    ]
});

// slice.stateの型を集約して1つの状態ツリーの型を生成します
export type RootState = ReturnType<typeof store.getState>;

React Component

useObserverでほしい状態を取り出して、useDispatchの戻り値を利用してActionをDispatchしています。

import { Provider, useDispatch, useObserver } from "react-relux";
import { store, RootState } from "./store";
import { IncrementalFibonacciAction} from "./IncrementalFibonacciAction";

export default () => {
    return (
        <Provider store={store}>
            <FibCounter />
        </Provider>
    );
};

function FibCounter() {
    const dispatch= useDispatch();
    const counter = useObserver((s: RootState) => s.fib);

    function increment() {
        dispatch(IncrementalFibonacciAction, undefined)
    }

    return (
        <div>
            <h1>Fibonacci counter</h1>
            <button onClick={increment}>Compute</button>
            <p>Compute Fibonacci number when N {"<"} 40</p>
            <div>Fib: {counter.count}</div>
            <div>N: {counter.n}</div>
        </div>
    );
}

おわりに

もしも気に入れば、使っていただけたらなと思います!

Github
NPM
デモ

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

Reactでカウントアップ機能を作る

カウントアップ機能を作る

+ボタンを押すと1ずつ数字が増えていくカウントアップ機能をReactでつくる。

stateを定義する

constructor内でプロパティ名がcount、値が0stateを定義する。

constructor(props) {
    super(props);
    this.state = {count:0};
  }

ボタンとつくり、stateを表示

ボタンはbuttonのタグを使ってつくる。そして前述で定義したstatereturn内で表示させる。その際、this.state.countはJavascriptなので、{}で囲む。

render() {
    return (
      <div>
        <h1>{this.state.count}</h1>

        <button>+</button>
      </div>
    );
  }

handleClickを定義

handleClickのメソッドを定義して、statecountの値に1を足す処理を追加する。

handleClick(){
    this.setState({count: this.state.count + 1});
  }

buttonタグにonClickイベントを追加

buttonタグにonClickのイベントを追加して、onClickのイベント時に前述で定義したhandleClickのメソッドが呼び出されるようにする。

<button onClick={()=>{
    this.handleClick()
    }
}>+</button>

最後に

洗練さんでインターン(Progate React)です。
Progate React

GitHubのレポジトリ

最後に
現在ここでインターンしています。
まだまだ駆け出しですが頑張ります!やる気は人一倍です!
洗練

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

Reactでfirebaseのconfig.jsファイルにあるappIdとstorageBucketを隠す方法【備忘録】

初めに

初心者です。
ある日Reactの勉強のためfirebaseを使用し個人をアプリを作成。
知人にレビューしてもらったところappIdとstorageBucketが公開されており隠す必要があると指摘を受けました。
どうやらセキュリティ的にかなりまずいと...

公開しないようにするには

ズバリ環境変数を使用して解決しました。

1 .rootディレクトリ直下に.envファイルを作成

root/
├ src/
 │ └ firebase/
 │   └ config.js/
├ env

2 .envファイルの中身を以下のように記述

create react appの公式サイトを見るとReactで環境変数を作る前はREACT_APP_を変数の頭に記載する必要があるため変数名1つ1つに加える。

.env
REACT_APP_apiKey="AAAAAAAAAAAAAAAAAAAA"
REACT_APP_authDomain= "BBBBBBBBBBBBBB"
REACT_APP_projectId="CCCCCCCCCCCCCCC"
REACT_APP_storageBucket="DDDDDDDDDDDDDD"
REACT_APP_messagingSenderId="EEEEEEEEEEE"
REACT_APP_appId="1:1111111111:web:1111111111111"
REACT_APP_measurementId="FFFFFFFFFFFF"

3 環境変数を使ってconfig.jsファイルappId等を記述する

他のファイルで環境変数を呼び出す際は変数名の前にprocess.env.を加えてあげればいい

.src/firebase/config.js
const firebaseConfig = {
  apiKey: process.env.REACT_APP_apiKey,
  authDomain: process.env.REACT_APP_authDomain,
  projectId: process.env.REACT_APP_projectId,
  storageBucket: process.env.REACT_APP_storageBucket,
  messagingSenderId: process.env.REACT_APP_messagingSenderId,
  appId: process.env.REACT_APP_appId,
  measurementId: process.env.REACT_APP_measurementId
};

export {firebaseConfig};

最後に忘れずに.envファイルを.gitigoreに加えてあげる

.gitignore
/node_modules
/.pnp
.pnp.js
/coverage
/build

# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*
.env

これでGithubに載せた時に環境変数のおかげでappIdとstorageBucketが公開されないようになりましたね!

参考:Create React App
https://create-react-app.dev/docs/adding-custom-environment-variables/#referencing-environment-variables-in-the-html

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

Reactの関数コンポーネントの基本をまとめてみた

(まだ、完全にまとまってません、これから追記していきます)
業務でReactを使って1年以上経ちますが、数ヶ月前から新しく作るコンポーネントは関数コンポーネント+TypeScriptに移行しました。
元々はClassコンポーネントで書いていたのですが、なぜ関数コンポーネントが優れているのかを知っておきたかったのと、現場でベテランエンジニアから学んだ書き方のTipsなどを記事にしようと思います。

関数コンポーネントとは?

Classに比べると簡潔に見通しよく書けるメリットがあったものの、Classの様にStateを持つ事ができなかった。(当たり前ですが、関数は状態を持つことができません。関数の実行が終われば、関数内の変数はスコープから外れ、アクセスできなくなります、クロージャーとかありますが、、)

そこで考案されたのがフックです。フックは、関数コンポーネントの中からReactの機能へ接続(Hooks into)することを実現しました。フックを用いることで、関数コンポーネントにおいてもクラスコンポーネントとほぼ同等の機能を実現することができる様になったわけです。

これによって、関数コンポーネントが主流になったらしいです。

では、フックとは?

フックは、関数コンポーネントに state やライフサイクルといった React の機能を “接続する (hook into)” ための関数です。フックは React をクラスなしに使うための機能ですので、クラス内では機能しません。今すぐに既存のコンポーネントを書き換えることはお勧めしませんが、新しく書くコンポーネントで使いたければフックを利用し始めることができます。
- React公式ドキュメントから抜粋

ですので、私がフロント開発に携わるサービスもClassコンポーネントが残っていて混在してる状態です。

では、基本のフックを見ていきましょう。

・ステートフック useState
その名の通り、state(状態)を持つ事ができる様になります。

最も単純なケースで表示、非表示を切り替えるboolean変数(showMenu)を作りましょう。
お作法として変数を書き換えるメソッド名はset + 変数名です。

const [showMenu, setShowMenu] = useState<boolean>(false);
const toggleVisibility = () => setShowMenu(prev => !prev);

prev => !prevと書いてるのは、現在の状態 => 現在の状態の逆 という事です。

・副作用フック useEffect
Classでいう、ComponentDidMount、ComponentDidUpdateを行う事ができる。
第一引数にcallbackを入れて、第二引数に依存する値の配列を入れる
* 依存する値が変更される度にcallbackが実行される

useEffect(
  () => {
     実行したい処理
  },
  [ 依存する値/state ]
);

・メモ化フック
同じ結果を返す処理に関しては初回のみ処理を実行しておき、2回目以降は前回の処理結果を呼び出すことで毎回同じ処理を実行しなくてよくなります。これはプログラミングではメモ化と呼ばれるテクニックで、それをReact Hooks上で簡単に利用できるのがuseMemoとuseCallbackです。
パフォーマンス向上のためにuseMemo、useCallbackは使われる。
パフォーマンス向上のポイントは 無駄な計算を抑え 、再レンダリングをできるだけ抑える この2つです。

useMemoは、計算結果を記憶し、必要な時だけ再計算することができる機能
useCallbackは、子コンポーネントに渡すコールバック関数を記憶しておく事ができる機能です

まとめ

関数コンポーネントのメリットは、constructor, renderなどが不要で記述量を減らせるからこっちでやるべき。

参考

https://www.to-r.net/media/react-tutorial-hooks-usememo-usecallback/
https://times.hrbrain.co.jp/entry/react-hooks-performance
https://sbfl.net/blog/2019/11/12/react-hooks-introduction/

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

[React] firestoreのデータをaxios取得に書き換える

開発環境

react : 17.0.1
node : 12.18.2
npm : 6.14.5
firebase : 8.2.1
axios : 0.21.1

既存コード

今回はusersコレクションをfirestoreで用意しておき、userのデータをfirestoreから取得し、userのnameを一覧で表示させる実装です。

top.js
import React, { useState, useEffect } from 'react'
import firebase from '../lib/firebase'

const Top = () => {
  const [users, setUsers] = useState([])

  // firestoreからuserのデータを取得する関数
  const getFirestoreUsers = async () => {
    const snapshot = await firebase.firestore().collection('users').get()
    const users = snapshot.docs.map(doc => doc.data())
    setUsers(users)
  }

  useEffect(() => {
    getFirestoreUsers()
  }, [])

  return (
    <div>
      {
        users.map((user, index) => (
          <p key={index}>{user.name}</p>
        ))
      }
    </div>
  )

export default Top

axiosの導入

yarn add axios

axiosでfirestoreのデータを取得する

userShow.js
import React, { useState, useEffect } from 'react'
import axios from 'axios'

const UserShow = () => {
  const [users, setUsers] = useState([])

  useEffect(() => {
    // プロジェクトIDは環境変数で呼び出す
    // process.envを付けるのを忘れずに
    const USERS_URL = `https://firestore.googleapis.com/v1/projects/${process.env.REACT_APP_PROJECT_ID}/databases/(default)/documents/users`
    const fetchUsersData = async () => {
      const result = await axios(USERS_URL)       

      setUsers(result.data.documents)
    }
    fetchUsersData()
  }, [])

  return (
    <div>
      {
        users.map((user, index) => (
          <p key={index}>{user.fields.name.stringValue}</p>
        ))
      }
    </div>
  )
}

export default UserShow

※useEffectを少しリファクタリングしました(2021/1/11)

userShow.js
useEffect(() => {
  axios.get(USERS_URL)
    .then(res => res.data.documents)
    .then(fields => setUsers(fields))
}, [])

まとめ

viewで呼び出す記述が長い気がするので、他に良い実装方法があれば教えていただきたいです。。

参考記事

Cloud Firestore REST API を使用する
How to fetch data with React Hooks?

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

DB 操作まで JS で完結!Next.js × Prisma を CRUD アプリケーションでざっくり理解する。

何について書いた記事か?

  • Next.js × Prisma を利用して CRUD アプリケーションを作成した ので、そのまとめ記事です.
    • :beginner: Next.js は React でアプリケーションを作成するためのフレームワークです.
    • :beginner: Prisma は Node.js のための ORM です.
  • 各レイヤーの役割とソースコードを対応付けながら説明することで、Next.js × Prisma で作るとどんな実装になるのか?』 をざっくりと理解することを目指します.
  • 開発を始める前にこの記事で概要を掴む 的な使い方をしてくれると嬉しいです :smile:

:bulb: こんな人にオススメ

  • Next.js / Prisma に興味を持っていて、まずはこれらで実現できることを知りたい.
  • React / Vue.js を書いていて、バックエンドも JS (TS) で書けたらいいなと思っている.

:warning: 注意点

  1. サンプルアプリケーション開発のハンズオン的な説明は行っていません.
  2. 自分は React, TypeScript の経験が浅いので、慣例 / ベストプラクティスに沿っていないソースがある と思います :rolling_eyes:
    • 逆に言えば、慣れていなくても楽しく、ストレスなく開発できました!
    • 『ここはこう書いた方がいいよ!』といったご指摘があれば、コメントで教えていただけると嬉しいです :bow:

何を作ったか?

シンプルに CRUD できるだけのアプリケーションです.

next-prisma-crud-demo.gif

  • 題材は何でもよかったので、スターバックスのカスタマイズドリンクを CRUD する前提にしています.

chanmio_special.jpg

  • 認証は入れていないので好きにデータ編集してもらってOKです.
    • (不正利用対策は主目的でないので、常識の範囲内で抑えてくれると助かります :pray: )
  • :warning: 性能: ローカル開発では気になりませんでしたが、デプロイすると DB との通信に結構時間がかかるようになってしまった (特に初回通信) ので、Vercel か AWS RDS で追加で設定すべき項目があるかもしれません.

Next.js × Prisma で作ったアプリケーションの構成

新しい技術を学ぶときの難しさの一つに 『色んな登場人物が出てきて関係性がわからない :innocent: ということがあると思っているので、最初に アプリケーションの主要な構成 を説明しておきます.

ただ、この説明だけでそれぞれについて深く理解することは難しいと思うので、まずは 『なるほど、こういうものがあるのね :thinking: と把握してもらえれば OK です.

:star: WEB ページにアクセスされてから DB 操作までのフロー

next-prisma-app-structure.png

  • 図の :arrow_up: が開発環境 / :arrow_down: が本番環境です.
    • 本番での差分にはオレンジの枠線を付けています.
  • フロントエンドは React による実装で、UI コンポーネントとして chakra-ui を利用しました.
  • バックエンドを Next.js の API Routes で実装しています.
    • これにより、フロントエンド / バックエンドがどちらも Next.js 上で実行される ことになります.
  • フロントエンド ⇄ バックエンドの通信は axios で行います.
  • バックエンド ⇄ DB の通信は Prisma で行います.

CRUD ごとにソースコードを理解する

前置きが長くなってしまいましたが、ようやく Next.js / Prisma のコードに関する説明です.
まずは CRAETE を例に、 React コンポーネント ⇄ API Routes ⇄ Prisma の関連図とソースコード を見ていきます.
READ / UPDATE / DELETE については、Prisma のコード例だけ紹介しておきます.

:warning: Prisma の基本的な書き方を集中するため、エラーハンドリングは省略しています.

:white_check_mark: CREATE

:star: CREATE するまでのフロー

next-prisma-create.png

:star: CRAETE を行う React コンポーネント

pages/create.tsx
export default function Create() {
  ...

  const createBeverage = async (values: BeverageFormData, actions) => {
    // Formik からフォームに入力された値を取得
    const body = {
      name: values.name,
      description: values.description,
      price: Number(values.price),
      isRecommend: values.isRecommend,
    };

    // axios で API Routes として定義された URL に通信を飛ばす
    await axios.post("/api/beverages", body);

    // 登録後のロジック
    ...
  };

:star: CRAETE を行う API Routes ( Prisma Client を利用 )

pages/api/beverages.ts
const handleCreate = async (
  req: NextApiRequest,
  res: NextApiResponse<Beverage>
) => {
  // request からフォームの値を取得
  const { name, description, price, isRecommend } = req.body;

  // 登録前のチェック
  ...

  // prisma - CREATE
  // Prisma Client を呼び出して、DB にデータを登録する.
  const beverage = await prisma.beverage.create({
    data: { name, description, price, isRecommend },
  });
  // 登録結果を JSON で返却する
  res.json(beverage);
};

:white_check_mark: READ

:star: READ を行う API Routes ( Prisma Client を利用 )

pages/api/beverages.ts
const handleRead = async (
  req: NextApiRequest,
  res: NextApiResponse<Beverage[]>
) => {
  // prisma - READ
  // テーブル内の全データを id 昇順に取得
  const beverages = await prisma.beverage.findMany({
    orderBy: {
      id: "asc",
    },
    // 取得データを絞り込む場合はココに `where` などを追加していく
    // https://www.prisma.io/docs/concepts/components/prisma-client/crud
  });
  res.json(beverages);
};

:white_check_mark: UPDATE

:warning: UPDATE / DELETE では、どのデータに対して操作するのかを特定するために、ファイル名を [id].ts として URL から情報を受け取っています.
ここでは、Next.js - Dynamic API Routes という仕組みを利用しています.

:star: UPDATE を行う API Routes ( Prisma Client を利用 )

pages/api/beverage/[id].ts
const handleUpdate = async (
  req: NextApiRequest,
  res: NextApiResponse<Beverage>
) => {
  // URL から id を取得
  const url = req.url;
  const updateID = parseInt(url.split(/\//, 10).pop());
  // request からフォームの値を取得
  const { name, description, price, isRecommend } = req.body;

  // 更新前のチェック

  // prisma - UPDATE
  // id が一致したデータに対して、フォームに入力された値で更新
  const beverage = await prisma.beverage.update({
    where: { id: updateID },
    data: { name, description, price, isRecommend },
  });
  res.json(beverage);
};

:white_check_mark: DELETE

:star: DELETE を行う API Routes ( Prisma Client を利用 )

pages/api/beverage/[id].ts
const handleDelete = async (
  req: NextApiRequest,
  res: NextApiResponse<Beverage>
) => {
  // URL から id を取得
  const url = req.url;
  const deleteID = parseInt(url.split(/\//, 10).pop());

  // prisma - DELETE
  // id が一致したデータを削除
  const beverage = await prisma.beverage.delete({
    where: {
      id: deleteID,
    },
  });
  res.json(beverage);
};

見ていただいた通り、Prisma を利用すると DB 操作が簡単に書けていい ですね!
また、スキーマ定義を元に型定義が生成されるので、タイプセーフに書ける というのも大きなメリットです.


Next.js × Prisma で開発するメリットは何か?

実際に開発して感じた Next.js × Prisma のメリットについてまとめておきます.

メリット :one: : JS (TS) だけで完結するため、キャッチアップコストを抑えられる

  • 当然ですが、フロントエンド / バックエンドが同一言語なので開発のキャッチアップコストを抑えることができます.
  • また、今回開発した構成だと 従来の REST API と構成が近いため、そういった意味でも理解しやすい のではと思っています.
  • React / Vue.js などのモダンフロントエンドに足を突っ込むとそれだけで結構なキャッチアップコストを支払うことになるので、『そこで学んだ技術でバックエンドも書きたい』というのは自然な発想で、それが実現できるという意味で 開発体験は非常によかった です.

メリット :two: : 同一言語 / 同一ディレクトリのため共通化がしやすい

  • 全てが JS で書かれることで、これまでフロントエンド / バックエンドで別々に管理されていた仕組みを簡単に共通化できるようになります.
  • 例えば、今回のアプリケーションではバリデーション定義を共通化したので、以下に実装例を載せておきます.

:white_check_mark: バリデーション定義の共通化

  • BeverageFormSchema.ts という Yup スキーマを定義して、それをフロントエンド / バックエンドそれぞれから import することで簡単にバリデーション定義を共通化することができました :smiley:
validators/BeverageFormSchema.ts
// Yup で入力チェックのためのスキーマを定義する
export const beverageFormSchema = Yup.object({
  name: Yup.string().required(),
  description: Yup.string(),
  price: Yup.number().min(0).max(3000),
  isRecomment: Yup.boolean(),
});

:star: Frontend

components/BeverageForm.tsx
// 1. スキーマをインポートして...
import { beverageFormSchema } from "../validators/BeverageFormSchema";

...

export default function BeverageForm({ ... }) {
  return (
    <Formik
      initialValues={initialValues}
      onSubmit={onSubmit}
      // 2. Formik に props として渡す
      validationSchema={beverageFormSchema}
    >

:star: Backend

pages/api/beverages.ts
// 1. スキーマをインポートして...
import { beverageFormSchema } from "../../validators/BeverageFormSchema";

...

const handleCreate = async ( ... ) => {
  const { name, description, price, isRecommend } = req.body;

  // 2. Yup の API を利用してバリデーションチェック
  const isValid = await beverageFormSchema.isValid({
    name,
    description,
    price,
    isRecommend,
  });
  if (!isValid) {
    res.status(400).end("sent param is invalid.");
    return;
  }

メリット :three: : サーバー管理が楽になる

  • yarn dev を実行して Next.js の開発用サーバーを立てれば SSR / ISR や API Routes もそこで実行されるため、フロントエンド / バックエンドで別々の開発用サーバーを管理しなくてよくなります.
  • 個人開発や小規模なアプリにとって、このコンパクトさは大きな魅力 だと思いました.

おわりに

いかがだったでしょうか.
Next.js × Prisma で開発をしてみて感じた良さが少しでも伝わっていれば嬉しいです.

この記事で『興味を持ったよ』という方は、是非以下のチュートリアルなどを参考に実際に開発をしてみることをオススメします.
結局、手を動かしてみるのが一番理解できると思うので!

以上、長い記事を読んでいただいてありがとうございました :bow:

開発に役立つチュートリアル集

  • Next.js - Create a Next.js App
    • Next.js の公式チュートリアルです.
    • Next.js の各機能についてハンズオン形式で解説されていて、図も豊富で非常に分かりやすかった です.
  • Prisma - Quickstart
    • Prisma を TS と SQLite で試すチュートリアルです.
    • Next.js のようなフレームワークと分離して Prisma 単体から理解を始めたい という方にオススメです.
  • Prisma - How to Build a Fullstack App with Next.js, Prisma, and PostgreSQL
    • つい最近 Prisma の公式ページに追加されていた記事なので自分はこれには沿っていないのですが、上で説明したものと同じ技術要素でのチュートリアルです.
    • プロジェクトの作成からデプロイまで丁寧に解説されていた ので、これに沿っていけば一通りの開発は順調に進められそうでした.
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Next.js】next/routerを基礎からしっかり。

前書き

筆者がNext.jsを仕事で書くことになったので、1から勉強するためにアウトプット記事を書くことにしました。
基本的にはドキュメントを噛み砕いて、翻訳した記事です。間違っているところなどあれば、ご指摘していただけるとありがたいです?‍♂️

以下、本題です。

*前提知識として【Next.js】Routingを基礎からしっかり。を一読しておくと、理解しやすいかと

useRouter

useRouter hookを使うと、アプリ内のrouterオブジェクトにアクセスすることができます。

import { useRouter } from 'next/router'

const Hoge = ({ children, href }) => {
  const router = useRouter()

  const handleClick = (e) => {
     e.preventDefault()
     route.push(href)
  }

  return (
    <a href={href} onClick={handleClick}>
      { children }
    </a>
  )
}

Hogeコンポーネントの子要素をラップして、指定したhrefへのリンクコンポーネントを作成するコードです。

const router = useRouter()の部分でrouterオブジェクトを取得できます。具体的にrouterオブジェクトに定義されているメソッドは下記です。

router object

  • pathnameString => 現在のrouteを表示。/pages内のpathを表示します。
  • queryObject => オブジェクトにパースされたクエリ文字列を表示します。
  • asPathString => ブラウザに表示される(クエリを含む)pathを表示します。
  • basePathString => 使えるBasePathを表示する。

主な関数はこんな感じです。まだいくつかあるので、気になる方は調べてみてください。

router.push

クライアント側の遷移を処理します。このメソッドはnext/linkが苦手な部分をカバーくれます。

router.push(url, as, options)
  • url:ここに遷移します
  • as:ブラウザに表示されるURLのオプションのデコレータ
  • options:設定オプション
    • shallow:再実行せずに現在のページのパスを更新する

使い方

事前に定義されたルート(pages/about.js)への遷移

import { useRouter } from 'next/router'

export default function Page() {
  const router = useRouter()

  return <span onClick={() => router.push('/about')}>Click me</span>
}

動的なルート(pages/post/[pid].js)への遷移

import { useRouter } from 'next/router'

export default function Page() {
  const router = useRouter()

  return <span onClick={() => router.push('/post/abc')}>Click me</span>
}

pages/login.jsへリダイレクトさせたい場合。認証の後のページに便利。

import { useEffect } from 'react'
import { useRouter } from 'next/router'

const useUser = () => ({ user: null, loading: false })

export default function Page() {
  const { user, loading } = useUser()
  const router = useRouter()

  useEffect(() => {
    if (!(user || loading)) {
      router.push('/login')
    }
  }, [user, loading])

  return <p>Redirecting...</p>
}

With URL object

URLオブジェクトはnext/linkと同じように使うことができます。URLとパラメータの両方で使用できます。

import { useRouter } from 'next/router'

export default function ReadMore({ post }) {
  const router = useRouter()

  return (
    <span
      onClick={() => {
        router.push({
          pathname: '/post/[pid]',
          query: { pid: post.id },
        })
      }}
    >
      Click here to read more
    </span>
  )
}

オブジェクトの形でpathnamequeryを指定していることが確認できるかと思います。ここでは動的なルーティングを実現しています。

router.replace

router.replace(url, as, options)

それぞれの役目はrouter.pushと同じです。

next/linkreplacepropと同様に、URLエントリを履歴スタックに追加するのを防ぎます。わかりにくいので例をみていきましょう。

では、使い方を見ていきましょう。

使い方

import { useRouter } from 'next/router'

export default function Page() {
  const router = useRouter()

  return <span onClick={() => router.replace('/home')}>Click me</span>
}

router.prefetch

クライアント側の遷移を高速化するためにページをプレフェッチします。とはいえnext/linkが自動的にページのプリフェッチを行うため、この方法はnext/linkを使用しないナビゲーションにのみ有用です。

ちなみにProduction環境での話であり、開発環境ではプレフェッチしません。

使い方

ログインページがあり、ログイン後にダッシュボードにリダイレクトするとします。その場合、次の例のように、ダッシュボードをプリフェッチすることで、より速く遷移させることができます。

つまりnext/linkでは自動的にプリフェッチしてくれるのですが、リダイレクト処理等でnext/routeを使う場合はプリフィッチしてあげると表示を高速にしてくれます。

import { useCallback, useEffect } from 'react'
import { useRouter } from 'next/router'

export default function Login() {
  const router = useRouter()
  const handleSubmit = useCallback((e) => {
    e.preventDefault()

    fetch('/api/login', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        /* Form data */
      }),
    }).then((res) => {
      // Do a fast client-side transition to the already prefetched dashboard page
      if (res.ok) router.push('/dashboard')
    })
  }, [])

  useEffect(() => {
    // Prefetch the dashboard page
    router.prefetch('/dashboard')
  }, [])

  return (
    <form onSubmit={handleSubmit}>
      {/* Form fields */}
      <button type="submit">Login</button>
    </form>
  )
}

基本的な使い方は以上です。ではでは〜

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

【Next.js】Base Pathを基礎からしっかり。

前書き

筆者がNext.jsを仕事で書くことになったので、1から勉強するためにアウトプット記事を書くことにしました。
基本的にはドキュメントを噛み砕いて、翻訳した記事です。間違っているところなどあれば、ご指摘していただけるとありがたいです?‍♂️

以下、本題です。

Base Path

どんな時に使うの?

Next.jsアプリケーションをドメインのサブパスの下にデプロイするには、basePath設定オプションを使うことができます

ちょっとわかりにくい。。。噛み砕いて解説してきます。

例えばexample.com/hogeみたいな感じでデプロイしたい場合、にBasePath設定をすることで解決してくれるということです。

具体的にどう設定するの?

example.com/hogeでデプロイしたい場合は、next.config.jsを下記のように設定してあげればOKです。

next.config.js
module.exports = {
  basePath: '/docs',
}

Links

他のページにリンクするには、next/linknext/routerを使えばbasePathを考慮して自動的に変換してくれます。例えば

export default function HomePage() {
  return (
    <>
      <Link href="/about">
        <a>About Page</a>
      </Link>
    </>
  )
}

このリンクコンポーネントは実際には下記のように出力されます。

<a href="/hoge/about">About Page</a>

ちゃんとhogeが追加されていることが確認できると思います。つまり、全てのリンクコンポーネントに対して、basePathを追加する必要はないということです。便利!

以上です。ではでは〜

参考記事

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

Next.jsで作ったWebアプリをデスクトップアプリ化した

はじめに

公式に例を参考にして、既に作ったWebアプリをデスクトップアプリ化してみました。公式チュートリアルで作ったものを例にして書いていきたいと思います。
とりあえずデスクトップアプリ化するのいう感じで、そのまま機能を全部使えるとは限らず、追加で色々な実装が必要になると思いますが、少しでも役立てたら嬉しいです。

参考:with-electron-typescript

今回は下の画像のようにsrcディレクトリにpagesやcomponentsディレクトリが入っている構成でやっていきたいと思います。
image.png

作成したリポジトリ:https://github.com/NozomuTsuruta/my-blog

導入

まず、以下のコマンドで必要なpackageをインストールします。

## npm
npm install electron-is-dev electron-next
npm install --save-dev electron electron-builder

## yarn 
yarn add electron-is-dev electron-next
yarn add -D electron electron-builder

Electron用のファイル作成

その後、以下のようにelectron-srcに3つのファイルを作成します。

image.png

electron-nextの型定義ファイル↓

electron-src/electron-next.d.ts
declare module "electron-next" {
  interface Directories {
    production: string;
    development: string;
  }

  export default function (
    directories: Directories | string,
    port?: number
  ): Promise<void>;
}

windowを開く、閉じる時の設定や処理↓

electron-src/index.ts
import { join } from "path";
import { format } from "url";
import { BrowserWindow, app, shell } from "electron";
import isDev from "electron-is-dev";
import prepareNext from "electron-next";

app.on("ready", async () => {
  await prepareNext(".");

  const mainWindow = new BrowserWindow({
    width: 1000,
    height: 800,
    webPreferences: {
      nodeIntegration: false,
      preload: join(__dirname, "preload.ts"),
    },
  });

  mainWindow.webContents.on("new-window", (event, url) => {
    event.preventDefault();
    shell.openExternal(url);
  });

  const url = isDev
    ? "http://localhost:8000/"
    : format({
        pathname: join(__dirname, "../out/index.html"),
        protocol: "file:",
        slashes: true,
      });

  mainWindow.loadURL(url);
});

app.on("window-all-closed", app.quit);

設定はお好みで↓

electron-src/tsconfig.json
{
  "compilerOptions": {
    "allowJs": true,
    "alwaysStrict": true,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "lib": ["dom", "es2017"],
    "module": "commonjs",
    "moduleResolution": "node",
    "noEmit": false,
    "noFallthroughCasesInSwitch": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "resolveJsonModule": true,
    "skipLibCheck": true,
    "strict": true,
    "target": "esnext",
    "outDir": "../main"
  },
  "exclude": ["node_modules"],
  "include": ["**/*.ts", "**/*.tsx", "**/*.js"]
}

package.jsonに追加

MyAppの部分はアプリ名です。

次にpackage.jsonに以下を追加

package.json
{
  ...
  "productName": "MyApp"
  "main": "main/index.js",
  "scripts": {
   ...
    "dev-electron": "tsc -p electron-src && electron .",
    "dist": "next build && next export && tsc -p electron-src && electron-builder"
  },
  ...
}

一応アプリアイコンはこんな書き方で変更できます↓

package.json
{
  ...
  "build": {
    "mac": {
      "icon": "./public/icons/icon.icns",
      "target": [
        "dmg"
      ]
    },
    "win": {
      "icon": "./public/icons/icon.ico",
      "target": "msi"
    }
  }
}

.gitignoreにmainとdistを追加しておきましょう

.gitignore
/main
/dist

作成

最後に以下のコマンドを実行します。Windowsのアプリを作りたい場合は後ろに--win --x64をつけます。

## npm
npm dist

## yarn
yarn dist

Finderなどからdmgファイル(windowsはフォルダーからexeファイル)を開くとインストールできます!
image.png

アプリケーションから開くとこんな感じになりました!
image.png

最後に

ここまで読んでいただきありがとうございます!私自身Electronに関しての知識がまだまだ浅いので詳しく説明できなかった部分が多いのでもう少し学習を進めていきたいと思います。少しでもお役に立てれば嬉しいです!

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

firebaseでメールアドレスを取得する方法

Firebaseでユーザネームをメールアドレスを取得する方法

export const createUserProfileDocument = (userAuth. additionalData) => {
 if(!userAuth) return;

const userRef = firestore.doc(`users/${userAuth.uid}`)

const snapshot = await userRef.get()

if(!snapshot.exists) {
 const {displayName, email} = userAuth;
 const createdAt = new Date();

 try {
  await userRef.set({
   displayName,
   email,
   ...additionalData
  })
} catch (error){
 console.log('error creating user' error.message)
}
}
return userRef
}

間違っていたら教えてください

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

Next.js公式examples集を分類(2021年1月版)

はじめに

Next.jsの公式サンプル前回(2020年7月)から34本増えて合計268本あります。新たに追加されたサンプルには(new)がついています。(2021/01/10)
しかし、このままではどれを見たらいいのかわからないので主観で分類してみました。

(基礎)Next.jsで基礎的な内容を扱っているサンプル。
(公式)公式ドキュメント で説明するのに使われているサンプル等。

※今回の更新で一番目についたのはwith-mysqlで、その他DB関連も多く追加されていました。

Next.js公式examples集

Next.jsの基礎1易しい
basic-css (基礎)(公式)CSS in JSを使っている
basic-export (基礎)最も基本的な使用法
dynamic-routing (基礎)(公式)動的ルーティングの使用例
environment-variables (基礎)環境変数の使い方
head-elements (基礎)ヘッド要素の使用例
hello-world (基礎)Next.jsの基本中の基本
layout-component (基礎)一般的な使用例
nested-components (基礎)コンポーネントをネストして利用する使用例
using-router (基礎)(公式)コンポーネントの代わりにnext/routerを使ってページをリンクする
with-app-layout (基礎)_app.jsを使用してすべてのページにグローバルレイアウトを実装する
with-loading (基礎)ページ切替時に時間がかかる時、Loading画面を表示する技術
Next.jsの基礎2普通
active-class-name Next独自のLinkを使ってclassNameでプロパティを設定する使用例
catch-all-routes (公式)ページをデータから自動的に作成してくれる機能
data-fetch (公式)サーバーとクライアントでデータをフェッチするのが非常に簡単になります。
gh-pages Nextの最も基本的なアイデアの使用方法
progressive-render プログレッシブサーバーサイドレンダリングを実装するアプリの使用例
ssr-caching 一度SSRしたページをキャッシュして使用する使用例
with-absolute-imports 絶対インポートを使用したアプリの使用例
with-context-api アプリでreact context apiを使用する方法
with-dynamic-app-layout app.jsを使用してページの_dynamicレイアウトを実装する方法
with-dynamic-import (公式)モジュールを動的にインポートする方法
with-env-from-next-config-js (公式)next.config.jsを使って環境変数をビルド時に設定します。
with-http2 HTTP2サーバーを使った最も基本的な使用例
with-next-page-transitions ページ間移動時において読み込み状態を簡単に追加
with-prefetching ページをプリフェッチ(事前読み込み)するサンプルアプリ
with-react-helmet next.jsとreact-helmetを組み合わせる方法の最小限の使用例 ドキュメントヘッドへのすべての変更を管理します。
with-shallow-routing (公式)ShallowRoutingExample
with-static-export (公式)APIからデータをフェッチするNext.jsアプリケーションを静的HTMLファイルにエクスポートして、ページの動的リストを生成する方法
with-typescript-eslint-jest NextJS Typescriptボイラープレート
with-typescript-types TypeScript型システムをNext.jsに統合する方法
with-typescript タイプスクリプトを使って型を適用
with-zones (公式)マルチゾーン機能を使用して、複数のアプリを1つのアプリとして使用できます。
Next.jsの基礎3 2021年1月版追加分
(new)fast-refresh-demo Next.jsにはFast Refreshが搭載されており、Reactコンポーネントに加えられた編集を即座にフィードバックすることができます。このデモでは、編集後やエラーが発生した場合に、自動インクリメント値とクラシックカウンタの状態がどのように保存されるかを見ます。
(new)redirects Next.jsでリダイレクトを使用して、入ってきたリクエストパスを別の宛先パスにリダイレクトする方法
(new)rewrites Next.jsで書き換えを使用して、着信要求パスを別の宛先パスにマップする方法
pwa関連
(new)progressive-web-app next-pwaを使用して、Workboxを利用したプログレッシブウェブアプリ(PWA)を作成します。
UI関連ant
with-ant-design-less Ant Design of ReactとともにNext.jsを使用する方法
with-ant-design-mobile antd-mobileとともにNext.jsを使用する方法
with-ant-design-pro-layout-less Ant Design Pro Layout of React.とともにNext.jsを使用する方法
with-ant-design Ant Design of ReactとともにNext.jsを使用する方法
UI関連その他
(new)with-chakra-ui-typescript このサンプルでは、typescriptを使用してNext.jsアプリ内のコンポーネントライブラリとしてchakra-uiを使用する方法を紹介します。
(new)with-ionic-typescript 高品質のクロスプラットフォームネイティブおよびWebアプリエクスペリエンスを構築するためのオープンソースモバイルUIツールキット。
(new)with-mdbreact レスポンシブでモバイルファーストのウェブサイトやアプリを構築するためのUIキット
with-atlaskit Atlaskit of ReactとともにNext.jsを使用する方法AltassianのオフィシャルUIライブラリ
with-chakra-ui Webサイトやアプリの作成を非常に簡単にする、アクセス可能で再利用可能で構成可能なReactコンポーネントのセットchakra-uiをNext.jsアプリ内のコンポーネントライブラリとして使用する方法
with-grommet Grommet UI library
with-material-ui (人気)(Material-UI公式サイトのサンプル) mui-org/material-ui/examples/nextjs/
with-patternfly RedHatが作っているUIフレームワークUIパターン集
with-rebass UIコンポーネントRebassはReactのブートストラップです。
Firebase関連
(new)with-supabase-auth-realtime-db Supabaseは、Firebaseのオープンソースの代替手段です。
with-firebase-authentication サーバーレスAPIを使用したFirebase認証の使用例
with-firebase-cloud-messaging FirebaseCloudMessagingの使用例
with-firebase-hosting Firebaseホスティングの使用例
with-firebase クライアントサイドアプリケーション用のFirebaseの簡単な設定です。
API Routes編
api-routes-cors (公式)Cross-OriginResourceSharing(CORS)追加のHTTPヘッダーを使用して、ある起点で実行されているWebアプリケーションに、異なる起点から選択されたリソースへのアクセスを許可するようにブラウザーに指示するメカニズムです。
api-routes-middleware (公式)APIルート
api-routes-rest (公式)独自のルートを構築する簡単なソリューションを提供するAPIルートが付属しています。このサンプルは、それを使用してREST APIを作成する方法
api-routes (公式)基本的なAPIルートの使用例
API Routes編 GraphQL関連
api-routes-graphql (公式)GraphQL Server apollo-server-micro
with-graphql-faunadb FaunaDBGraphqlスターターの使用例-FaunaDBゲストブック
with-graphql-hooks GraphQLフックの使用例。GraphQL Hooksは、最小限のフック優先のGraphQLクライアントになることを目的としたNearFormのライブラリです。
with-graphql-react graphql-react最新のコンテキストを使用したReactのGraphQLクライアント
with-react-relay-network-modern The production-ready GraphQL client for React.
with-reason-relay GraphQL backend
with-relay-modern Facebookが開発 Next.jsの9.3で導入されたgetStaticProps, および9.4で導入されたIncremental Static Regenerationは、Relayと非常に相性がいい The production-ready GraphQL client for React.
with-typescript-graphql GraphQLとtypescriptの使用例
with-urql 高度にカスタマイズ可能で用途の広いGraphQLクライアント
API Routes編 apollo関連
(new)api-routes-rate-limit このサンプルではlru-cacheを使用してAPIルート(サーバーレス関数)の単純なレートリミッターを実装します。lru cacheは最も使用頻度の低いアイテムを削除するキャッシュオブジェクトです。
(new)with-apollo-neo4j-graphql GraphQLとApolloでNeo4jデータベースを使用するNextの簡単なセットアップです。 Neo4jのMoviesデータセットの使用例です。
api-routes-apollo-server-and-client-auth ApolloはGraphQLクライアント
api-routes-apollo-server-and-client ApolloはGraphQLクライアント
api-routes-apollo-server ApolloはGraphQLクライアント
with-apollo-and-redux ApolloはGraphQLクライアント
with-apollo ApolloはGraphQLクライアント
DB関連 prisma編
with-prisma Node.jsおよびTypeScript用の次世代ORM
DB関連 mysql編
(new)with-mysql Next.jsプロジェクトでMySQLを使用する使用例
DB関連 その他
(new)with-deta-base Deta Baseは、エンドユーザーのシンプルさに重点を置いた、フルマネージドで高速、スケーラブルで安全なNoSQLデータベースです。
(new)with-knex Knexは、Postgres や MySQL を含むさまざまな SQL データベースで動作する SQL クエリビルダーです。このサンプルでは、Next.js と Knex を使って Postgresデータベースに接続してクエリを実行する方法です。
(new)with-mongodb このサンプルはMongoDBに接続してNext.jsアプリのバックエンドとして使用する方法
(new)with-neo4j Neo4jは、データだけでなく、データの関係性を活用するために一から構築されたネイティブのグラフデータベースです。
(new)with-redis Redisは、Key-Value型 の NoSQLデータベースです。
with-mongodb-mongoose MongoDB
with-realm-web MongoDBRealmWebSDK
コンポーネント関連
with-carbon-components IBM's carbon-components-react
server関連
custom-server-actionhero Action Hero
custom-server-express (公式)Express Webアプリケーション
custom-server-fastify Fastify
custom-server-hapi (公式)Secure Framework
custom-server-koa (公式)new web framework designed
custom-server-polka Express.jsの代替品
custom-server-typescript Nodemonを使用してサーバーとクライアントの両方でTypeScriptを使用し、Next.jsユニバーサルコードに影響を与えずにサーバーコードをライブでリロードする方法
custom-server カスタムサーバーの使用例
storybook関連
(new)with-storybook-styled-jsx-scss このサンプルはStorybookでレンダリングされTypeScriptで記述されたコンポーネントStyled-jsx(SCSSを使用)の使用例です。
with-storybook UIコンポーネントを開発するためのオープンソースツール
検索関連
with-algolia-react-instantsearch 検索の実装と検索の分析
監視関連
with-sentry アプリケーション監視プラットフォーム
リッチテキスト関連
with-draft-js RichTextEditorFrameworkforReact
with-quill-js powerfulrichtexteditor
with-slate リッチテキストThisiseditablerichtext
認証関連
auth0 (認証)(有料有り)認証サポートを簡単に追加する方法
with-cookie-auth-fauna (認証)(有料有り)ユーザーを認証し、トークンを安全な(JS以外の)Cookieに格納します。
with-iron-session (認証)署名および暗号化されたCookieを使用してセッションデータを格納する認証システムを作成
with-magic (認証)(有料有り)Magic電子メールベースのマジックリンクを使用した、Cookieベースのパスワードなし認証を特徴としています。
with-next-auth (認証)オープンソースで使いやすく、デフォルトで安全な認証ライブラリを備えたnext-authを使用
with-passport-and-next-connect (認証)Passport.jsでnext-connectおよびcookieベースの認証を使用して、基本的なCRUDアプリを作成します。
with-passport (認証)ユーザー名とパスワードを使用したCookieベースの認証
with-userbase (認証)(有料有り)Userbaseユーザーアカウントとデータの永続性を静的サイトに追加する最も簡単な方法です
CSS関連 tailwindcss編
with-tailwindcss-emotion tailwindCSS
with-tailwindcss (公式)tailwindCSS
CSS関連 styled-jsx編
(new)with-styled-jsx Next.jsにはstyled-jsxが付属しており、CSSを完全にサポートするスコープ付きスタイルのコンポーネントを作成できます。
with-styled-jsx-plugins CSS styled-jsxプラグインを使用
with-styled-jsx-scss PostCSS、SASS(SCSS)、LESS、またはstyled-jsxを備えたその他のプリプロセッサを使用できます。
CSS関連 その他
(new)with-cssed CSS-in-JSlibraryであるcssedの使用例
(new)with-react-md-typescript このサンプルではreactのマテリアルデザイン、Next.js、およびTypescriptアプリをセットアップします。
(new)with-reactstrap reactstrapをNext.jsで使用する方法。reactstrapはBootstrap4のステートレスreactコンポーネント。
with-aphrodite (公式)CSS in JS aphroditeを使用したアプリの使用例
with-astroturf CSS in JS stroturfを使用したアプリの使用例
with-cxs (公式)CSS in JS minimal CSS in JS cxsを使用したアプリの使用例
with-emotion CSS in JS SSR中にサーバーデータを直接Next.jsページに渡す
with-fela (公式)CSS in JS
with-filbert CSS in JSソリューション(フレームワーク)filbert-jsでNext.jsを使用する
with-glamor (公式)CSS in JS CSS関連スタイリングソリューションの使用方法
with-goober 小さなcss-in-js
with-linaria CSS linariaを使用したアプリの使用例
with-next-css CSSモジュールサポートの使用方法
with-next-less CSS Next.js + Less
with-next-sass Sass/Scssモジュールサポートの使用方法
with-rbx-bulma-pro Bulma is simply a collection of CSSclasses.
with-react-bootstrap react-bootstrap react用に再構築されたbootstrap
with-react-jss JSSはCSSのオーサリングツール
with-react-md (紹介ページが消えている、V2になってページが移動した?)SCSSreact-md (React Material Design)
with-react-with-styles CSS in JS
with-semantic-ui CSSフレームワーク Semantic UI Reactと一緒にNext.jsを利用する方法
with-stitches CSS in JS
with-style-sheet CSS in JSlibrarystyle-sheet
with-styled-components-rtl 右から左にすると、サイト内のすべての要素を「反転」して、右から左に読む文化(たとえば、アラビア語)のニーズに合わせることができます。
with-styled-components (公式)CSS in JS CSSstyled-components
with-styletron (公式)CSS in JSスタイルソリューション
with-typescript-styled-components StyledComponentsとTypeScriptの使用例。CSS in JSの中で最も人気のあるライブラリ
with-typestyle CSSスタイルソリューションを使用する方法
状態管理redux関連
with-redux-code-splitting Redux関連
with-redux-observable Redux関連
with-redux-persist Redux関連
with-redux-saga Redux関連
with-redux-thunk Redux関連
with-redux-toolkit Redux関連
with-redux-wrapper Redux関連
with-redux Redux関連
with-rematch このサンプルには2つのページがあります。最初のページには、同期的または非同期的にインクリメントできるカウンタがあります。2番目のページはgithubユーザーのリストを表示するページです。このエンドポイントを使ってgithub APIからデータを取得します。 rematchはreduxを使ったユーティリティなので、store.jsやwithRematchのような要素はwith-reduxの使用例と非常に似ています。redux が nextjs とどのように統合されているかをよく知らない方は、ここで with-reduxの使用例を見てから読んでください。RematchはReduxの拡張機能に過ぎないので、多くの要素は同じです。
状態管理その他
(new)with-zustand React向け軽量ステート管理ライブラリの使用例
with-kea 状態管理フレームワーク
with-mobx-react-lite 状態管理
with-mobx-state-tree-typescript 状態管理
with-mobx-state-tree 状態管理
with-mobx 状態管理アプリのグローバルな状態を取得したい場合
with-overmind 状態管理
with-recoil 状態管理ライブラリ
with-unstated unstated-nextReact状態管理ライブラリ
amp関連
amp-first AMPファーストサイトのボイラープレートを設定
amp-story Next.jsとAMP機能を使用してamp-storyを含むAMPページを作成する方法
amp (公式)Next.jsとAMP機能を使用してAMPページを作成する方法
国際化
(new)i18n-routing Next.js ver10.0から国際化が組み込まれました。https://nextjs.org/docs/advanced-features/i18n-routing
with-i18n-rosetta 汎用国際化ライブラリ
with-lingui LinguiJS-JavaScriptでのシームレスな国際化
with-next-i18next i18nextに基づく国際化をnext.jsアプリケーションに追加する最も簡単な方法
with-next-translate next-translate Next.jsページを翻訳するためのツールです。
with-react-intl FormatJSクライアントとサーバーでWebアプリを国際化します。
AWS関連
with-aws-amplify-typescript AWSAmplifyは、モバイルおよびフロントエンドのウェブデベロッパーがAWSを利用して安全でスケーラブルなフルスタックアプリケーションを構築できるようにするツールとサービスのセットです。
with-aws-amplify AWSAmplifyは、モバイルおよびフロントエンドのウェブデベロッパーがAWSを利用して安全でスケーラブルなフルスタックアプリケーションを構築できるようにするツールとサービスのセットです。
テスト関連
with-jest テスト
with-mocha テスト
with-tesfy A/Bテストと機能フラグ
システム関連 webpack bundle babel
analyze-bundles @next/bundle-analyzerの使い方
with-babel-macros babel-plugin-macrosは、ユーザーがビルドシステムにbabelプラグインを追加することなくコンパイル時のコード変換を使用するライブラリの標準インターフェイスを定義します
with-custom-babel-config カスタムBabel構成の使用例
with-webpack-bundle-size-analyzer Webpackバンドルのサイズに寄与しているものを見つけるのに役立つ小さなユーティリティ。
cms関連
(new)cms-kontent Next.jsとKontentを使用して静的に生成されたブログの使用例
blog-starter-typescript Next.js、Markdown、TypeScriptを使用して静的に生成されたブログの使用例
blog-starter (公式)Next.jsとMarkdownを使用して静的に生成されたブログの使用例
cms-agilitycms AgilityCMS
cms-buttercms ButterCMS
cms-contentful (公式)Contentful
cms-cosmic Cosmic
cms-datocms (公式)DatoCMS
cms-graphcms GraphCMS
cms-prismic (公式)Prismic
cms-sanity (公式)Sanity
cms-storyblok Storyblok
cms-strapi (公式)Strapi
cms-takeshape (公式)TakeShape
cms-wordpress (公式)WordPress
with-netlify-cms Gitワークフロー用のオープンソースのコンテンツ管理システム
デスクトップアプリケーション関連
with-electron-typescript デスクトップアプリケーションElectron application example with typescript
with-electron デスクトップアプリケーションElectron application example
mdx関連
(new)with-mdx-remote next-mdx-remoteライブラリを使用して簡単なブログを構築する方法
with-mdx next.jsアプリのトップレベルページとしてMDXを使用する方法
google関連
(new)with-google-tag-manager Googleタグマネージャーを使用したアプリの使用例
with-google-analytics-amp AMPと組み合わせてGoogleアナリティクスとともにNext.jsを使用する方法
with-google-analytics GoogleアナリティクスとともにNext.jsを使用する方法
with-react-ga react-ga React Google Analytics Module
preact関連
using-preact 高速で小型のReactと言われるpreactを使用する使用例
サイトマップ関連
(new)with-next-sitemap next-sitemapを使用してすべてのページ(すべての事前レンダリング/静的ページを含む)のサイトマップファイルを生成する使用例
(new)with-sitemap Next.jsアプリのページに基づいてファイルを生成する方法
既存プロジェクトからの移行関連
custom-routes-proxying このサンプルでは、Next.jsの新しいカスタムルート機能を使って、リクエストをアップストリームサーバーにプロキシする最も基本的な使用例。pages/index.js、pages/about.js、pages/hello/[slug].jsの3つのページがあります。これらのページはすべてNext.jsと照合され、それ以外のパスはアップストリームサーバーにプロキシされます。このアプローチは、アプリケーションをインクリメンタルにNext.jsに移行しようとしているが、既存のアプリケーションにフォールバックする必要がある場合に非常に便利です。Next.jsアプリケーションにページを1つずつ追加し、移行していないページについては、移行できるようになるまでNext.jsが既存のアプリケーションにプロキシすることができます。
docker関連
with-docker 実行時にDockerアプリケーションのカスタム環境変数を設定する方法
画像関連
(new)image-component Next.js の Image Componentを使用して、最適化されたレスポンシブ画像を提供する方法
(new)with-unsplash 自由に使用できる画像のインターネットソース。
svg-components .babelrcを使用して、.svgファイルをインポートし、それらをReactコンポーネントとしてレンダリングするためのサポートを追加します。
with-three-js threejsはWebGL レンダラを持つ軽量な 3D ライブラリ。このライブラリには Canvas 2D、SVG、CSS3Dのレンダラーも用意されています。
動画関連
with-hls-js HTTPライブストリーミングクライアントを実装するJavaScriptライブラリです。
with-mux-video この使用例では、APIファーストのビデオプラットフォームであるMuxVideoを使用しています。この使用例では、Next.jsアプリケーションでのビデオのアップロードと再生を取り上げています。
with-videojs デフォルトのスタイルの処理を含む、Video.jsとともにNext.jsを使用する方法
アニメーション関連
(new)with-gsap gsapはアニメーションライブラリです。
with-framer-motion motionはオープンソースで本番環境に対応したモーションWeb上のReact用のライブラリ
moved、removed、非推奨、廃止
page-transitions (インストール不要)このサンプルは非推奨になり、削除されました。
parameterized-routing (インストール不要)このサンプルは非推奨になり、削除されました。
with-cookie-auth (非推奨)(認証)このサンプルは非推奨になり、次のいずれかを参考にしてください。auth0 with-cookie-auth-fauna with-passport with-iron-session with-next-auth
with-dotenv (インストール不要)Next.js9.4からサポートされています。
with-firebase-authentication-serverless (moved)with-firebase-authentication
with-glamorous (インストール不要)glamorousは非推奨になり、エモーションが採用されました。
with-global-stylesheet-simple (インストール不要)このサンプルは非推奨になりました。代わりにexamples/with-next-cssを使用してください。
with-global-stylesheet (インストール不要)このサンプルは非推奨になりました。代わりにexamples/with-next-cssを使用してください。
with-markdown (インストール不要)Markdownの使い方はcanary/examples/blog-starterを見てください。
with-next-routes (インストール不要)動的ルートがデフォルトでサポートされるようになりました
with-now-env (インストール不要) Next.jsは9.4以降、環境変数の読み込みを自動的にサポートします。
with-pretty-url-routing (インストール不要)動的ルートはデフォルトでサポートされるようになりました
with-sentry-simple (インストール不要)(moved)with-sentryの方を使用してください。アプリケーション監視プラットフォーム
with-strict-csp-hash (インストール不要) (moved)このサンプルはwith-strict-cspに移動しました
with-styled-jsx-postcss (moved) このサンプルは/examples/with-styled-jsx-pluginsに移動しました
with-sw-precache (インストール不要)canary/examples/with-next-offlineの使用をおすすめします。
with-universal-configuration-build-time (インストール不要)Next.js9.4以降、環境変数の読み込みを自動的にサポートします。
with-universal-configuration-runtime (インストール不要)Next.js9.4以降、環境変数の読み込みを自動的にサポートします。
with-webpack-bundle-analyzer (moved)このサンプルはanalyze-bundlesに移動しました。
古い、数年更新がない
with-reflux 古い SSR中にサーバーデータをNext.jsページに直接渡す
その他
(new)with-facebook-pixel Facebook Pixelの使用例
(new)with-mqtt-js Next.jsでMQTT.jsを使用する方法 MQTT.jsは、node.jsおよびブラウザー用のJavaScriptで記述されたMQTTプロトコルのクライアントライブラリです。
(new)with-msw Mock Service Workerは、ブラウザとノード用のAPIモックライブラリです。
(new)with-paste-typescript Pasteは、Twilioでアクセス可能で、まとまりのある、高品質のカスタマーエクスペリエンスを構築するために使用される設計システムです。Pasteは、Sketch and Reactで顧客のUIを構築するのに役立つツールとアセットで製品デザイナーとエンジニアをサポートします。
(new)with-portals-ssr ポータルは、親コンポーネントのDOM階層の外側に存在するDOMノードに子をレンダリングするためのファーストクラスの方法を提供します。
(new)with-portals ポータルは、親コンポーネントのDOM階層の外側に存在するDOMノードに子をレンダリングするためのファーストクラスの方法を提供します。
(new)with-service-worker ServiceWorkerをNext.jsアプリケーションに追加する方法
with-cerebral 一般的なJavaScriptフレームワーク用の宣言型の状態および副作用管理ソリューション
with-custom-reverse-proxy リバースプロキシの使用例
with-expo-typescript Next.js、Expo、およびTypeScriptを使用してユニバーサルReactアプリを作成するためのスタータープロジェクトです。
with-expo Next.jsとExpoを使用してユニバーサルReactアプリを作成するためのスタータープロジェクトです。
with-flow Flow静的型チェッカーFlowを使用したアプリの使用例 flowはJavaScriptの静的タイプチェッカーです。
with-monaco-editor モナコエディタは VS Codeを動かすコードエディタです。
with-next-offline next-offlineプラグインの使用方法
with-next-seo Next.jsでSEOを管理するのに役立つプラグインであるnext-seoを統合する方法
with-orbit-components Orbitは、Kiwi.comの特定のニーズに合わせて作成されたオープンソースのデザインシステムで、旅行プロジェクトのニーズにも対応しています。
with-polyfills ポリフィルを使用したアプリの使用例 警告:このサンプルは、ポリフィルを追加するための推奨される方法ではなく、バンドルで問題を引き起こすことが知られています。
with-react-multi-carousel react-multi-carouselは、外部依存関係のない複数のアイテムをサポートするサーバー側でレンダリングするカルーセルを提供するReactコンポーネントです。
with-react-native-web react-native-webを使用して、プラットフォームに依存しないReactNativeのコンポーネントとAPIをWebに取り込む方法
with-react-toolbox React Toolbox 2.0以降を使用してください。
with-reasonml-todo ReasonMLおよびReasonReactコンポーネントを使用したサンプルアプリ
with-reasonml ReasonMLおよびReasonReactコンポーネントを使用したサンプルアプリ
with-route-as-modal 多くの人気のソーシャルメディアでは、投稿を開くとURLが更新されますが、ナビゲーションはトリガーされず、代わりにモーダル内にコンテンツが表示されます。この動作により、ユーザーは現在のUIコンテキスト(スクロール位置)を失うことはありません。URLは引き続き投稿の実際のページの場所を反映しており、更新するとユーザーはそこに移動します。この動作により、SEOを無視することなく優れたUXが保証されます。 このサンプルは、ルートに基づいてモーダルを条件付きで表示する方法。
with-segment-analytics 分析機能を備えたアプリの使用例
with-stencil ステンシルは、Webコンポーネント(より具体的にはカスタム要素)を生成するコンパイラです。ステンシルは、最も人気のあるフレームワークの最高の概念をシンプルなビルドタイムツールに組み合わせています。
with-stomp Next.jsアプリケーション内でSTOMPを使用する方法。STOMPは、単純なテキスト指向のメッセージングプロトコルです。
with-strict-csp スクリプトハッシュを生成する厳密なCSPを使用したアプリの使用例
with-stripe-typescript TypeScriptとreact-stripe-jsでStripeを使用した使用例。 Stripe はインターネットビジネスのための決済プラットフォームです。
with-web-worker worker-pluginを利用してWebWorkersでコードを実行する方法
with-webassembly WebAssemblyの使用例
with-why-did-you-render why-did-you-renderの簡単な使用方法。
with-xstate XStateをNext.jsに統合する方法。 JavaScriptとTypeScriptの有限状態マシンと最新のWeb用のステートチャート。
with-yarn-workspaces ワークスペースはパッケージアーキテクチャを設定する新しい方法で、Yarn 1.0 からデフォルトで利用可能です。これにより、複数のパッケージを設定することができ、yarn install を一度だけ実行して、すべてのパッケージを一度にインストールすることができます。
with-zeit-fetch Next.jsアプリケーションで@zeit/fetchを使用する方法
前回の調査から削除されたもの
with-emotion-11 CSS in JS
with-stitches-styled CSS in JS
with-storybook-typescript (インストール不要)削除されました。
z-experimental-refresh (実験的) アプリケーションやプロジェクトでは、これらの機能を(まだ)使用しないでください。

Yarn workspace機能で2個目以降のインストール時間を短縮

前提

複数のサンプルを試したい場合に、一つ一つインストールしていくと非常に時間がかかってしまいます。どうにか時間を短縮したいという場合。

  • 問題点 サンプルによっては正常に動かないものがあります。 認証系など外部に頼るものをインストールした時。 他には、数百個同時にインストールをした時。 どちらも解決方法は不明です。

もしエラーが出た場合
そのexampleのREAD.MEを読んでみましょう。
npm install or yarnという単純なインストール方法でない可能性が高いです。

Yarn workspace機能を利用してリポジトリを一元管理します。

準備&初期設定

まずはNext.jsリポジトリの中にあるexamples/を取得します。

公式Next.jsリポジトリから
git clone https://github.com/vercel/next.js.git
Next.jsの公式リポジトリからNext.js本体をgit cloneします。
もしくはgithubのDownload ZIP機能でローカルフォルダに保存します。

git cloneした、もしくはダウンロードしたzipファイルを解凍したフォルダの中にexamples/フォルダがありますので取り出します。

[nextjs-examples]というexamplesを管理するフォルダを作ってこの中に保存します。
( []内の名前は自由に変更可能です。)

現在のフォルダ構造

[nextjs-examples]/
  └ examples/
    ├ [exampleA]/
    ├ [exampleB]/
    └ [exampleC]/

[nextjs-examples]/はルートフォルダになります。

[nextjs-examples]/をVSCodeで開きます。
ターミナルから
yarn init --yes --private
を実行します。

package.jsonが出来ます。

package.json
{
  "name": "nextjs-examples",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "private": true
}

※privateはtrueにする必要があります。

現在のフォルダ構造

[nextjs-examples]/
  ├ examples/
  │   ├ [exampleA]/
  │   ├ [exampleB]/
  │   └ [exampleC]/
  ├ node_modules/
  └ package.json
  └ yarn.lock

最初の一つをインストールする

まずは、examplesの中でNext.jsを初めて触るのに手頃な「basic-export」をインストールしてみます。

package.jsonを開きます。
"workspaces"を追記して、その中に
インストールする"examples/basic-export"を書きます。

package.json
{
  "name": "nextjs-examples",
  "version": "0.1.0",
  "main": "index.js",
  "license": "MIT",
  "private": true,
  "workspaces": [
    "examples/basic-export"
  ]
}

インストールするexampleを決めたらルートでyarnもしくはyarn installを実行します。
最初なので数分かかると思います。

インストール完了後に、

cd examples/basic-export
yarn dev
これでbasic-exportがサーバーで起動し、

http://localhost:3000/で実行されているのが確認できます。

サーバーの起動を停止して(Ctrl+C)
次のサンプルをインストールしてみます。

cd ../..
(ルート[nextjs-examples]/)
に戻ります。

examplesの「basic-css」と「dynamic-routing」の2つを追加してみます。

package.json
{
  "name": "nextjs-examples",
  "version": "0.2.0",
  "main": "index.js",
  "license": "MIT",
  "private": true,
  "workspaces": [
    "examples/basic-export",
    "examples/basic-css",
    "examples/dynamic-routing"
  ]
}

ルートフォルダに戻り
(ルート[nextjs-examples]/)
yarn or yarn install を実行してみます。。

Done in 6.78s.でインストールが完了しました、早いですね。

それぞれのサブフォルダに移動してyarn devを実行してみます。
3つとも動くのが確認できました。

では次に、「Next.jsの基礎1易しい」を全部インストールしてみましょう。

package.json
{
  "name": "nextjs-examples",
  "version": "0.3.0",
  "main": "index.js",
  "license": "MIT",
  "private": true,
  "workspaces": [
    "examples/basic-export",
    "examples/basic-css",
    "examples/dynamic-routing",
    "examples/environment-variables",
    "examples/head-elements",
    "examples/hello-world",
    "examples/layout-component",
    "examples/nested-components",
    "examples/using-router",
    "examples/with-app-layout",
    "examples/with-loading"
  ]
}


ルートフォルダに戻り ([nextjs-examples]/)
yarn or yarn install を実行してみます。
Done in 3.71s.でインストールが完了しました。
インストールするものがほぼありませんので一瞬で終わりましたね。

全部の動作確認はしていませんが、
エラーなども特に出ていないので、
一気にNext.jsの基礎2普通を全部インストールしてみましょう。

package.json
{
  "name": "nextjs-examples",
  "version": "0.4.0",
  "main": "index.js",
  "license": "MIT",
  "private": true,
  "workspaces": [
    "examples/basic-export",
    "examples/basic-css",
    "examples/dynamic-routing",
    "examples/environment-variables",
    "examples/head-elements",
    "examples/hello-world",
    "examples/layout-component",
    "examples/nested-components",
    "examples/using-router",
    "examples/with-app-layout",
    "examples/with-loading",
    "examples/active-class-name",
    "examples/catch-all-routes",
    "examples/data-fetch",
    "examples/gh-pages",
    "examples/progressive-render",
    "examples/ssr-caching",
    "examples/with-absolute-imports",
    "examples/with-context-api",
    "examples/with-dynamic-app-layout",
    "examples/with-dynamic-import",
    "examples/with-env-from-next-config-js",
    "examples/with-http2",
    "examples/with-next-page-transitions",
    "examples/with-prefetching",
    "examples/with-react-helmet",
    "examples/with-shallow-routing",
    "examples/with-static-export",
    "examples/with-typescript-eslint-jest",
    "examples/with-typescript-types",
    "examples/with-typescript",
    "examples/with-zones"
  ]
}

Done in 165.56s.でインストールが完了しました
「typescript」等が追加されているので少し時間がかかりました。

14個ものexampleを追加インストールしたのに、こんな短時間でインストールが完了しました。
このようにyarn workspaces機能を使うことで最初の一個以外残りはほぼ時間をかけることなくインストールが出来ました。

追記用全リスト

Next.jsの基礎2普通
"examples/active-class-name",
"examples/catch-all-routes",
"examples/data-fetch",
"examples/gh-pages",
"examples/progressive-render",
"examples/ssr-caching",
"examples/with-absolute-imports",
"examples/with-context-api",
"examples/with-dynamic-app-layout",
"examples/with-dynamic-import",
"examples/with-env-from-next-config-js",
"examples/with-http2
"examples/with-next-page-transitions",
"examples/with-prefetching",
"examples/with-react-helmet",
"examples/with-shallow-routing",
"examples/with-static-export",
"examples/with-typescript-eslint-jest",
"examples/with-typescript-types",
"examples/with-typescript",
"examples/with-zones"

Next.jsの基礎3 2021年1月版追加分
"examples/fast-refresh-demo",
"examples/redirects",
"examples/rewrites"

pwa関連
"examples/progressive-web-app"

UI関連ant",
"examples/with-ant-design-less",
"examples/with-ant-design-mobile",
"examples/with-ant-design-pro-layout-less",
"examples/with-ant-design"

UI関連その他
"examples/with-chakra-ui-typescript",
"examples/with-ionic-typescript",
"examples/with-mdbreact",
"examples/with-atlaskit",
"examples/with-chakra-ui",
"examples/with-grommet",
"examples/with-material-ui",
"examples/with-patternfly",
"examples/with-rebass"

Firebase関連
"examples/with-supabase-auth-realtime-db",
"examples/with-firebase-authentication",
"examples/with-firebase-cloud-messaging",
"examples/with-firebase-hosting",
"examples/with-firebase"

API Routes編
"examples/api-routes-cors",
"examples/api-routes-middleware",
"examples/api-routes-rest",
"examples/api-routes"

API Routes編 GraphQL関連
"examples/api-routes-graphql",
"examples/with-graphql-faunadb",
"examples/with-graphql-hooks",
"examples/with-graphql-react",
"examples/with-react-relay-network-modern",
"examples/with-reason-relay",
"examples/with-relay-modern",
"examples/with-typescript-graphql",
"examples/with-urql"

API Routes編 apollo関連
"examples/api-routes-rate-limit",
"examples/with-apollo-neo4j-graphql",
"examples/api-routes-apollo-server-and-client-auth",
"examples/api-routes-apollo-server-and-client",
"examples/api-routes-apollo-server",
"examples/with-apollo-and-redux",
"examples/with-apollo"

DB関連 prisma編
"examples/with-prisma"

DB関連 mysql編
"examples/with-mysql"

DB関連 その他
"examples/with-deta-base",
"examples/with-knex",
"examples/with-mongodb",
"examples/with-neo4j",
"examples/with-redis",
"examples/with-mongodb-mongoose",
"examples/with-realm-web"

コンポーネント関連
"examples/with-carbon-components",
server関連
"examples/custom-server-actionhero",
"examples/custom-server-express",
"examples/custom-server-fastify",
"examples/custom-server-hapi",
"examples/custom-server-koa",
"examples/custom-server-polka",
"examples/custom-server-typescript",
"examples/custom-server",
storybook関連
"examples/with-storybook-styled-jsx-scss",
"examples/with-storybook"

検索関連
"examples/with-algolia-react-instantsearch"

監視関連
"examples/with-sentry"

リッチテキスト関連
"examples/with-draft-js",
"examples/with-quill-js",
"examples/with-slate"

認証関連
"examples/auth0
"examples/with-cookie-auth-fauna",
"examples/with-iron-session",
"examples/with-magic",
"examples/with-next-auth",
"examples/with-passport-and-next-connect",
"examples/with-passport",
"examples/with-userbase"

CSS関連 tailwindcss編
"examples/with-tailwindcss-emotion",
"examples/with-tailwindcss"

CSS関連 styled-jsx編
"examples/with-styled-jsx",
"examples/with-styled-jsx-plugins",
"examples/with-styled-jsx-scss"

CSS関連 その他
"examples/with-cssed",
"examples/with-react-md-typescript",
"examples/with-reactstrap",
"examples/with-aphrodite",
"examples/with-astroturf",
"examples/with-cxs",
"examples/with-emotion",
"examples/with-fela",
"examples/with-filbert",
"examples/with-glamor",
"examples/with-goober",
"examples/with-linaria",
"examples/with-next-css",
"examples/with-next-less",
"examples/with-next-sass",
"examples/with-rbx-bulma-pro",
"examples/with-react-bootstrap",
"examples/with-react-jss",
"examples/with-react-md",
"examples/with-react-with-styles",
"examples/with-semantic-ui",
"examples/with-stitches",
"examples/with-style-sheet",
"examples/with-styled-components-rtl",
"examples/with-styled-components",
"examples/with-styletron",
"examples/with-typescript-styled-components",
"examples/with-typestyle"

状態管理redux関連
"examples/with-redux-code-splitting",
"examples/with-redux-observable",
"examples/with-redux-persist",
"examples/with-redux-saga",
"examples/with-redux-thunk",
"examples/with-redux-toolkit",
"examples/with-redux-wrapper",
"examples/with-redux",
"examples/with-rematch"

状態管理その他
"examples/with-zustand",
"examples/with-kea",
"examples/with-mobx-react-lite",
"examples/with-mobx-state-tree-typescript",
"examples/with-mobx-state-tree",
"examples/with-mobx",
"examples/with-overmind",
"examples/with-recoil",
"examples/with-unstated",
"examples/amp関連
"examples/amp-first",
"examples/amp-story",
"examples/amp"

国際化
"examples/i18n-routing",
"examples/with-i18n-rosetta",
"examples/with-lingui",
"examples/with-next-i18next",
"examples/with-next-translate",
"examples/with-react-intl"

AWS関連
"examples/with-aws-amplify-typescript",
"examples/with-aws-amplify"

テスト関連
"examples/with-jest",
"examples/with-mocha",
"examples/with-tesfy"

システム関連 webpack bundle babel",
"examples/analyze-bundles",
"examples/with-babel-macros",
"examples/with-custom-babel-config",
"examples/with-webpack-bundle-size-analyzer"

cms関連
"examples/cms-kontent",
"examples/blog-starter-typescript",
"examples/blog-starter",
"examples/cms-agilitycms",
"examples/cms-buttercms",
"examples/cms-contentful",
"examples/cms-cosmic",
"examples/cms-datocms",
"examples/cms-graphcms",
"examples/cms-prismic",
"examples/cms-sanity",
"examples/cms-storyblok",
"examples/cms-strapi",
"examples/cms-takeshape",
"examples/cms-wordpress",
"examples/with-netlify-cms"

デスクトップアプリケーション関連
"examples/with-electron-typescript",
"examples/with-electron"

mdx関連
"examples/with-mdx-remote",
"examples/with-mdx"

google関連
"examples/with-google-tag-manager",
"examples/with-google-analytics-amp",
"examples/with-google-analytics",
"examples/with-react-ga"

preact関連
"examples/using-preact"

サイトマップ関連
"examples/with-next-sitemap",
"examples/with-sitemap"

既存プロジェクトからの移行関連
"examples/custom-routes-proxying"

docker関連
"examples/with-docker"

画像関連
"examples/image-component",
"examples/with-unsplash",
"examples/svg-components",
"examples/with-three-js"

動画関連
"examples/with-hls-js",
"examples/with-mux-video",
"examples/with-videojs"

アニメーション関連
"examples/with-gsap",
"examples/with-framer-motion"

moved、removed、非推奨、廃止
"examples/page-transitions",
"examples/parameterized-routing",
"examples/with-cookie-auth",
"examples/with-dotenv",
"examples/with-firebase-authentication-serverless",
"examples/with-glamorous",
"examples/with-global-stylesheet-simple",
"examples/with-global-stylesheet",
"examples/with-markdown",
"examples/with-next-routes",
"examples/with-now-env",
"examples/with-pretty-url-routing",
"examples/with-sentry-simple",
"examples/with-strict-csp-hash",
"examples/with-styled-jsx-postcss",
"examples/with-sw-precache",
"examples/with-universal-configuration-build-time",
"examples/with-universal-configuration-runtime",
"examples/with-webpack-bundle-analyzer"

古い、数年更新がない
"examples/with-reflux"

その他
"examples/with-facebook-pixel",
"examples/with-mqtt-js",
"examples/with-msw",
"examples/with-paste-typescript",
"examples/with-portals-ssr",
"examples/with-portals",
"examples/with-service-worker",
"examples/with-cerebral",
"examples/with-custom-reverse-proxy",
"examples/with-expo-typescript",
"examples/with-expo",
"examples/with-flow",
"examples/with-monaco-editor",
"examples/with-next-offline",
"examples/with-next-seo",
"examples/with-orbit-components",
"examples/with-polyfills",
"examples/with-react-multi-carousel",
"examples/with-react-native-web",
"examples/with-react-toolbox",
"examples/with-reasonml-todo",
"examples/with-reasonml",
"examples/with-route-as-modal",
"examples/with-segment-analytics",
"examples/with-stencil",
"examples/with-stomp",
"examples/with-strict-csp",
"examples/with-stripe-typescript",
"examples/with-web-worker",
"examples/with-webassembly",
"examples/with-why-did-you-render",
"examples/with-xstate",
"examples/with-yarn-workspaces",
"examples/with-zeit-fetch"

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