20210123のReactに関する記事は10件です。

[React] Reactの学習をします(2-3)React Router を用いた複数ページ Web アプリの開発

Reactの学習をします(2-3)

引き続き、Reactの学習をしています。

前回の記事 : [React] Reactの学習をします(2-2)Node.js による API サーバー開発

教材

Reactチュートリアル2:レビューサイトを作ろう

引き続き、likr さんが公開している「Reactチュートリアル2:レビューサイトを作ろう」という記事を教材に学習させて頂きます。

素晴らしい教材をありがとうございます。

成果物

このチュートリアル2につきましては、チュートリアルの通りに作成し既にNetlifyに公開させて頂いております。

こちらです → 日大文理ラーメンレビュー

学習日記

既に作成済ですが、少しずつチュートリアルの内容を読み返してみたいと思います。

※ 教材から箇条書き的に抜粋させて頂きます。

React Router を用いた複数ページ Web アプリの開発

・React で複数ページから構成される Web アプリを開発するためには React Router を使用します。

client/src/App.js をチュートリアルの内容で作成します。

・ここでは、react-router-dom からインポートした Router と Switch 、 Router という 3 つのコンポーネントが登場します。

Router コンポーネントは、React Router が管理するコンポーネントの範囲を設定します。
・基本的にはアプリケーションのコンポーネント全体を Router コンポーネントの子要素にしておくとよいでしょう。

Switch コンポーネントは、URL によって切り替わる要素の場所を設定します。

Route コンポーネントは、path 属性を持ち、URL が path と一致したときにページに表示させる内容を設定します。

フロントエンドからの API リクエスト

1.環境変数の利用

・開発環境と本番環境(最終的に公開する環境)でパラメータを切り替える必要がある場合には環境変数を利用すると良いでしょう。
・react-scripts を使っていれば、開発環境用の環境変数を .env.development 、本番環境用の環境変数を .env.production で設定することができます。
・これらのファイルには REACT_APP_ から始まる環境変数名を記述します。

2.API サーバーのエンドポイントに対応した関数の作成

/restaurants/restaurants/:restaurantId/restaurants/:restaurantId/reviews に対して GET リクエストを行う関数をそれぞれ getRestaurantsgetRestaurantgetRestaurantReviews としています。

これらの間の共通の処理は request 関数にまとめています。

3.CORS の設定を追加

・フロントエンドと異なるオリジンとの通信は CORS(Cross-Origin Resource Sharing) と呼ばれます。

(つづく)

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

tailwind2.0 + react + typescript 環境構築

tailwindとreactの環境作り、特にPostCSSに苦労したのでまとめようと思ったら本家がわかりやすくなってたのでやってみました。
公式の通りなのでぜひ公式もご覧ください。

Install Tailwind CSS with Create React App

公式ではtypescriptやyarnは使用しません。

環境

$ node -v
v14.15.3

$ yarn -v
1.22.10

$ npx create-react-app --version
3.4.1

Reactアプリ作成

テンプレートをTypescriptで作成します。

$ yarn create react-app app-name --template typescript
$ cd app-name
$ yarn start

tailwind導入

パッケージを追加します。

$ yarn add tailwindcss@npm:@tailwindcss/postcss7-compat @tailwindcss/postcss7-compat postcss@^7 autoprefixer@^9

Create React Appで作ったままではPostCSSの設定を上書きできないのでCRACOをインストールします。

$ yarn add @craco/craco

package.jsonファイル内のスクリプトをreact-scriptsの代わりにcracoを使用します。ejectはそのままです。

  {
    // ...
    "scripts": {
     "start": "craco start",
     "build": "craco build",
     "test": "craco test",
     "eject": "react-scripts eject"
    },
  }

craco.config.jsを作成します。
PostCSSのプラグインとしてtailwindcssとautoprefixerを追加します。

module.exports = {
  style: {
    postcss: {
      plugins: [
        require('tailwindcss'),
        require('autoprefixer'),
      ],
    },
  },
}

tailwindの設定ファイル作成

initを実行するとtailwind.config.jsが作成されます。

$ npx tailwindcss init

buildしたときに未使用のスタイルを含めないようにtailwind.config.jsのpurgeオプションにすべてのコンポーネントへのパスを指定します。

module.exports = {
  purge: ['./src/**/*.{js,jsx,ts,tsx}', './public/index.html'],
  // ...
}

プロジェクトのCSSにtailwindを追加

デフォルトで作成される./src/index.css@tailwindディレクティブを使ってbase, components, utilitiesを含めます。

@tailwind base;
@tailwind components;
@tailwind utilities;

tailwindを使ってみる

簡単にボタンでも作ってみます。
./src/Button.tsxを追加します。

import React from 'react';

export const Button: React.FC = ({ children }) => {
  return (
    <button className="py-2 px-4 bg-green-500 text-white font-semibold rounded-lg shadow-md hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-green-400 focus:ring-opacity-75">
      {children}
    </button>
  );
};

./src/App.tsxにButtonをimportします。

import React from 'react';
import logo from './logo.svg';
import './App.css';
import { Button } from './Button';

function App() {
  return (
    <div className="App">
      <header className="App-header">
        // ...
        <Button>Click!</Button>
      </header>
    </div>
  );
}

export default App;

実行します。

$ yarn start

yarnstart.png

とても簡単にtailwindが導入できました。

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

[自分用メモ]Reactのstateとpropsの関係

自分用のメモです。
本記事ではReactの概念について解説しています。

Reactとは

Reactとはフレームワークではなく、あくまでもUIの作成に特化したJavascriptのライブラリです。

ライブラリは部品で、フレームワークは既に決められたテンプレートと例えることができます。
プログラマはライブラリの機能を呼び出すタイミングと場所を指定できますが、フレームワークはフローの中で、プログラマが介入できる場所がいくつか用意され、フレームワークは必要に応じてそれらを呼び出します。

ライブラリとフレームワークの違いについてはこちらの記事をどうぞ
「ライブラリ」と「フレームワーク」は何が違うのか

Reactではコンポーネントと呼ばれる構成要素を用いて開発します。部分ごとにコンポーネントを分けることで、カスタマイズしやすく変えたい部分だけを変えることができます。

なぜReactを使うのか

  • 仮想DOMが高速

Reactには、仮想DOM(Virtual Document Object Model)というレンダリング機構が備わっています。
(DOMとはdocument.getElementById(id);のようにjavascriptから自由に文字色などを操作することができる操作を指す。)

仮装DOMはページの差分検出の比較対象に使われ、従来のDOMと違い、必要な部分しか更新されないため非常に高速に動作します。

DOM操作についてはこちらをどうぞ
仮想DOMについてはこちらをどうぞ

  • SPA(Single Page Application)が作りやすい SPAは、ページすべてを毎回読み込む必要がなく、単一のWebページでコンテンツの切り替えを行うことができる。効率的かつ高速で動かすことができる設計構造のことです。 ReactはSPAに必要な高速な動作速度を完全に再現できるので、非常に相性のいいライブラリといえます。

 Reactの構成要素

Reactは主にComponent、state、propsの3つで構成されており、データが変更された時に、適切なコンポーネントだけを効率的に更新してレンダリングすることができます。

  • Component

コンポーネント単位でUIの部品を作り、コンポーネントを組み合わせてアプリケーションを構築します。
コンポーネントのおかげで、UI を独立した再利用できる部品に分割し、部品それぞれを分離して開発することができます。
コンポーネントは関数と似ており(props)任意の入力を受け取り、画面上に表示すべきものを記述する React 要素を返します。 
ComponentにはClass ComponentとFunctional Componentの2種類あります。

1.関数(Functional Component)
const App = (props) => {
return (
<div>
<h1>Hello World</h1>
</div>
);
};

2.ClassComponent

class App extends React.Component {
render() {
return (
<div>
<h1>Hello World</h1>
</div>
);
}
}

  • state

 Componentでは内部で状態(state)を持つことができます。stateはコンポーネント毎に持っており、コンポーネントの状態を管理します。
状態の変化によってstateの値を変えることができます。

  • props

 親コンポーネントから子コンポーネントへ値を渡し、コンポーネント間でデータの受け渡しができます。(propsは子供が持っており、子から親へは渡せない)

処理の流れ

・コンポーネントにはコンポーネントを利用する側である「親コンポーネント」とコンポーネントを利用される側である「子コンポーネント」に分けられます

・親コンポーネントが子コンポーネントを呼び出すとき、子コンポーネントに値が渡されますが、この時に渡されるのが「props」になります。

・親から渡された値を取り出して画面に描画します。

stateの使い方

・stateを使うことで画面を動的に変更させることができます。

stateを使う際には、初期値を設定して変化させる処理を書いて使います。
stateの値が更新されることで画面を動的に変えることができます。

まとめ

・各コンポーネントはstateを持っており、自身のstateしか更新できない
・stateが更新されると再描画される
・親から子にのみpropsを渡せる

propsとstateの説明はこちらの記事が分かりやすいです

実際にこうしてアウトプットしてみるとReactの概念しか理解できていないと痛感させられますね。。
アウトプット大事です。

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

[フロントエンド] うわっ…Componentの凝集度、低すぎ?

Screen Shot 2021-01-23 at 16.38.03.png

0. はじめに

有名OSSのコミッターから、コピペで動かすマンまで、彼らは等しくプログラマと呼ばれます。10xプログラマという言葉があるように、同じプログラマでもその生産性には天地ほどの開きがあります。

プログラマの生産性は、1968年のSackmanらの研究以来、ソフトウェア工学でも熱い研究テーマの一つですが、未だにプログラマの生産性を測る指標は確立されていません。

一方、広木大地氏は自著「エンジニアリング組織論への招待」で、エンジニアリングを不確実性を削減する行為と定義しました。プログラミング能力を測る重要な尺度として、モジュールの凝集度があります。高い凝集度で設計しコーディングされたモジュールは、見通しがよく、再利用可能で、バグが少ない…つまり不確実性が少ない状態と言えるでしょう。

システムが指数関数的に複雑化し続ける昨今、凝集度という概念は、1つのクラスからインフラ構成に至るまで、ソフトウェア・エンジニアリングの全てのレイヤーで必要となる基本教養です。凝集度は言語に依存しない概念ですが、ここではWebのフロントエンドを題材に、凝集度を向上させる方法を実例と共に紹介します。

1. 対象読者

下記の人たちに宛てて書きます。

  • 凝集度が何かよく知らない方
  • 凝集度の高い設計にいまいち自信のない方
  • クソコードを書いてスヤスヤ眠る毎日を過ごしていた過去の私

2. 類語

言葉の意味を知りたいとき、国語辞典より類語辞典を引いたほうが理解の助けになる場合があります。ここでは凝集度そのものの説明の前に、凝集度の類語をいくつか紹介します。

2-1. UNIX哲学 - Do one thing well

UNIXはソフトウェア界のバイキングたちが昼夜を問わず開発を進めている大規模なOSSです。そのUNIX開発を背骨のように支える思想を総称しUNIX哲学と呼びます。

UNIX哲学の中でも、様々なプロジェクトに適用できる思想が Do one thing well=1つのことを上手くやれ です。

例えば、次のUNIXコマンドは今いるディレクトリの.jsonファイルを個数を出力します。

$ ls
bar.json    foo.json    fuga.gif    hoge.txt    piyo.json
$ ls -l | grep '\.json$' | wc -l
3

UNIXではプログラムを小さな粒度に保つべきという掟があります。複雑な処理を行いたいときは、上の例のように、それら小さなプログラムをパイプ|で連結して実現するのです。

つまり個々のプログラムは、小さな責任を冴えたやり方で果たせ、すなわちDo one thing wellであれという考えです。

2-2. KISS原則

Keep it simple, stupid=シンプルにしておけ、バカ、もしくはKeep it short and simple=簡潔かつシンプルしておけのアクロニムです。

一般にコードは書かれる時間よりも読まれる時間の方が長いです。したがって、コーディングに時間を掛けてでも、モジュールはリーダブルである必要があります。

また一番美しいコードは0行のコードだという極論が示すように、設計のシンプルさはシステムの堅牢性と明白な因果関係があります。スペースシャトルよりもソユーズの耐用年数が長いのも、AK-47が世界で最も使われる銃であるのも、これらの設計がシンプルであることと無関係ではありません。

3. 凝集度

上で述べた類語に共通することはなんでしょうか。それはモジュールの責任を減らすという考え方です。

Do one thing wellKISS原則を現実世界のコードに反映させる具体的な指標が凝集度です。

ソフトウェアの複合/構造化設計」によれば、凝集度はその巧拙のレベルにより次の7つに分かれます。

  1. 偶発的凝集(最悪)
  2. 論理的凝集
  3. 時間的凝集
  4. 手続き的凝集
  5. 通信的凝集
  6. 逐次的凝集
  7. 機能的凝集(最良)

しかしこの7つのレベルは細分化されすぎており境界が曖昧です。知っておくことは決して無駄ではありませんが、憶えていてもそれほど実務では役に立ちません。

また凝集度の低さを定量的に測るLCOM*という指標があり、次式で表されます。

LCOM* = \frac{\frac{1}{a}\sum_{j=1}^{a}\mu(A_j)-m}{1-m}
変数 説明
$a$ クラスのメンバ変数の個数
$A_j$ クラスのj番目のメンバ変数
$m$ クラスのメソッドの個数
$\mu(A_j)$ $A_j$にアクセスしているメソッドの個数

しかしLCOM*は古き良きオブジェクト指向言語のクラス設計には有効ですが、特に昨今のフロントエンドでデファクトスタンダードとされる設計手法から見ると、時代遅れの感は否めません。

したがってこの記事では、現実世界のプロジェクトで如何に凝集度が低下するか、具体例を使って示します。

4. 凝集度が下がる瞬間

フロントエンド開発においてComponentの凝集度を上げると言った場合、Componentの責任を可能な限り小さく保つことを指します。

例えばユーザーのプロフィールを表示する次のようなProfile Componentを考えます。

const Profile = ({user: UserModel}) => {
  return (
    <>
      <img src={user.avatar} />
      <h2>Hi, I'm {user.name}.</h2>
    <>
  )
}

userという単一の引数を持ったシンプルなComponentで、プロフィールを表示するという責任に集中しています。よって凝集度は最良と言えます。

しかしここで「プロフィールと一緒に友達のリストを表示する」という要件が追加されたとします。Profile Componentは次のようになりました。

const Profile = ({user: UserModel}) => {
  // 友達をロードして
  const friends: FriendModel[] = loadFriends(user.id)
  // 友達リストのNodeを作る
  const friendsNode = (
    <ul>
      {friends.map(friend => <li key={friend.id}>{friend.name}</li>)}
    </ul>
  )

  return (
    <>
      <img src={user.avatar} />
      <h2>Hi, I'm {user.name}.</h2>
      {friendsNode}
    <>
  )
}

しかしあなたはProfile Componentが既に複数の場所から呼ばれており、友達を表示したくないケースがあることに気が付きます。そのため友達リストの表示をコントロールできるよう、Profile Componentに分岐処理を加えました。

const Profile = ({user: UserModel, shouldShowFriends: bool}) => {
  // 友達リストのNodeを生成する関数
  const showFriends = () => {
    // 非表示ならreturn null
    if (!shouldShowFriends) return null

    // 表示するなら友達をロードしてNodeを生成
    const friends: FriendModel[] = loadFriends(user.id)
    return (
      <ul>
        {friends.map(friend => <li key={friend.id}>{friend.name}</li>)}
      </ul>
    )
  }

  return (
    <>
      <img src={user.avatar} />
      <h2>Hi, I'm {user.name}.</h2>
      {showFriends()}
    <>
  )
}

引数に依存した分岐処理が加わりました。凝集度が低下した瞬間です。

Profile Componentは、プロフィールを表示するという唯一の責任を果たす美しいモジュールでした。それがいまや分岐処理を加えられ、友達リストを表示するという新たな責任を負ってしまいました。

5. 凝集度を高く保つ

それでは「友達リストを表示する」という要件に対して、どのようなComponentを書けば良かったのでしょうか。

当然答えは友達リストを表示するという単一の責任だけを負った新たなComponentを作る、です。Profile Componentからコードを分離し、FriendsというCompnentを作ります。

const Friends = ({user: UserModel}) => {
  const friends: FriendModel[] = loadFriends(user.id)

  return (
    <ul>
      {friends.map(friend => <li key={friend.id}>{friend.name}</li>)}
    </ul>
  )
}

そしてあとは、Profile Componentを呼んでいた親Componentに、Friends Componentを追加してあげれば良いのです。

// 親Componentから個々のComponentをコール
<Profile user={user} />
<Friends user={user} />

これで個々のComponentの凝集度を高く保ったまま、要件に応えることができました。

またFriends Componentを分離したことで、「友達リストを表示する」という機能に対して、以後は同じFriends Componentを再利用すれば良くなった点も重要です。

Componentにコードを書き足す前に、その修正によりComponentの責任を増やすことにならないか、自分に問いかけてみましょう。もし答えがYESなら、それはComponentを分割するタイミングであるはずです。

6. 結合度

凝集度とセットで語られる概念として結合度があります。これらは混同されやすい概念ですが、図示すると分かりやすいです。図の中の円は、引数、メンバ変数、メンバ関数といった要素を示します。

Screen Shot 2021-01-23 at 16.38.03.png

凝集度の対象はモジュール単体です。モジュールの担う責任の少なさ、要素の少なさ、要素同士の関連度によって決定します。高いほど善です。

一方、結合度の対象はモジュール同士の関連です。モジュール同士の結びつきの強さを表します。低いほど善です。

ただし凝集度と結合度は反比例の関係にあります。高い凝集度を意識し書かれたモジュールは、自ずと低い結合度になります。結合度への意識が必要なケースもありますが、フロントエンド開発においては、凝集度さえ意識できていれば問題ないというのが今の所の結論です。

7. おわりに

ソフトウェア・エンジニアリングの世界は流行り廃りが激しい一方、どのようなプロジェクトでも有用な教養があります。そのうちの一つが凝集度という古くから存在する尺度です。

特に昨今のシステムは指数関数的に複雑化しており、モジュールの凝集度を高く保つことはほぼ全ての職業エンジニアに求められます。

Microserviceアーキテクチャや関数型言語といったトレンドの底流にあるのも、凝集度と同じく、小さな責任を冴えたやり方で果たすという考えです。

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

Next.js 開発環境構築テンプレ(TypeScript、ESLint、Prettier)

はじめに

Next.jsのプロジェクト作成のテンプレートです。自分用ですが、毎回調べるのは面倒なのでのでメモしておきます。

1.Next.jsのプロジェクトの作成

npx create-next-app $PROJECT_NAME

2.ベースディレクトリを変更

pages と styles を src のディレクトリ内に移動。

mkdir src && \
  mv pages/ src/pages & \
  mv styles/ src/styles

3.TypeScriptを導入

npm install -D typescript @types/react @types/react-dom @types/node

4. ESLintとPrettierを導入

エラーを事前に取り除いたり、コードを整形するため

npm install -D eslint prettier eslint-config-prettier

ESLintで使うプラグインもインストール

npm install -D eslint-plugin-{react,react-hooks,prettier}
npm install -D @typescript-eslint/{parser,eslint-plugin}

5.ESLintルール設定

.eslintrc.json
{
  "env": {
    "es6": true,
    "node": true,
    "browser": true,
    "commonjs": true
  },
  "globals": {
    "Atomics": "readonly",
    "SharedArrayBuffer": "readonly",
    "React": "writable"
  },
  "parser": "@typescript-eslint/parser",
  "parserOptions": {
    "ecmaVersion": 2018,
    "sourceType": "module",
    "ecmaFeatures": {
      "jsx": true
    }
  },
  "settings": {
    "react": {
      "version": "detect"
    }
  },
  "plugins": ["react-hooks", "react", "@typescript-eslint", "prettier"],
  "extends": [
    "eslint:recommended",
    "plugin:@typescript-eslint/eslint-recommended",
    "plugin:@typescript-eslint/recommended",
    "plugin:react/recommended",
    "plugin:react-hooks/recommended",
    "prettier",
    "prettier/react",
    "prettier/@typescript-eslint"
  ],
  "rules": {
    "react/prop-types": "off",
    "prettier/prettier": "error",
    "react/react-in-jsx-scope": "off"
  },
  "overrides": [
    {
      "files": ["*.js"],
      "rules": {
        "@typescript-eslint/no-var-requires": "off",
        "@typescript-eslint/explicit-function-return-type": "off"
      }
    }
  ]
}

6.Prettier設定

.prettierrc.json
{
  "semi": true,
  "trailingComma": "all",
  "singleQuote": true,
  "printWidth": 100,
  "tabWidth": 2
}

7.VSCodeの自動整形

.vscode/settings.json
{
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "editor.formatOnSave": true,
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  }
}

8.状態管理ライブラリを追加(オプション)

2020/05月にFacebookから出た新しい状態管理ライブラリです。

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

Reactアプリ内でのReduxの複数のReducerを一つにまとめる方法

1. combineReducers()reduxからimportする。

src/reducers/index.js
import { combineReducers } from 'redux';

2. まとめたい他のreducerもimportする。

src/reducers/index.js
import { combineReducers } from 'redux';
import counterReducer from './counter'; // 追加
import loggedReducer from './isLogging'; // 追加
既存のサービスのネットワーク構成変更に伴い、実現可能かどうかのデモ用SPAの作成の希望があった。

3. importしたcombineReducers()を使用してreducerをまとめる。そしてexport。

src/reducers/index.js
import { combineReducers } from 'redux';
import counterReducer from './counter';
import loggedReducer from './isLogging';

// coombine()を使ってreducerをまとめる。
const rootReducers = combineReducers({
  // key名はなんでも。任意のものでいい。
  counter: counterReducer,
  isLoggedIn: loggedReducer
  // ちなみに、ES6のプロパティ名のショートハンドを使用して以下のようにも書ける
  // counterReducer,
  // loggedReducer
});

export default rootReducers;

4. exportしたrootReducerをsrc/index.jsでimportする。

src/index.js
import roorReducers from './reducers' // ファイル名の指定がない場合、webpackがindex.jsを自動的に指定してくれる

// ReduxのcreateStore()の引数にrootReducersを渡す。
const store = createStore(
  rootReducers
);

完了!

参考

Redux For Beginners | React Redux Tutorial - YouTube
ちょっと高度なJavaScriptの話 - Qiita

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

React-Reduxの使い方 (ReactとReduxの接続)

個人的なメモも兼ねて。

src/index.jsでやること

1. createStoreのメソッドをReduxからimportする。

STOREを作成するためのメソッド。
引数にreducerを指定する(後述)。

src/index.js
import { createStore } from 'redux';

2. Providerコンポーネントをimport

ReduxをReactで使用するためのMWであるreact-reduxから、Reactプロジェクトで使用することのできるProviderコンポーネントをimportし、設置する。

Providerコンポーネントって何?

React Reduxの公式ドキュメントにもあるように、Providerコンポーネントにネストされている範囲だけが、react-reduxの機能の一つであるconnect()でconnectされたコンポーネントを扱えるようになるらしい。

Normally, you can’t use a connected component unless it is nested inside of a<Provider>.

Providerコンポーネントはstoreと言うpropsのみ受け付けている。文字通りこのpropsにはcreateStore()で作成したSTOREを渡す。

src/index.js
import { Provider } from 'react-redux';

~~~~~中略~~~~~

ReactDOM.render(
  <React.StrictMode>
    <Provider store={store}> 
      <App />
    </Provider>
  </React.StrictMode>,
  document.getElementById('root')
);

3. STOREに渡すためのREDUCERをimport

REDUCERは他のファイルで定義しておく。
よく見かけるのはsrc/reducersディレクトリを切ってその中に目的別のreducerファイルを作成していく手法。

複数のファイルにまたがるREDUCERを一つにまとめてsrc/index.jsSTOREに渡す方法は以下を参照。
Reactアプリ内でのReduxの複数のReducerを一つにまとめる方法 - Qiita

REDUCERをまとめてimport
import rootReducers from "./reducers"; // 指定がない場合はwebpackがデフォルトでindex.jsというファイルを指定してくれる

Reduxを使用するときにやること

ReactとReduxの接続 connect()

登場人物たち
- mapStateToProps :STOREが持っているstateをpropsに入れて子コンポーネントへ渡す。
- mapDispatchToProps :DISPATCHを呼び出す関数をpropsに入れて子コンポーネントへ渡す。

mapStateToPropsについて
const mapStateToProps = (state) => { // Issueコンポーネント内で使用するstateを限定する役目
  return {
    // stateオブジェクトから指定できるのは、src/reducers/index.js でrootReducerにまとめたときのオブジェクトのkey名
    // key名がコンポーネントで受け取るpropsの名前になる
    // なので、子コンポーネントでは「issue」という名前で参照可能。
    issue: state.issue.data,
  };
}
mapDispatchToPropsについて
/*
子コンポーネントからdispatchするときに、わざわざ `dispatch(actionCreator(追加したい要素))`しなくても、
この場合だと `addContents(追加したい要素)` でstoreにdispatchできるようになる。
*/
const mapDispatchToProps = dispatch => {
  return {
    addIssue: (payload) => {
      dispatch(actions.addIssue(payload));
    },
  }
}

connect()の書き方

connect()の書き方
const ContainerInMiddle = connect(
  mapStateToProps,
  mapDispatchToProps
)(ChildComponent);

Container Components(reduxと接続したreactのコンポーネント)のコード例

import * as actions from '../actions';
import { connect } from 'react-redux';
import IssueContents from '../components/organisms/IssueContents';

const mapStateToProps = (state) => { // Issueコンポーネント内で使用するstateを限定する役目
  return {
    // stateオブジェクトから指定できるのは、src/reducers/index.js でrootReducerにまとめたときのオブジェクトのkey名
    // key名がコンポーネントで受け取るpropsの名前になる
    // なので、子コンポーネントでは「issue」という名前で参照可能。
    issue: state.issue.data,
  };
}

/*
  子コンポーネントからdispatchするときに、わざわざ `dispatch(actionCreator(追加したい要素))`しなくても、
  この場合だと `addContents(追加したい要素)` でstoreにdispatchできるようになる。
*/
const mapDispatchToProps = dispatch => {
  return {
    addIssue: (payload) => {
      dispatch(actions.addIssue(payload));
    },
  }
}

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(IssueContents);

参考

Reduxのconnectについて
Basic Tutorial | React Redux
ReactとReduxで管理するstateの分け方|Playground発!アプリ開発会社の技術ブログ

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

【Slack】webhookを使って見た(備忘録)

どうもwebエンジニアなりたく勉強中です。
Qiita初投稿ということもあり使い方がいまいちわかってません。
色々教えて頂ければと思います。
今Reactを使ってchatbotを作成中で問い合わせがきた時にslackに通知する仕様が作りたいと思い、忘れないうちにアウトプットしていきたいと思います。

通知文の作成

const payload = {
text : '新しい通知がきました'
}

textのvalue側に任意のコメントを挿入することで通知時にそのコメントが表示されます。
例えばstateに記載あるkeyを設定すればフォーム入力された値がslackに表示される!!

fetchでwebhookを取得する

webhook取得方法は以下記事を参照しました
https://www.sejuku.net/blog/74471

ここでは取得方法は割愛します。

const url = '取得したURL'
const options = {
method : "POST",
body : JSON.stringify(payload)

fetch(url,options);
alert('送信が完了しました');

最後にはフォームの初期化をしてダイアログをfalseにすれば完了。

エンジニアになれるように引き続き頑張っていきたいと思います!

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

Gatsbyでreact-modalを使う方法について

最近Gatsbyを使って勉強をしてみています。

Reactを素で使うよりもとっかかりやすく、StarterやPluginの充実、GraphQLの標準装備と個人的には学習コストが少ないし、Reactを最初にやるには良いんじゃないかなとは思ってます。

Gatsby

今回は、Gatsbyを使ってページにモーダルウィンドウの機能を実装するために使えるreact-modalをGatsbyで使う場合に結構ハマってしまったので、備忘録を兼ねてメモです。

react-modal documentation

react-modalのセットアップ

react-modalの初期設定は簡単です。
npmなりyarnなどを使ってreact-modalをインストールすればOKです。

command
npm install react-modal

react-modalを使う(1ページに1つのモーダルのみを表示する場合)

まずはシンプルに1ページに1つのモーダルだけを表示する場合です。
例としてmodal-simple.jsというページで設定したとすると以下のようなコードになります。

page/modal-simple.js
import React from "react"
import Modal from "react-modal";

// react-modalの初期設定
// root nodeのSelectorを設定
Modal.setAppElement("#___gatsby");
// react-modalのデザインを設定修正する場合の例
Modal.defaultStyles.overlay.backgroundColor = "black";

const ModalSingle = () => {

  //モーダルの表示状態と切り替える為にState(props)を準備
  const [modalIsOpen, setIsOpen] = React.useState(false);

  // shouldCloseOnEscやshouldCloseOnOverlayCloseを使う場合に設定が必要
  const handleCloseModal = () => {
    setIsOpen(false)
  }

  return(
    <div>
      <div className="container">
        ここにモーダルを表示します
        <button className="button" onClick={() => setIsOpen(true)}>ボタン</button>
      </div>
      <Modal 
        isOpen={modalIsOpen}
        onRequestClose={() => handleCloseModal()}
        shouldCloseOnEsc={true}
        shouldCloseOnOverlayClick={true}
      >
        <div>モーダルの表示内容です</div>
      </Modal>
    </div>
  )
}

export default ModalSingle

これで以下のようなモーダル表示をするためのボタンと、モーダル表示がされるはずです。
イメージ画像

ポイントはGatsbyでは明確にprops等が通常見えないので…
React.useState()を使ってステータス管理用のpropsを準備してます。

また、shouldCloseOnEscなどを使いたい場合は、onRequestCloseの定義も必要です。
そこを設定しないと機能しないので気をつけてください。
onRequestClose - react-modal documentation

応用編:1ページに複数モーダルを表示したい場合

上の設定だと1ページに1つのモーダルなら良いのですが、複数だとうまく出来ません。
複数のモーダルの表示を切り替え分けたい場合は、ステータス管理を少し調整するコツが必要です。

modal-multiple.js
import React from "react"
import Modal from "react-modal";

// react-modalの初期設定
// root nodeのSelectorを設定
Modal.setAppElement("#___gatsby");

const ModalMultiple = () => {

  // モーダルの表示状態と切り替える為にState(props)を準備
  // false = 非表示、数値 = 表示しているModalの番目とする
  const [modalIsOpen, setIsOpen] = React.useState(false);

  //どのモーダルを表示するのか操作するために関数を準備
  const handleOpenModal = (num) => {
    setIsOpen(num) 
  }

  // shouldCloseOnEscやshouldCloseOnOverlayCliceを使う場合に設定が必要
  // モーダルを非表示の状態にするため、falseを指定する
  const handleCloseModal = () => {
    setIsOpen(false)
  }

  return(
    <div>
      <div className="container">
        パターン2ここにモーダルを表示します
        <ul>
          <li><button className="button" onClick={() => handleOpenModal(0)}>モーダル1</button></li>
        </ul>
        <ul>
          <li><button className="button" onClick={() => handleOpenModal(1)}>モーダル2</button></li>
        </ul>
        <ul>
          <li><button className="button" onClick={() => handleOpenModal(2)}>モーダル3</button></li>
        </ul>
        <ul>
          <li><button className="button" onClick={() => handleOpenModal(3)}>モーダル4</button></li>
        </ul>
      </div>
      <Modal 
        isOpen={(modalIsOpen === 0)}
        onRequestClose={() => handleCloseModal()}
        shouldCloseOnEsc={true}
        shouldCloseOnOverlayClick={true}
      >
        <div>モーダル1の表示内容です</div>
      </Modal>
      <Modal 
        isOpen={(modalIsOpen === 1)}
        onRequestClose={() => handleCloseModal()}
        shouldCloseOnEsc={true}
        shouldCloseOnOverlayClick={true}
      >
        <div>モーダル2の表示内容です</div>
      </Modal>
      <Modal 
        isOpen={(modalIsOpen === 2)}
        onRequestClose={() => handleCloseModal()}
        shouldCloseOnEsc={true}
        shouldCloseOnOverlayClick={true}
      >
        <div>モーダル3の表示内容です</div>
      </Modal>
      <Modal 
        isOpen={(modalIsOpen === 3)}
        onRequestClose={() => handleCloseModal()}
        shouldCloseOnEsc={true}
        shouldCloseOnOverlayClick={true}
      >
        <div>モーダル4の表示内容です</div>
      </Modal>

    </div>
  )
}

export default ModalMultiple

で定義するisOpenの状態を数値にしてしまえば、その値が合致した時だけ表示されます。
各Modalの表示条件をModalIsOpenの値で条件て設定し、表示制御する関数(今回はhandleOpenModal())を使って制御をすれば動きます。

image.gif

今回はOnClick要素でOpenしたいモーダルのID(0−3)を指定すれば開くように設定しています。

実際に今回動作を組んでみたサンプルコードをgithubにあげてますので、参考までに。

manji6/gatsby-modal: Gatsby で react-modalを使うサンプル

これがモーダル複数バージョンのサンプルコード
gatsby-modal/modal-multiple.js at main · manji6/gatsby-modal

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

Webpack5でReactのプロジェクトをビルドしたら一生エラーが出続けた話

経緯

ReactでchromeのExtensionを開発していた時のこと。

とあるライブラリを使い始めたあたりから唐突にビルドが通らなくなりました。

今回は一旦エラーを消す方法について調べたので書き記しておきます。

エラー内容

ERROR in ~~ 
Module not found: Error: Can't resolve 'http' in ~~

上記の他にも tls やら fs やらも見つからんとエラー。

一個一個インストールするのかーめんどくさいなーと思いながら、なんかおかしいなという思いが湧き出てきてなんとなく調べてみました。

エラー原因

クライアントサイド用のビルドをするときに、サーバーサイド用のライブラリが含まれていると発生するようです。

webpackではデフォルトのビルドターゲットがクライアント用(web)になっており、サーバーサイド(多分SSRとか?その他でwebpackを使ってビルドする用途がわからない)であればtargetをnodeにしてあげればビルドできるようになるはずです。

対応策

How to Polyfill node core modules in webpack 5.

上記の記事を参考にしました。

やること

  1. パッケージ群のインストール
  2. webpack.config.jsにaliasの設定
  3. クライアントサイドで使用できないcoreようモジュールを無効にする

まずcore(サーバーサイド)用のライブラリを、クライアントサイドで使えるライブラリにaliasとしてマッピングするとともに対応したライブラリをインストールしてあげるって感じです。

パッケージ群のインストール

対応策の項で紹介したリンクのさらに先にあるサンプルから、ワンライナーでインストールできるように準備しておいたので褒めて欲しい気持ち。

$ yarn add -E -D assert buffer console-browserify constants-browserify crypto-browserify domain-browser events stream-http https-browserify os-browserify path-browserify punycode process querystring-es3 stream-browserify readable-stream readable-stream readable-stream readable-stream readable-stream string_decoder util timers-browserify tty-browserify url util vm-browserify browserify-zlib 

※ ただし可読性は悪い

yarnを使っていますが、npmの人は適宜書き換えてください。

coreモジュールをクライアント用モジュールにマッピング

coreモジュールとして認識、ロードされてしまうパッケージ群をクライアントサイドで使用できるパッケージ群にマッピングするためのaliasを設定します。

webpack.config.jsに以下の記述を追加してください。

webpack.config.js
resolve: {
    alias: {
      assert: "assert",
      buffer: "buffer",
      console: "console-browserify",
      constants: "constants-browserify",
      crypto: "crypto-browserify",
      domain: "domain-browser",
      events: "events",
      http: "stream-http",
      https: "https-browserify",
      os: "os-browserify/browser",
      path: "path-browserify",
      punycode: "punycode",
      process: "process/browser",
      querystring: "querystring-es3",
      stream: "stream-browserify",
      _stream_duplex: "readable-stream/duplex",
      _stream_passthrough: "readable-stream/passthrough",
      _stream_readable: "readable-stream/readable",
      _stream_transform: "readable-stream/transform",
      _stream_writable: "readable-stream/writable",
      string_decoder: "string_decoder",
      sys: "util",
      timers: "timers-browserify",
      tty: "tty-browserify",
      url: "url",
      util: "util",
      vm: "vm-browserify",
      zlib: "browserify-zlib"
    },
}

core用モジュールの無効化

臭いものに蓋と巷では話題の方法です。

以下をwebpack.config.jsに追記してください。

webpack.config.js
resolve: {
    alias: { ... },
    fallback: {
      child_process: false,
      fs: false,
      crypto: false,
      net: false,
      tls: false
    }
}

上記の設定は 当該モジュールを要求するときは空のオブジェクトに変換する という方法です。

これで大体の人は動くようになるようです。

ただ、私の場合は uncaught ReferenceError: Buffer is not defined と、また違うエラーが出て悩まされています。

ひとまず大抵の方はこれで動くようになるようなので、困っている方がいればぜひ試してみてください。

言葉足らずだったりわかりにくいところなどあればコメントで教えていただけると幸いです。

それじゃあまた。

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