Open15

Next.jsの前にReact入門

ちびまろちびまろ

Reactの3つのコア・コンセプト

Reactを扱ううえで、以下3つのコア・コンセプトを理解する必要がある。

  • Components
  • Props
  • State
ちびまろちびまろ

Components

コンポーネントは、ボタンのような小さなものである場合も、ページ全体を表す大きなものである場合もあります。
引用元:公式ドキュメント

画面に表示される1つ1つの部品のこと。
Reactの画面(UI)はComponentが集まってできている。
Component(部品)ごとにオブジェクトを作成するため、再利用することができる。

ちびまろちびまろ

コンポーネントの構築手段は2つ存在する

  • クラスコンポーネント
  • 関数コンポーネント

クラスコンポーネント

Reactの初期のバージョンの頃に使用されていた方法
※関数コンポーネントが好まれている傾向があるように見えたので、触りだけ学んで詳細な書き方やコードについては飛ばす

メリット

  • Reactが独自に提供するReact.Componentクラスを継承したJavaScriptクラスを使って生成される
  • オブジェクト指向的な構文があるため、OOP開発経験のあるものは馴染みやすい

デメリット

  • 記述が冗長であり、コンポーネントの状態やライフサイクルメソッドの管理により複雑性が増す
  • ES6のクラス構文を使用しているため、関数コンポーネントよりも読みづらい

参考サイト:
https://www.uxpin.com/studio/jp/blog-jp/functional-vs-class-components-ja/

ちびまろちびまろ

昔はクラスコンポーネントがよく使われていたらしいが、今は関数コンポーネント派が多いらしい。

じゃあなぜ関数コンポーネント派が増えたのか?

クラスコンポーネントでしか使えなかった以下の機能が関数コンポーネントでも使えるようになった。

  • State
  • Lyfecycle Hooks

React 16.8 で新たに追加されたHooksによって、これらを関数コンポーネントでも使えるようになった。

参考サイト:
https://zenn.dev/swata_dev/articles/7f8ef4333057d7

ちびまろちびまろ

関数コンポーネント

マークアップを返すJavaScriptコンポーネント

UIとなる部品ボタンをfunction MyButton() {}で作成する。

でないと、Reactのコンポーネントとして認識されない。

returnでjsxで書かれた属性を返す。

function MyButton() {
  return (
    <button>I'm a button</button>
  );
}
export default function MyApp() {
  return (
    <div>
      <h1>Welcome to my app</h1>
      <MyButton /> 
    </div>
  );
}
ちびまろちびまろ

Props

HomePage()からHeader()を呼び出すときに引数へpropsを指定することで、プロパティをHeaderコンポーネントに渡すことができる。

function Header(props) {
  return <h1>Develop. Preview. Ship.</h1>;
}

function HomePage() {
  return (
    <div>
      <Header title="React" />
    </div>
  );
}

試しにコンソールに出力してみる

function Header(props) {
  console.log(props);
  return <h1>Develop. Preview. Ship.</h1>;
}

Headerの呼び出し元に書いたプロパティが出力されている

propsの型はオブジェクトであるため、デストラクチャリングを使用することができるそう。

この記事が参考になった
https://qiita.com/akifo/items/19a4f2823fc99779dffc

PHPのlist()とは少し違うよう。

<script type="text/jsx">
    const app = document.getElementById("app")

    function Header({ title,name }) {
        console.log(title);
        console.log(name);
        return <h1>Develop. Preview. Ship.</h1>;
    }

    function HomePage() {
        return (
            <div>
                <Header title="React" name="headerName" />
            </div>
        ) 
    }

    const root = ReactDOM.createRoot(app);
    root.render(<HomePage />);
</script>
ちびまろちびまろ

こうすることで、条件によってレンダリング対象を切り替えることできるそう

function Header({title}) {
    return <h1>{title}</h1>;
}

function HomePage() {
    return (
        <div>
            <Header title="React" />
        </div>
    ) 
}
ちびまろちびまろ

他にも手段があるそう

1. ドット表記のオブジェクト・プロパティ

function Header(props) {
  return <h1>{props.title}</h1>;
}

2. テンプレート・リテラル
${title}で表記するときは、必ずシングルクォートではなく、バッククォートを使うように注意する

function Header({ title }) {
  return <h1>{`Cool ${title} Literal`}</h1>;
}

3. 関数の戻り値
titleプロパティの設定値判定条件をいれて表示する内容を切り替えている。

function createTitle(title) {
    if (title) {
        return title;
    } else {
        return 'Default Title';
    }
}

function Header({title}) {
    return <h1>{createTitle(title)}</h1>
}

function HomePage() {
    return (
        <div>
            <Header title="React" />
        </div>
    ) 
}

titleプロパティの値が入っていたらtrue
つまり画面に「React」と表示される。

titleプロパティが空であればfalse
つまり、画面に「Default Title」と表示される。

4. 三項演算子
3ではIF文で分岐していたが、三項演算子で表現する方法もある

function Header({ title }) {
  return <h1>{title ? title : 'Default Title'}</h1>;
}
ちびまろちびまろ

Iterating through lists

リストの内容をforのように回してレンダリングする方法
同じスタイル(表示の仕方)で異なる情報を保持するUI要素を作成する

array.map()

array名.map()とし、mapのなかで(key)=>(value)の書き方で配列の各要素を表示できる

function HomePage() {
  const names = ['Ada Lovelace', 'Grace Hopper', 'Margaret Hamilton'];
 
  return (
    <div>
      <Header title="Develop. Preview. Ship." />
      <ul>
        {names.map((name) => (
          <li key={name}>{name}</li>
        ))}
      </ul>
    </div>
  );
}

If you run this code, React will give us a warning about a missing key prop. This is because React needs something to uniquely identify items in an array so it knows which elements to update in the DOM.

このコードを実行すると、Reactはキー・プロップが見つからないという警告を出す。これは、ReactがDOMのどの要素を更新すべきかを知るために、配列のアイテムを一意に識別する何かが必要だからです。
引用元

{names.map((name) => (
    <li key={name}>{name}</li>
))}
ちびまろちびまろ

ボタンをクリックした時に動作させたいロジックはonClickイベントで呼び出す

function HomePage() {
    function handleClick() {
        console.log("increment like count");
    }

    return (
        <div>
            <button onClick={handleClick}>Like</button>
        </div>
    )
}
ちびまろちびまろ

State

stateを使うことで、ボタンをクリックした回数などを保持することができる。
例:いいねボタンのいいね数
Hooksの機能を使うことで、実装することができ、名前はuseState()という。

  1. 空の配列としてuseState()を初期化する
    今回は初期値としてuseState()に「0」を入れておく
    ※必ずしも入れる必要はない
function HomePage() {
  const [] = React.useState(0);
}
  1. state名をつける
    配列の1番目の項目にstate名をつける。名前はなんでもOKらしい。
    言わずもがな何を表しているかが誰でも判断できる範囲ならOKだということ。
    今回はいいね数を例としているため、likesにする。
function HomePage() {
  const [likes] = React.useState(0);
}
  1. 更新名をつける
    配列の2番目に対象の値を更新する際に使う関数名を書く。
    基本的に名前はなんでもOKだが、名称の前に「set」をつけること。
    一般的には配列の1番目の名前をsetの後ろにくっつけるそう。
    ちなみにキャメルケースで命名すること
function HomePage() {
  const [likes, setLikes] = React.useState(0);
}

完成品がこちら

コードはこちら
<html>
    <body>
        <div id="app"></div>

        <script src="https://unpkg.com/react@18/umd/react.development.js"></script>
        <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
        
        <!-- Babel Script -->
        <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>

        <script type="text/jsx">
            const app = document.getElementById("app")

            function createTitle(title) {
                if (title) {
                    return title;
                } else {
                    return 'Default Title';
                }
            }

            function Header({title}) {
                return <h1>{createTitle(title)}</h1>
            }

            function HomePage() {
                const names = ['Ada Lovelace', 'Grace Hopper', 'Margaret Hamilton'];
                const [likes, setLikes] = React.useState(0);

                function handleClick() {
                    setLikes(likes + 1);
                }

                return (
                    <div>
                        <Header title="Develop. Preview. Ship." />
                        <ul>
                            {names.map((name) => (
                                <li key={name}>{name}</li>
                            ))}
                        </ul>
                        <button onClick={handleClick}>Like({likes})</button>
                    </div>
                )
            }

            const root = ReactDOM.createRoot(app);
            root.render(<HomePage />);
        </script>
    </body>
</html>
ちびまろちびまろ

Next.jsについて学ぶ

Reactの3つの基本概念について大体理解したからNext.jsの章に進む

package.jsonindex.htmlを作成してコマンド実行

npm install react@latest react-dom@latest next@latest

エラー発生
エラー文読む感じpackage.jsonファイルが悪そう

package.jsonの中に以下を記載

{}

ファイルを保存してもう一度コマンド実行したら成功した。

ちびまろちびまろ

Reactプロジェクトを作成したら、フロントエンドのビルド機能を使うためにpackage.jsonに以下を追加する
こうすることで、ターミナルでnpm run devと実行することで開発用サーバーが立ち上がる

{
// ここから
  "scripts": {
    "dev": "next dev"
  },
// ここまで
  "dependencies": {
    "next": "^14.1.3",
    "react": "^18.2.0",
    "react-dom": "^18.2.0"
  }
}

ちびまろちびまろ

部品を再利用する

いいねボタンを部品化して簡単に再利用できるようにする
app/like-button.jsを作成していいねボタンのコードを入力

like-button.js
'use client';

import { useState } from "react";

const [likes, setLikes] = useState(0);

export default function LikeButton() {
    function handleClick() {
        setLikes(likes + 1);
    }

    return <button onClick={handleClick}>Like ({likes})</button>
}

埋め込みたいページで対象のコンポーネント(今回はLikeButton)をpage.jsでimportして使う
てことでlike-button.js内の関数LikeButtonpage.jsへimportする
<コンポーネント名 />とすることで再利用可能となる

page.js
import LikeButton from "./like-button"

function Header({ title }) {
    return <h1>{title ? title : "Default title"}</h1>
}

export default function HomePage() {
    const names = ["Ada Lovelace", "Grace Hopper", "Margaret Hamilton"]

    return (
        <div>
            <Header title="Develop. Preview. Ship." />
            <ul>
                {names.map((name) => (
                    <li key={name}>{name}</li>
                ))}
            </ul>

            <LikeButton />
        </div>
    )
}