react-router のミニマルな形 (TypeScript)

● react-router のミニマルな形 (TypeScript)

● react アプリの作成

npx create-react-app my-app --template typescript

● react-router

yarn add react-router-dom
yarn add @types/react-router-dom

index.tsx

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';

import { BrowserRouter, Routes, Route } from "react-router-dom";
import About from "./routes/about";

ReactDOM.render(
  <React.StrictMode>
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<App />} />
        <Route path="about" element={<About />} />
      </Routes>
    </BrowserRouter>
  </React.StrictMode>,
  document.getElementById('root')
);

reportWebVitals();

App.tsx

import React from 'react';
import logo from './logo.svg';
import './App.css';
import { Link } from "react-router-dom";

function App() {
  return (
    <div>
      <h1>My-App Hello!</h1>
      <nav>
        <Link to="/about">About</Link> |{" "}
        <Link to="/contact">Contact</Link>
      </nav>
    </div>
  );
}

export default App;

about.tsx


export default function About() {
  return (
    <main style={{ padding: "1rem 0" }}>
      <h2>About</h2>
    </main>
  );
}
No.2107
12/02 16:46

edit

TypeScript

Reactの関数コンポーネントで親コンポーネントから子コンポーネントの関数を実行する

● Reactの関数コンポーネントで親コンポーネントから子コンポーネントの関数を実行する

forwardRef , useImperativeHandle を使います

import React, { useImperativeHandle, forwardRef, useRef } from "react";

https://ja.reactjs.org/docs/hooks-reference.html#useimperativehandle

useImperativeHandle は forwardRef と組み合わせて使います:

● 子コンポーネントで関数 showAlert() を登録

1. メソッドの追加

import { useImperativeHandle, forwardRef } from "react";
    useImperativeHandle(
        ref,
        () => ({
            showAlert() {
                alert("Child Function Called")
            }
        }),
    )

2. refを受け取れるようにする

const MyChildComponent = (props) => {

      ↓

const MyChildComponent = (props, ref) => {
export default EcosModal;

      ↓

export default forwardRef(EcosModal);

● 親コンポーネントで ref を渡す

import { useRef } from "react";
const childRef = useRef();
<MyChildComponent
    ref={childRef}
/>

後は親コンポーネントの好きなところから関数を呼ぶことができます

<button type="button"
    onClick={ () => { childRef.current.showAlert() }}
>

関数コンポーネントはクラスとどう違うのか? — Overreacted

● useImperativeHandle を async で使用したい

子コンポーネントのuseImperativeHandle を次のようにします。

    useImperativeHandle(
        ref,
        () => (
            {
                showAlert:  async function(){ await showAlert(); } ,
            }
        )
    )

また showAlert() 関数にも async をつけておきます

No.2093
11/02 09:24

edit

Next.js の ビルド先ディレクトリ「.next」を変更する / ビルド先ディレクトリをシェルから変更する

● Next.js の ビルド先ディレクトリ「.next」を変更する

next.config.js

module.exports = {
  distDir: '.next',
}

● Next.js の ビルド先ディレクトリをシェルから変更する

シェルから環境設定をセットすると process.env で読み取ることができます

シェルコマンド

export NEXTJS_BUILD_DIST=.tmp_next

next.config.js

( NEXTJS_BUILD_DISTが設定してある場合はそのディレクトリをセット。 設定されてない場合はデフォルトの .next をセット )

module.exports = {
  distDir: process.env.NEXTJS_BUILD_DIST ? process.env.NEXTJS_BUILD_DIST : '.next',
}

シェルから環境変数を削除するには次のようにします

export -n NEXTJS_BUILD_DIST
No.2090
10/28 09:15

edit

Next.js の 環境設定ファイル(.env)と サーバーサイド・クライアントサイドの判別

● Next.js の 環境設定ファイル(.env)

使うのは以下の2ファイルに限定すると良いでしょう。

.env.development : 開発用ファイル

NODE_ENV が development ( = npm run dev )の時に読み込まれる。

.env.production : 本番用ファイル

NODE_ENV が production ( = npm run build && npm run start )の時に読み込まれる。

● .envファイルの書き方と呼び出し方

書き方(サーバーサイド)
( .env.development または .env.production)

HOGE=mySettingValue

呼び出し方(サーバーサイド)
( xxx.js や xxx.ts ファイル )

console.log( process.env.HOGE );

書き方(フロントエンド)
( .env.development または .env.production)

NEXT_PUBLIC_HOGE=mySettingValue

呼び出し方(フロントエンド)
( xxx.js や xxx.ts ファイル )

console.log( process.env.HOGE );
alert( process.env.HOGE );

● 現在「開発用」か「本番用」かどちらが読み込まれているのかをチェックする

NODE_ENV で判断すると良いでしょう

console.log( process.env.NODE_ENV );

● 現在「サーバーサイド」か「フロントエンド」かを判別する

typeof window === "undefined"

windowオブジェクトがないのがサーバーサイド
windowオブジェクトがあるのがフロントエンド
です。

デバッグ用にサーバーがクライアントを返したい場合はメソッドにしておいても良いかもです

export default function ServerOfClient() {
  return (typeof window === "undefined") ? 'Server' : 'Client';
}

Booleanの場合はそのまま利用しても良いですし以下のようにしても良いです

const isProduction = process.env.NODE_ENV === "production";

● envの値を確認するサンプル

  console.error(`● process.env.APOLLO_FETCH_POLICY は (${process.env.APOLLO_FETCH_POLICY}) / NODE_ENVは(${process.env.NODE_ENV}) / Server or Client は(${ServerOfClient()})`);

結果例

● process.env.APOLLO_FETCH_POLICY は (network-only-S) / NODE_ENVは(development) / Server or Client は(Server)

● .envファイルを書き換えたのに値が更新されない時は?

control + c でいちどプロセスを終了してから再度起動します
npm run dev
No.2088
10/28 09:01

edit

Next.js を nginx にデプロイする

● Next.js を nginx にデプロイする

Next.js とphpを使用できるように下記の仕様とします

「/php/<ファイル名>でアクセスした場合」→  /home/YOUR/SERVER/PATH/DocumentRoot/php/<ファイル名>を返す
「/でアクセスした場合」→  next.jsを返す  
	location /php/ {
	    alias  /home/YOUR/SERVER/PATH/DocumentRoot/php/;
	    index  index.html index.htm;
	}

	location / {
      	# Next.js Server
      	proxy_pass http://localhost:3000;
	}
No.2086
10/25 13:50

edit

Next.js で 任意のdivの高さを 100% にする ( height:100% )

● Next.js で 任意のdivの高さを 100% にする ( height:100% )

const FullHeightPage = () => (
  <div>
    Hello World!
    <style global jsx>{`
      html,
      body,
      body > div:first-child,
      div#__next,
      div#__next > div {
        height: 100%;
      }
    `}</style>
  </div>
)
No.2085
10/22 10:55

edit

Next.js で GraphQL クライアント Apolloクライアントを使用する

● 1. サンプルの「GraphQLクエリ」と「結果」を確認しておく

URL
http://snowtooth.moonhighway.com/

エンドポイントURL

https://countries.trevorblades.com

GraphQLクエリ

query {
  countries{
    code
    name
    emoji
  }
}

こちらの「エンドポイントURL」「GraphQLクエリ」を入力して ▶︎のボタンをクリックするとGraphQLクエリーが実行されます


● 2. apolloクライアントのインストール

開発しているアプリケーションの一番上の階層からnpmでインストールします

npm install @apollo/client graphql

● 3. apolloクライアントクラスの作成

apollo-client.js

import { ApolloClient, InMemoryCache } from "@apollo/client";

const client = new ApolloClient({
  uri: 'https://countries.trevorblades.com',            // 今は直接設定していますが .env から参照しましょう。
  cache: new InMemoryCache(),
});

export default client;

● 4. GraphQLから取り込んだデータを表示したいコンポーネントで次のように追加する

/pages/index.js

import { gql } from "@apollo/client";
import client from "../apollo-client";

SSG (Static Site Generation)用の getStaticProps() 関数を作成する
/pages/index.js

// getStaticProps ( for SSG (Static Site Generation) )
export async function getStaticProps() {
  const { data } = await client.query({
    query: gql`

query {
  countries{
    code
    name
    emoji
  }
}


    `,
  });
  return {
    props: {
      countries: data.countries.slice(0, 4),
    },
 };
}

/pages/index.js の JSXで表示する

export default function Home({ countries }) {
      {countries.map((v) => (
        <div key={v.code} style={{ display:'flex' }}>
          <h1 style={{ lineHeight:'100px' }}>{v.name}</h1>
          <div style={{ fontSize:'100px' }}>
            {v.emoji}
          </div>
        </div>
      ))}

これで該当ページを表示すると次のような表示となります

以上です。


● VS Code の拡張機能「Apollo GraphQL」のインストールして開発速度をアップさせる

https://marketplace.visualstudio.com/items?itemName=apollographql.vscode-apollo

[GraphQL] TypeScript+VSCode+Apolloで最高のDXを手に入れよう | DevelopersIO


● GraphQL Playground for Chrome

https://chrome.google.com/webstore/detail/graphql-playground-for-ch/kjhjcgclphafojaeeickcokfbhlegecd/related?hl=ja


● Apollo Client Devtools for Chrome

https://chrome.google.com/webstore/detail/apollo-client-devtools/jdkknkkbebbapilgoeccciglkfbmbnfm/related

Google Chromeの拡張機能 Apollo Client Devtools でできること(引用 : https://bit.ly/3pmP4je

– GraphiQLをその場で実行する(本来であればAPIサーバと別のポートでGraphiQLサーバを立ち上げて、ブラウザでそこにアクセスして利用します)
– JavaScriptから発行されたクエリのログの確認、クエリの編集・再発行
– apollo-link-stateでキャッシュに書き込んだ値の確認(apolloはクエリのレスポンスを勝手にキャッシュしてくれるのですが、その内容も確認できます)

初めて Apollo Client を使うことになったらキャッシュについて知るべきこと - WASD TECH BLOG

・取得するフィールドに id は必ず含める
・更新処理のときは Mutation のレスポンスでオブジェクトのキャッシュを更新する
・作成、削除処理のときは refetchQueries などを使い配列のキャッシュを更新する
・画面表示のたびに最新のデータを表示したければ fetchPolicy: "cache-and-network" を使う

fetchPolicy の種類

https://www.apollographql.com/docs/react/data/queries/

Name Description
cache-first

Apollo Client first executes the query against the cache. If all requested data is present in the cache, that data is returned. Otherwise, Apollo Client executes the query against your GraphQL server and returns that data after caching it.

Prioritizes minimizing the number of network requests sent by your application.

This is the default fetch policy.

cache-only

Apollo Client executes the query only against the cache. It never queries your server in this case.

A cache-only query throws an error if the cache does not contain data for all requested fields.

cache-and-network

Apollo Client executes the full query against both the cache and your GraphQL server. The query automatically updates if the result of the server-side query modifies cached fields.

Provides a fast response while also helping to keep cached data consistent with server data.

network-only

Apollo Client executes the full query against your GraphQL server, without first checking the cache. The query's result is stored in the cache.

Prioritizes consistency with server data, but can't provide a near-instantaneous response when cached data is available.

no-cache

Similar to network-only, except the query's result is not stored in the cache.

standby

Uses the same logic as cache-first, except this query does not automatically update when underlying field values change. You can still manually update this query with refetch and updateQueries.

参考 : ApolloのFetchPoliciesを理解する - Qiita

添付ファイル1
No.2084
10/27 14:13

edit

添付ファイル

ReactのJSX内で string の style を扱う

● ReactのJSX内で string の style を扱う

helpers/stringHelper.js

export const getStyleObjectFromString = str => {
  if (!str) { return {}; }
  const style = {};
  str.split(";").forEach(el => {
    const [property, value] = el.split(":");
    if (!property) return;

    const formattedProperty = formatStringToCamelCase(property.trim());
    style[formattedProperty] = value.trim();
  });
  return style;
};

コンポーネントで使用する

import { getStyleObjectFromString } from "helpers/stringHelper";
      return (
          <div
            style={getStyleObjectFromString("color:red; margin:20px; font-weight:bold;")}
          />
      )
No.2083
10/26 13:14

edit

Next.js で YAMLファイルを使用する

● Next.js で YAMLファイルを使用する

js-yaml-loaderのインストール

npm install js-yaml-loader

next.config.js に以下を設定

module.exports = {
 webpack: function (config) {
   config.module.rules.push(
     {
       test: /\.ya?ml$/,
       use: 'js-yaml-loader',
     },
   )
   return config
 }
}

使用する

import useryml from 'user.yml';
  console.log( '● useryml' );
  console.log( useryml );
No.2082
10/19 22:23

edit

VS Code の「F5」キーで Next.js のデバッグを行う

● VS Code の「F5」キーで Next.js のデバッグを行う

Next.JSのVS Code を使ったデバッグは次の2ステップのみでとても簡単に行うことができます

・1. ローカルサーバーを起動する

VS Codeの
「エクスプローラー」→「NPMスクリプト」 →「dev」の横の ▶︎ をクリックしてローカルサーバーを起動する。

・2. 「F5」をクリックしてデバッガーを起動する

最初に launch.json があるかどうかのチェックが行われ、まだない場合は作成を促されるので作成します。 launch.json を以下の内容で保存します

{
    "version": "0.2.0",
    "configurations": [
      {
        "name": "Next.js: debug server-side",
        "type": "node-terminal",
        "request": "launch",
        "command": "npm run dev"
      },
      {
        "name": "Next.js: debug client-side",
        "type": "pwa-chrome",
        "request": "launch",
        "url": "http://localhost:3000"
      },
      {
        "name": "Next.js: debug full stack",
        "type": "node-terminal",
        "request": "launch",
        "command": "npm run dev",
        "console": "integratedTerminal",
        "serverReadyAction": {
          "pattern": "started server on .+, url: (https?://.+)",
          "uriFormat": "%s",
          "action": "debugWithChrome"
        }
      }
    ]
  }

この設定ファイルでは

Next.js: debug client-side
Next.js: debug server-side
Next.js: debug full stack

と言う3つのデバッグを定義していますので「Next.js: debug client-side」を選択肢で起動します。(クライアントアプリをデバッグしたい場合)

これだけでokです。
後は「F5」でデバッグを起動「shift+F5」デバッグを終了 のお決まりのキーボード操作をしてください

No.2081
11/22 09:53

edit

Next.js で import の相対パスのルートディレクトリを変更(固定)してルートからの絶対パスで記述する

● Next.js で import の相対パスのルートディレクトリを変更(固定)してルートからの絶対パスで記述する

jsconfig.json (プロジェクトトップディレクトリにこのファイルがない場合は新規で作成します)

{
  "compilerOptions": {
    // import時のパスのルートを設定
    "baseUrl": "."
  },
  "include": ["**/*.js", "**/*.jsx"]
}

VS Codeの「F12」てのファイル移動も有効です

No.2080
11/02 09:04

edit

Next.js アプリの初期化

● Next.js アプリの初期化(JavaScript)

npx create-next-app@latest  my-app

● Next.js アプリの初期化(TypeScript)

npx create-next-app@latest --ts my-app

● Next.js アプリの初期化(JavaScript + TailWind CSS を追加)

npx create-next-app -e with-tailwindcss my-project

-e オプションはこちらのリポジトリからデータを持ってきます https://github.com/vercel/next.js/tree/master/examples

● Next.js アプリの初期化(TypeScript + TailWind CSS を追加)

公式のリポジトリにサンプルがないためまずTypeScriptでアプリを作成してその後にTailWindを追加します

・1. Next.js アプリの初期化(TypeScript)

npx create-next-app@latest --ts my-app

・2. TailWindのインストールと設定ファイルの初期化

cd my-app
npm install -D tailwindcss@latest postcss@latest autoprefixer@latest
npx tailwindcss init -p

・3. tailwind.config.js に mode と purge を追記する

module.exports = {
  mode: 'jit',
  purge: ['./pages/**/*.{js,ts,jsx,tsx}', './components/**/*.{js,ts,jsx,tsx}'],
  darkMode: false, // or 'media' or 'class'
  theme: {
    extend: {},
  },
  variants: {
    extend: {},
  },
  plugins: [],
}

・4. tailwindを _app.ts から読み込む

import 'tailwindcss/tailwind.css';

・5. index.tsx の JSXを試しに以下のようにする

  return (
    <div className="text-red-500 text-4xl sm:text-6xl lg:text-7xl leading-none font-extrabold tracking-tight mt-10 mb-8 sm:mt-14 sm:mb-10">テストです</div>
  )

● VS Code の IntelliSense for CSS class names in HTML が重い場合

IntelliSense for CSS class names in HTML を無効にしましょう
No.2070
10/13 20:38

edit

React Hook Formでフォームを作成する ( + Yup )

● 1. React Hook Formのインストール

npm install react-hook-form

● 2. React Hook Formを使用する

import { useForm } from 'react-hook-form';
    // React Hook Form
    const {
        register,
        handleSubmit,
        formState: { errors },
    } = useForm();
    const onSubmit = (data) => console.log(data);

useForm() には様々なオプションを渡すことができます

https://react-hook-form.com/api/useform/

useForm({
  mode: 'onSubmit',
  reValidateMode: 'onChange',
  defaultValues: {},
  resolver: undefined,
  context: undefined,
  criteriaMode: "firstError",
  shouldFocusError: true,
  shouldUnregister: false,
  shouldUseNativeValidation: false,
  delayError: undefined
})

例1: 会社名を入力するフォームに「入力必須」「入力文字数4文字以上」のバリデーションを設定します

return (
    <form onSubmit={handleSubmit(onSubmit)}>
        <input {...register('company', { required: true, minLength: 4 })} placeholder="株式会社○○" />
        {errors.company?.type === "required" && <div className="err_message" id="company_err">会社名は必須です</div>}
        {errors.company?.type === "minLength" && <div className="err_message" id="company_err">会社名は4文字以上を入力してください</div>}

        <input type="submit" />
    </form>
);

例2: 次のように「チェック内容」と「エラーメッセージ」をまとめて記述することもできます

    <input type="email" placeholder="user@server.xxx"
        {...register("email", {
            required: "入力必須です",
            pattern: {
            value: /\S+@\S+\.\S+/,
            message: "メールアドレスが不完全です"
            }
        })}
    />
    {errors.email && <div className="err_message">{errors.email.message}</div>}

● 3. フォーム入力値のバリデーションの記述と種類

https://react-hook-form.com/jp/api#register

● 4. React Hook Form + Yup を使用する

バリデーションの記述をYupでまとめるには次のように記述します

npm install @hookform/resolvers yup
import { yupResolver } from '@hookform/resolvers/yup';
import * as Yup from 'yup';
  const validationSchema = Yup.object().shape({
    firstName: Yup.string()
      .required('First Name は必須です'),
    lastName: Yup.string()
      .required('Last Name は必須です'),
  });

  const formOptions = { resolver: yupResolver(validationSchema) };

  const { register, handleSubmit, reset, formState } = useForm(formOptions);
  const { errors } = formState;
<input name="firstName" type="text" {...register('firstName')} className={`form-control ${errors.firstName ? 'is-invalid' : ''}`} />
<div className="invalid-feedback">{errors.firstName?.message}</div>

● その他参考になるサイト

https://bit.ly/3oSjgm9

No.2068
10/27 14:28

edit

React で登場する ... (3点リーダー)(ドット3つ)の使い方

● React で登場する ... (3点リーダー)(ドット3つ)(JSX Spread Attributes)の使い方

これは JSX Spread Attributes といって JSXでの記法です。 意味としては以下のコードと同じ意味合いとなります。

const props = { foo: "foo", bar: "bar" };
render() {
  return <Child foo={props.foo} bar={props.bar} />
}

       ↓

const props = { foo: "foo", bar: "bar" };
render() {
  return <Child {...props} />
}

● なぜ JSX Spread Attributes を利用するのか?

子コンポーネントに渡したい値に変更があった場合に変更箇所が少なくて済みます。

props に hogee を追加する場合でも提示する箇所のみの変更でokです。

const props = { foo: "foo", bar: "bar", hoge:"hoge" };
render() {
  return <Child {...props} />
}
No.2067
10/12 09:03

edit

Next.js のコンポーネントが 「サーバー」/「クライアント」どちらで動いているかを調べる

● Next.js のコンポーネントが 「サーバー」/「クライアント」どちらで動いているかを調べる

引用 : https://maku.blog/p/m7is4dn/

windowオブジェクトはクライアント(WEBブラウザ)で動作している時のみ存在するのでこれを調べると言う方法です

const isClient = () => typeof window !== 'undefined'
// const isServer = () => typeof window === 'undefined'

const HelloPage: FC = () => {
  if (isClient()) {
    console.log('これはクライアントサイド JS として実行されているよ!')
    console.log(window.location)
    alert('だから alert も使えるよ!')
  }
  return <h1>Hello</h1>
}
No.2066
10/08 11:09

edit

Next.jsで改行コードを改行タグに変換(nl2br)する

● Next.jsで改行コードを改行タグに変換(nl2br)する

npm install react-nl2br -S
const nl2br = require('react-nl2br');

jsxで以下のように記述します
my_textに入っている文字列の改行コードをbrタグに変換します

return(
    <div>
        { nl2br(my_text) }
    </div>
);
No.2065
10/08 09:33

edit

Next.js で日付をフォーマットする

● moment.js の次世代のパッケージ date-fns をインストールする

次世代のパッケージ date-fns をインストールします

npm install date-fns

● 使用する

import { parseISO, format } from 'date-fns'
import ja from 'date-fns/locale/ja'
console.log( format(new Date(), 'yyyy-MM-dd (EEEE) HH:mm:ss', {locale:ja}) );

結果

2021-10-08 (金曜日) 10:09:21

● jsxで使用する

// date-fns
function Date({ dateString }) {
 return <time dateTime={dateString}>{format(parseISO(dateString), 'yyyy.MM.dd (EEEE)', {locale:ja} )}</time>
};
<Date dateString={my_date} />
No.2064
11/01 09:59

edit

Next.js で font awesomeなどのアイコンフォントを使用する

● React Icons インストール

npm install react-icons --save

● コンポーネント内で呼び出して使用する

Mycompoenent.js

import { FaGithub } from "react-icons/fa"

function MyComponent() {
  return (
    <div>
        <FaGithub />
    </div>
  )
}

● 使用したいアイコンを検索する

https://react-icons.github.io/react-icons/search?q=cart

No.2063
10/07 15:04

edit

Next.js で SWR を使用する

● SWR を使用する

・1. swrのインストール

npm i swr -S

・2. fetcherの定義

import useSWR from 'swr'
const fetcher = (url) => fetch( url )
  .then(res => res.json());

・3. NewsIndexコンポーネントの作成

function NewsIndex() {
  const { data, error } = useSWR('https://YOUR/SERVER/PATH/api/news/', fetcher)
    // swrによるfetchエラー時
  if (error) return <div>failed to load</div>
  // swrによるfetchロード中
  if (!data) return <div>now loading...</div>
  return (
    <ul>
    {data.map((v) => 
      <li key={v.id}>{v.id} : {v.name}</li>
    )}
  </ul>
  );
}

・4. NewsIndexコンポーネントの呼び出し

<div>
  <NewsIndex/>
</div>

これで URL「https://YOUR/SERVER/PATH/api/news/」が返す json (中身はコレクション)の id と name を一覧で表示します。

● SWRの自動再検証(自動再読込)について

デフォルトでは自動的に revalidate(再読込)処理が入っています。

revalidateIfStale = true: automatic revalidation on mount even if there is stale data (details)
revalidateOnMount: enable or disable automatic revalidation when component is mounted
revalidateOnFocus = true: automatically revalidate when window gets focused (details)
revalidateOnReconnect = true: automatically revalidate when the browser regains a network

公式 : https://swr.vercel.app/docs/options
参考 : https://bit.ly/3Aicc4w

● fetch と axios どちらを使用するか?

axios

const options = {
  url: 'http://localhost/test.htm',
  method: 'POST',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json;charset=UTF-8'
  },
  data: {
    a: 10,
    b: 20
  }
};

axios(options)
  .then(response => {
    console.log(response.status);
  });

fetch

const url = 'http://localhost/test.htm';
const options = {
  method: 'POST',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json;charset=UTF-8'
  },
  body: JSON.stringify({
    a: 10,
    b: 20
  })
};

fetch(url, options)
  .then(response => {
    console.log(response.status);
  });

引用 : https://bit.ly/3DkNoL0

【JS】Fetch API のResponse には気をつけて。axios とは違うぞ。。。 - 7839

No.2062
10/11 10:57

edit

React の if文、for文 in JSX

● (React の if文)論理演算子&& を利用する

例2: isAdmin == true の場合に 私は管理者ですと表示します。

{isAdmin && <div>私は管理者です</div>}

例2: 未ログインの場合に class="hidden" とします。

className={! isLogin && 'hidden'}>

● (React の if文)三項演算子を利用する

<div>
    {isLogin
        ? 'ログイン済み'
        : '未ログイン'
    }
</div>

● (React の for文)配列.map と 無名関数を利用する

const data = [
    { text: "hogehoge" },
    { text: "fugafuga" }
  ];
<ul>
  {data.map((v,i) => {
    return <li>{v.text} {i}番目</li>;
  })}
</ul>

i は 0から始まります

配列じゃないものが渡ってくる可能性がある場合は事前にチェックします

{Array.isArray( data ) &&
  data.map((v,i) => {
    return <li>{v.text} {i}番目</li>;
  })
}

Missing "key" prop for element in iterator のアラートが出る場合はkeyを渡します

<ul>
  {data.map((v) => {
    return <li key={v.id}>{v.text}</li>;
  })}
</ul>

また return と {} は省略できます。

      <ul>
      {data.map((v) => 
        <li key={v.id}>{v.name}</li>
      )}
    </ul>
No.2057
10/26 14:15

edit

React に Tailwind CSS を導入する

● React + Tailwind CSS のアプリを新規作成する

npx create-next-app next-tailwind -e with-tailwindcss

● Tailwind CSS のインストール

npm install -D tailwindcss@latest postcss@latest autoprefixer@latest

● Tailwind CSS の設定ファイルの作成

npx tailwindcss init -p

自動で tailwind.config.js , postcss.config.js の2ファイルが生成されます

tailwind.config.js

module.exports = {
  mode: 'jit',
  purge: ['./pages/**/*.{js,ts,jsx,tsx}', './components/**/*.{js,ts,jsx,tsx}'],
  darkMode: false, // or 'media' or 'class'
  theme: {
    extend: {},
  },
  variants: {
    extend: {},
  },
  plugins: [],
}
No.2056
10/01 15:34

edit

React hooksの概要 / useState / useEffect / useContext / useReducer / useCallback / useMemo / useRef

● 1. React hooks / useState()

useState() とは

「状態を持つ変数」と「更新する関数」を管理するReactフックです。
「状態を持つ変数」の値が変わると再レンダリングが起こります。

useState の宣言方法

import { useState } from "react";
    // const [変数, 変数を更新するための関数(setter アクセサ)] = useState(状態の初期値);
    // (例)変数 email / 更新する関数 setEmail() を宣言する
    const [email, setEmail] = useState("");
        <input
          type="email"
          value={email}
          onChange={e => setEmail(e.target.value)}
          placeholder="Email..."
        />

オブジェクトや配列に対して、useStateをどう使うか

const [member, setMember] = useState({ name: "", part: "" });

引用 : https://bit.ly/3nG3WHa


● 2. React hooks / useEffect()

useEffect() とは

useEffectを使うと、useEffectに渡された関数はレンダーの結果が画面に反映された後に動作します。( = componentDidMount() )
また便利なことに、useStateフックはマウント解除にも使用できます。( =componentWillUnmount()  )

useState の宣言方法

// 第1引数に「実行させたい副作用関数」を記述
// 第2引数に「副作用関数の実行タイミングを制御する依存データ」を記述
useEffect( [副作用関数], [依存する変数の配列]) 
useEffect(() => {
    console.log('useEffectが実行されました');
},[]);

// 第2引数を省略するとコンポーネントがレンダリングされるたび毎回実行されます。
// 第2引数に空の配列 [] を記述すると初回レンダリングのみ実行されます。

マウント解除時

const FunctionalComponent = () => {
 React.useEffect(() => {
   return () => {
     console.log("Bye");
   };
 }, []);
 return <h1>Bye, World</h1>;
};


● 3. React hooks / useContext()

useContext() とは

propsバケツリレーを使用することなく高い窓にまたがったコンポーネントで簡単にデータにアクセスするために使用します


● 4. React hooks / useReducer()

useReducer() とは

引用 : https://bit.ly/3uzQaJb

useReducer で setState 関連のロジックを閉じ込める
deleteItem メソッドは、配列のうち該当する index の item を削除するメソッドであるが、こういったロジックをどこに書くかをかなり悩んできた。結論としては useReducer 内にロジックを保持するパターンが、一番疎結合である。

引用: https://bit.ly/3BeyRQw

useReducerというAPIも登場しています。 useReducerはReduxにおけるReducerのような振る舞いをします。 

引用: https://bit.ly/2Yb49ZK

useReducer が生きるのは、複数の関連したステート、つまりオブジェクトをステートとして扱うときです。
useReducer は useState と似ている。
useState では「数値」、「文字列」、「論理値」を扱うことができるがそれを拡張して
useReducerでは「配列」、「オブジェクト」を扱えるようにする


● 5. React hooks / useCallback

useReducer() とは

useEffect の高速化のための手法
useCallbackはパフォーマンス向上のためのフックで、メモ化したコールバック関数を返します。
useEffectと同じように、依存配列(=[deps] コールバック関数が依存している要素が格納された配列)の要素のいずれかが変化した場合のみ、メモ化した値を再計算します。


● 6. React hooks / useMemo


● 7. React hooks / useRef

useRef() とは

関数コンポーネントでは、Classコンポーネント時のref属性の代わりに、useRefを使って要素への参照を行います。

useStateを利用している場合はstateの変更される度にコンポーネントの再レンダリングが発生しますが、
useRefは値が変更になっても、コンポーネントの再レンダリングは発生しません。

コンポーネントの再レンダリングはしたくないけど、内部に保持している値だけを更新したい場合は、保持したい値をuseStateではなく、useRefを利用するのが良さそうです。

引用: https://bit.ly/3zXdqC2

No.2055
10/29 14:35

edit

Next.js + Firebase で Googleログインのテスト

● Next.js + Firebase で Googleログインのテスト


● Next.js アプリの初期化と実行

1-1. アプリの初期化

npx create-next-app

(アプリ名を聞かれるので 「my-first-next-app」 のように入力します。)

1-2. アプリの実行

cd my-first-next-app
npm install
npm run dev

http://localhost:3000/ へ アクセスできることを確認します


● Firebaseの設定

2-1. Firebaseの新規登録

https://console.firebase.google.com/u/0/
へアクセスして「+プロジェクトの追加」をクリックします

(プロジェクト名を聞かれるので「my-first-next-app-firebase」 のように入力します。)

「続行」をクリックしてプロジェクトを作成します。

2-2. 新規登録したFirebaseのプロジェクトの設定

「ウェブ」アイコンをクリックして「ウェブアプリへの Firebase の追加」画面へ移動します。

(ニックネームを聞かれるので「my-first-next-app-apelido」 のように入力します。)

登録が完了すると firebaseConfig が表示されるのでコピーしておきます。

const firebaseConfig = {
  apiKey: "xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  authDomain: "xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  projectId: "xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  storageBucket: "xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  messagingSenderId: "xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  appId: "xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
};

コピーした後コンソールに進みます

2-3. FirebaseでGoogle認証を有効にする

一番左のメニューの「Authentication」をクリックし「始める」をクリックします。

ログインプロバイダーにGoogleを追加して有効化します。

2-4. ログインテスト用アカウントを作成しておく

「Authentication」 →「Users」からログインテスト用アカウントを作成しておきます


● Next.js アプリへFirebaseの追加

3-1. Firebaseの新規登録

npm install firebase

3-2. Firebaseアプリ初期化コンポーネントの作成

FirebaseApp.js

import { initializeApp } from "firebase/app";

const firebaseConfig = {
  apiKey              : "xxxxxxxxxxxxxxxxxxxxxxxxxxx",
  authDomain          : "xxxxxxxxxxxxxxxxxxxxxxxxxxx",
  projectId           : "xxxxxxxxxxxxxxxxxxxxxxxxxxx",
  storageBucket       : "xxxxxxxxxxxxxxxxxxxxxxxxxxx",
  messagingSenderId   : "xxxxxxxxxxxxxxxxxxxxxxxxxxx",
  appId               : "xxxxxxxxxxxxxxxxxxxxxxxxxxx"
};

const FirebaseApp = initializeApp(firebaseConfig);

export default FirebaseApp

3-3. Firebaseログインサンプル画面の作成

pages/login.js

import Head from 'next/head'
import Image from 'next/image'
import styles from '../styles/Home.module.css'
import FirebaseApp from '../FirebaseApp';
import { getAuth, signInWithEmailAndPassword } from "firebase/auth";

export default function Home() {

  const doLogin = () => {
    const auth = getAuth();

    // Firebaseに登録したID,PASSWORD
    const email = 'test@user.com';
    const password = 'XXXXXXXXXX';

    signInWithEmailAndPassword(auth, email, password)
      .then((userCredential) => {
        const user = userCredential.user;
        alert( 'ログインok!' );
        console.log( '● user' );
        console.log( user );
      })
      .catch((error) => {
        const errorCode = error.code;
        const errorMessage = error.message;
      });
  }

  return (
    <div className={styles.container}>
      <h1>Googleログイン</h1>
      <button onClick={doLogin}>googleでログインする</button>
    </div>
  )
}

3-4. Firebaseログインの実行

http://localhost:3000/login
にアクセスしてログインボタンをクリックすると「ログインok!」のアラートが表示されます。

● ログイン状態の永続性

import {
  getAuth,
  setPersistence,
  browserLocalPersistence,
  browserSessionPersistence,
  inMemoryPersistence
} from "firebase/auth";

const auth = getAuth()

await setPersistence(auth, browserLocalPersistence);

以下の4パターンが存在します

browserLocalPersistence (LOCAL)
browserSessionPersistence (SESSION)
indexedDBLocalPersistence (LOCAL)
inMemoryPersistence (NONE)

Firebase Authentication これだけは覚えておけ!テストに出るぞ! - Qiita

No.2052
10/04 09:52

edit

プロセスマネージャー pm2で next.js を動作させる

● 1. pm2 のインストール

-g オプションをつけてグローバルにインストールします

 npm install pm2@latest -g

バージョンを確認します

pm2 --version
5.1.2


● 2-A. ワンライナーでpm2からnext.jsを起動する

cd <nextjsアプリのディレクトリ >
pm2 start npm --name "next" -- start 

● 2-B. app.jsonを作成してpm2からnext.jsを起動する

vi app.json

app.json を次の内容で保存する

{
  "name" : "nextjs",
  "script" : "./node_modules/next/dist/bin/next",
  "env" : {
    "NODE_ENV" : "development"
  },
  "env_production" : {
    "NODE_ENV" : "production"
  }
}

"name" : "nextjs", としているので、アプリ名は nextjs になります。)

pm2の起動(pm2で next.js を動作させる)

pm2 start app.json --env production

起動すると nextjs というアプリがリストに表示されます。


● pm2のコマンド

プロセスの状態を見る

pm2 ls

「nextjs」という名前のアプリを停止する

pm2 stop nextjs

「nextjs」という名前のアプリをプロセスリストからする

pm2 delete nextjs

「nextjs」という名前のアプリをリスタートする

pm2 restart app_name

● pm2 を サーバーマシン起動時に自動実行するように設定する

pm2 を自動起動させる( centos )

pm2 startup

● pm2自動起動時の起動プロセスを保存

pm2 を自動起動させる

pm2 save
No.1907
10/25 12:14

edit

next.js