月: 2025年1月

  • Reace Hooks その③

    useStateで配列を更新しリアルタイムで表示を変える

    今回はuseStateで配列の値を管理し、それをリアルタイムで表示していきます。

    今回の書き方は管理者側の更新画面などでReactで頻繁に出てくるものなので、少し複雑ですが頑張っていきましょう。

    app/componentsフォルダに「todoList.js」を作成しTodoListコンポーネントを定義します。

    "use client";
    
    import { useState } from "react";
    
    export default function TodoList() {
        // 配列を `useState` で管理
        const [items, setItems] = useState([]);
        const [text, setText] = useState("");
    
        // 入力値を更新
        const handleChange = (e) => {
            setText(e.target.value);
        };
    
        // 配列に新しいアイテムを追加
        const addItem = () => {
            setItems([...items, text]); // 新しい配列を作成(スプレッド構文)
            setText(""); // 入力欄をクリア
        };
    
        return (
            <div>
                <h2>Todo List</h2>
                <input type="text" value={text} onChange={handleChange} />
                <button onClick={addItem}>追加</button>
    
                <ul>
                    {items.map((item, index) => (
                        <li key={index}>{item}</li>
                    ))}
                </ul>
            </div>
        );
    }
    

    次にapp/page.jsでTodoListコンポーネントを読み込みます。

    import TodoList from "./components/todoList";
    <TodoList />

    このように、inputタグに入力し、「追加」ボタンをクリックするとリストがリアルタイムで増えていきます。

    コード解説

    上からTodoListコンポーネント内のコードを順に解説していきます。

    useStateを使って、リスト用の配列「items」と入力値の管理用の値「text」を定義しています。

    初期値はそれぞれ空の配列と空の文字列です。

    const [items, setItems] = useState([]);
    const [text, setText] = useState("");

    次に、textを更新するイベントハンドラ「handleChange」関数を定義しています。

     const handleChange = (e) => {
            setText(e.target.value);
        };
    

    そしてitemsを更新するイベントハンドラ「addItem」関数を定義しています。

    const addItem = () => {
            setItems([...items, text]); // 新しい配列を作成(スプレッド構文)
            setText(""); // 入力欄をクリア
        };

    ここで見慣れない書き方がされています。

    setItems([...items, text]);

    これは、元のitemsをスプレッド構文で展開しそれにtextの値を足した新しい配列を新しいitems配列として定義・更新しています。

    stateで扱う値は直接変更できない。というルールがあるため、元の配列に要素を追加するのではなく、新たな配列として定義する形をとっています。

    また、下記のように値を使用したら空にしてクリアするのもReactでは一般的な作法となります。

     setText("");

    JSXでは「追加」ボタンをクリックしたらinputタグに入力されている値が<li>タグとして追加される記述をしています。

     return (
            <div>
                <h2>Todo List</h2>
                <input type="text" value={text} onChange={handleChange} />
                <button onClick={addItem}>追加</button>
    
                <ul>
                    {items.map((item, index) => (
                        <li key={index}>{item}</li>
                    ))}
                </ul>
            </div>
        );

    まず見慣れないのは<ul>の中身です。

      {items.map((item, index) => (
         <li key={index}>{item}</li>
      ))}

    mapメソッドを使ったリスト作成

    mapメソッドは元の配列の各要素を加工して新しい配列を作るJavascriptのメソッドです。

    今回の記述だと、items配列の各要素を基に<li>JSXタグを要素とする配列を作っています。

    最後に、indexとkeyについて説明します。

    <li key={index}>{item}</li>

    ここで「key」をmapメソッドの生成するindexの値を入れていますが、

    Reactではリストには「key属性」を必ず指定するというルールがあるためです。

    なぜこのようなルールがあるかについての詳細な説明は省きますが、ルールとして覚えておいてください。

    また、今回のindexの指定の仕方だと、実はリストの「変更」「削除」があるような場合には不適切です。

    こちらもまた今後解説します。

    textのstateを作った理由(※飛ばしてもOK)

    こちらは興味のある方のみでOKですが、今回stateで管理する値を

    • test
    • items

    の2つ用意しました。

    JQueryでのDOM操作に慣れている方なら、

    「addItem」関数内で直接inputタグの値を参照すればよいのでは?と思うかもしれません
    例:)

    const addItem = () => {
        const inputValue = document.querySelector("input").value; 
        setItems([...items, inputValue]);
    };

    これは実は動くことは動くのですが、以下の理由で推奨されません。

    1. 更新タイミングがずれる可能性がある(値が最新でない)。
    2. 入力欄のクリアが難しい。
    3. 直接 DOM を操作している(React の流儀に反する)。

    stateが更新される度に画面が更新(再レンダリング)されるため、stateを使わないと値が最新でない可能性があるというのが一番の理由になります。

    このstateが更新される度に画面が更新(再レンダリング)されるという特性は重要なReactの機能なので覚えておいてください。

  • Reace Hooks その②

    useStateでテキスト入力

    useStateを使って入力したテキストがリアルタイムで表示されるようにしてみましょう。

    まずはapp/componentsフォルダにtextInput.jsを作成しTextInputコンポーネントを定義します。

    "use client";
    
    import { useState } from "react";
    
    export default function TextInput() {
        const [text, setText] = useState("");
    
        return (
            <div>
                <input
                    type="text"
                    value={text}
                    onChange={(e) => setText(e.target.value)}
                />
                <p>You typed: {text}</p>
            </div>
        );
    }

    次にapp/page.jsでTextInputコンポーネントを呼び出して表示します。

    import TextInput from "./components/textInput";
    <TextInput />

    入力フォームに入力したテキストがリアルタイムで「You tiped:」の箇所に反映されます。

    コード解説

    textInput.jsのコードを解説していきます。

    クライアントコンポーネントの宣言、useStateのインポートをします。

    "use client";
    
    import { useState } from "react";

    textを更新するための設定をします。初期値は空テキスト「””」です。

     const [text, setText] = useState("");

    inputタグのonChangeイベントでtextの更新処理ができるように記述しています。

      return (
            <div>
                <input
                    type="text"
                    value={text}
                    onChange={(e) => setText(e.target.value)}
                />
                <p>You typed: {text}</p>
            </div>
        );

    見慣れない記述かと思いますが、ここでのイベントハンドラはアロー関数により定義されているので、下記のように定義したのと同じ意味になります。

     function handleChange(e) {
            setText(e.target.value);
        }
    
        return (
            <div>
                <input 
                    type="text"
                    value={text}
                    onChange={handleChange} 
                />
                <p>You typed: {text}</p>
            </div>

    アロー関数は「式」なのでJSX内に値としてそのまま埋め込めるというわけです。

    useStateでクラスのON・OFF

    次に、CSSとJavascriptを組み合わせて見た目を変化させる時によく使うクラスのON・OFFのやり方を見ていきましょう。

    まずはapp/componentsフォルダに「toggleButton.js」ファイルを作成し、下記コードを記述します。

    "use client";
    
    import { useState } from "react";
    import "./styles.css"; // CSSファイルを適用
    
    export default function ToggleButton() {
        // 初期状態は OFF(false)
        const [isActive, setIsActive] = useState(false);
    
        // アロー関数で ON / OFF を切り替える
        const toggleActive = () => setIsActive(prev => !prev);
    
        return (
            <button
                className={isActive ? "active" : ""}
                onClick={toggleActive}
            >
                {isActive ? "Active" : "Inactive"}
            </button>
        );
    }

    次にapp/componentsフォルダに「sytle.css」を作成して下記コードを記述します。

    button {
        padding: 10px 20px;
        font-size: 16px;
        border: none;
        cursor: pointer;
        background-color: lightgray;
        transition: 0.3s;
    }
    
    button.active {
        background-color: dodgerblue;
        color: white;
    }

    最後にapp/page.jsでToggleButtonコンポーネントを呼び出します。

    下記のようにInactiveボタンをクリックするとスタイルがあたります。

    コード解説

    toggleButton.jsのコードを解説していきます。

    • クライアントコンポーネントの宣言
    • useStateのインポート
    • style.cssの読み込み
    "use client";
    
    import { useState } from "react";
    import "./styles.css";

    isActiveを更新する設定をします。初期値は「false」です。

    const [isActive, setIsActive] = useState(false);

    イベントハンドラーtoggleActiveを定義します。

    const toggleActive = () => setIsActive(prev => !prev);

    見慣れない記述がありますが、これは関数型更新と呼ばれる書き方です。
    説明が長くなるので説明は後述します。

    JSX内ではbuttonタグがクリックされる度にisActiveがtureとfalseで反転する記述を書いています。

    return (
            <button
                className={isActive ? "active" : ""}
                onClick={toggleActive}
            >
                {isActive ? "Active" : "Inactive"}
            </button>
        );

    クラスはReactでは「class」ではなく「className」と書きます。

    {isActive ? "active" : ""}
    {isActive ? "Active" : "Inactive"}

    この記述は2つとも「三項演算子」です。

    isActiveの値が「true」か「false」かによって返す値を分けています。

    三項演算子は「式」なのでJSX内に値として{}の中に入れられます。

    関数型更新

    関数型更新とは?

    初期値ではisActiveは「false」で、「!」は値を反転させる記号なので、!isActiveは「true」となります。
    一度クリックするとisActiveは「true」に更新されて、!isActiveは「false」ということになります。
    このように記述することでクリックする度にtrueとfalseが反転する処理を記述しています。

    このように常に最新のstateの値を基にした処理を書きたいときにこの関数型更新を使用します。

    「常に最新のstateの値」とはどういうことか?

    例えば下記のようなコードを書いたとします。

    function Counter() {
        const [count, setCount] = useState(0);
    
        function handleClick() {
            setCount(count + 1);
            setCount(count + 1);
            setCount(count + 1);
        }
    
        return (
            <div>
                <p>Count: {count}</p>
                <button onClick={handleClick}>+3</button>
            </div>
        );
    }

    このコードだとbuttonタグをクリックする度に「3ずつ」数字が増えそうなものですが、実際は「1ずつ」しか増えません。
    これはuseStateが非同期で動くからなのですが、なぜそうなるのかの詳細な説明は省きます。

    上記の奥に「3ずつ」増やしたい場合は下記のように記述します。

    function Counter() {
        const [count, setCount] = useState(0);
    
        function handleClick() {
            setCount(prev => prev + 1);
            setCount(prev => prev + 1);
            setCount(prev => prev + 1);
        }
    
        return (
            <div>
                <p>Count: {count}</p>
                <button onClick={handleClick}>+3</button>
            </div>
        );
    }

    このように記述することでhandleClick関数の処理の中でcountの値が関数型更新により順番に1ずつ加算され、最終的に一回のクリックで「3ずつ」増えます。

    次回はuseStateで配列を更新する手順を見ていきましょう。

  • Reace Hooks その①

    Hooksとは

    React の Hooks(フック) とは、関数コンポーネントで「状態(state)」や「ライフサイクル」の機能を使うための仕組み です。頻繁に使うHooksの解説をしていきます。

    useState

    Hooksの一つであるuseStateについて見ていきます。

    useStateとは

    useStateとはコンポーネントが持つ「動的なデータ」を管理するために使うHooksです。

    Next.jsの構築

    まず、Next.jsを構築しましょう。構築するフォルダをVScodeで開きターミナルで下記コードを入力します。

    npx create-next-app@latest hooks-app

    このように表示されていればNext.js構築完了です。

    ページ作成

    次にapp/pages.jsのHomeコンポーネントの中のreturn内の記述を削除します。

    次に、appフォルダにcomponentsフォルダを作成し「useState.js」ファイルを作成、下記コードを記述してください。

    "use client";
    
    import { useState } from "react";
    
    export default function Counter() {
        const [count, setCount] = useState(0);
    
        // アロー関数でイベントハンドラを定義
        const handleClick = () => setCount(count + 1);
    
        return (
            <div>
                <p>カウント: {count}</p>
                <button onClick={handleClick}>+1</button>
            </div>
        );
    }

    最後にapp/page.jsでCounterコンポーネントを呼び出します。

    import Counter from "./components/useState";
    
    export default function Home() {
      return (
        <Counter />
      );
    }

    ターミナルで開発サーバーを起動しhttp://localhost:3000/にアクセスすると下のように表示されます。

    npm run dev

    「+1」をクリックするとカウントの横の数字が増えていきます。

    コード解説

    app/components/useState.jsのコードを上から解説していきます。

    これはuseStateを使うための準備で、このコンポーネントをクライアントコンポーネントとして扱うという宣言です。

    use client"; 

    詳細の説明は省きますが、Next.jsでは

    • サーバーコンポーネント
    • クライアントコンポーネント

    という区別があり、useStateはクライアントコンポーネントでしか使えないというルールがあります。

    useStateを使用するためにreactからインポートしています。

    import { useState } from "react";

    ここでuseStateを使ってcountの状態管理をするための設定をしています。

    const [count, setCount] = useState(0);

    これは下図のような仕組みに基づきます。

    ここでクリックイベント用の関数を定義しています。※イベントハンドラといいます。

    const handleClick = () => setCount(count + 1);

    この書き方はアロー関数といいます。下図のように書き換え可能です。

    アロー関数もよく使うので書き方に慣れておいてください。

    最後にbuttonタグをクリックするとhandleClick関数が発火し、setCount関数がcountの値を更新するというJSXの記述になります。

       return (
            <div>
                <p>カウント: {count}</p>
                <button onClick={handleClick}>+1</button>
            </div>
        );

    useStateの特徴

    • React の Hooks の 1 つ
    • 状態が更新と自動的に再レンダリング(再描画)される
    • state は直接変更できない更新用関数のsetStateで変更・更新する

    次回はuseStateの色々な使い方を見ていきましょう。

  • Next.js構築 その⑩

    スプレッド構文とは

    スプレッド構文について説明します。

    スプレッド構文は配列やオブジェクトを「展開」する機能を持ちます。

    まずは下記のようなpersonというオブジェクトがあったとします。

    const person = {
        name: "Alice",
        age: 25,
        city: "Tokyo"
    };
    

    このpersonの中身を複製したnewPersonというオブジェクトを作成したいとして、

    const newPerson = person;

    このように記述すると、Javascriptの特性上「複製」ではなくnewPersonが元のpersonのデータを指すという意味になります。

    これだと、newPersonの中身だけ変更したい場合など、複製した上でそのデータを扱う場合に不便です。そこで使用するのがスプレッド構文です。

    書き方は下記のように、複製したいpersonの前に「…」をつけます。

    const newPerson = { ...person };

    このように記述することで、personの中身を展開した上で複製し、新たなnewPersonを作成できます。

    今回はオブジェクトを例に出しましたが配列でも使用可能です。

    スプレッド構文を使ったデータの継承

    オブジェクトとスプレッド構文を使って複数のデータを継承してみましょう。

    まずはapp/components/offspringフォルダに「spreadGC.js」を作成し、SpreadGcコンポーネントを定義します。

    export default function SpreadGc(props) {
        return (
            <div>
                <h3>I am the grandchild.</h3>
                <p>Name: {props.name}</p>
                <p>Age: {props.age}</p>
                <p>Favorite Color: {props.color}</p>
            </div>
        );
    }

    次にapp/componentsフォルダに「spreadChild.js」を作成しSpreadChildコンポーネントを定義します。

    import SpreadGc from "./offspring/spreadGC";
    
    export default function SpreadChild(props) {
        return (
            <div>
                <h2>I am the child.</h2>
                {/* スプレッド構文で全てのpropsを孫に渡す */}
                <SpreadGc {...props} />
            </div>
        );
    }

    最後にapp/page.jsでSpreadChildコンポーネントを定義し、personオブジェクトをpropsとして渡します。

    import SpreadChild from "./components/spreadChild";
      const person = {
        name: "Alice",
        age: 25,
        color: "blue",
      };
     <h1>I am the parent.</h1>
     {/* スプレッド構文で複数プロパティを子に渡す */}
     <SpreadChild {...person} />

    このように表示されました

    propsはオブジェクト

    今回行ったスプレッド構文を使ったデータの継承を図にまとめると下記のようになります。

    この図でも記載のある通り、propsはオブジェクトです。

    その性質を利用したデータ継承方法ということです。

    propsの特徴

    propsはオブジェクトですが、通常のオブジェクトとは異なる特徴があります。

    • オブジェクトなので分割代入やスプレッド構文が使える
    • 読み取り専用(変更不可)
    • 何も渡されないと {} になる

    データ継承の他の方法

    ここまでpropsを使ったデータ継承を見てきました。

    しかし、

    親から子、子から孫に明示的に渡す必要があるので、深いネストでの管理が複雑になる場合がある

    というデメリットがあります。

    ですので、他の方法としてContext APIReduxのような状態管理ツールといったものがReactでは用意されています。

    今は「そういうものもあるんだな」程度に考えておいてください。

  • Next.js構築 その⑨

    propsを使ってデータを渡そう

    今回はコンポーネント間でデータを受け渡す方法について見ていきます。

    Propsとは

    props(プロップス)は、親コンポーネントから子コンポーネントへデータを渡す仕組みです。

    • 親から子へ一方向に渡されるデータで、子コンポーネント側でデータを受け取って利用します。
    • propsの値は子コンポーネント内で変更できない(読み取り専用)。

    使い方

    では実際に動きを見ていきます。

    まずはapp/componentsフォルダに「props.js」ファイルを作成します。

    次にpropsを受け取る子コンポーネントを定義します。

    ここでは「content」というデータを受け取れるようにしています。

    export default function Props(props) {
        return <h1>{props.content}</h1>;
    }

    次にapp/page.jsでこのPropsコンポーネントを呼び出します。その際渡したいデータを定義します。

    import Props from "./components/props";
    <Props content="これはpropsで渡ってきたデータです。" />

    表示できました。

    孫コンポーネントへのデータ継承

    次に、親から子、子からさらに孫コンポーネントにデータを継承してみましょう。

    まず、app/componentsフォルダに「offSpring」フォルダを作成し、grandChild.jsを作成しGrandChildコンポーネントを定義します。

    ここでは「title」というデータを受け取れるようにしています。

    export default function GrandChild(props) {
        return <h1>{props.title}</h1>;
    }

    次にapp/componentフォルダにchild.jsを作成し、Childコンポーネントを定義します。

    import GrandChild from "./offspring/grandChild";
    
    export default function Child(props) {
        return (
            <GrandChild title={props.title} />
        );
    }

    最後にapp/page.jsでChildコンポーネントを読み込み、データを渡します。

    import Child from "./components/child";
    <Child title="これはpropsで渡ってきたtitleです。" />

    表示されました。

    どのような状況で使うのか?

    propsでデータを渡す方法を説明してきましたが、具体的にどういった状況で使用するかをまとめました。

    1. 再利用可能なコンポーネントを作りたいとき
    2. 親から子にデータやロジックを渡したいとき
    3. 動的なデータを扱いたいとき
    4. スタイルや設定を動的に変えたいとき

    いまいちピンとこないかもしれませんが、今はこういうことがある、という風に気に留めておいてもらえばOKです。

    複数のデータを渡す場合

    これまで渡すデータは1つでしたが、複数ある場合も見ていきましょう

    まずはapp/components/offspringフォルダに「multipleGC.js」を作成し、MultipleGCコンポーネントを定義します。ここではpropA,propB,propCを受け取れます。

    export default function MultipleGc(props) {
        return (
            <>
                <p>{props.propA}</p>
                <p>{props.propB}</p>
                <p>{props.propC}</p>
            </>
        );
    }

    次にapp/componentsに「multipleCilld.js」を作成しMultipleChildコンポーネントを定義します。

    import MultipleGc from "./offspring/multipleGC";
    
    export default function MultipleChild(props) {
        return (
            <MultipleGc propA={props.propA} propB={props.propB} propC={props.propC} />
        );
    }

    最後にapp/pages.jsでMultipleChildコンポーネントを読み込んで、データを渡します。

    import MultipleChild from "./components/multipleChild";
    <MultipleChild propA="データA" propB="データB" propC="データC" />

    表示できました。

    ただ、上記のやり方だと

    propA="..." propB="..." propC="..." 

    という記述が2回出てきており、コードとしては冗長といえます。

    これを回避する方法はいくつかありますが、そのうちの一つである

    スプレッド構文

    について次回見ていきます。

  • Next.js構築 その⑧

    Javascriptの扱い方

    これまでWebページを構成するHTML(JSX)、CSS、画像ファイルの使い方を見てきました。

    もう一つWebページに欠かせないJavascriptの扱い方について見ていきましょう。

    まずは今回記述する内容のためのコンポーネントをcomponentsフォルダに作成します。

    次に下記のコードを記述します。

    export default function JScode() {
        // 前半での処理
        const name = "Alice";
        const baseAge = 20;
    
        // 計算処理
        const doubleAge = baseAge * 2;
    
        // 条件分岐によるメッセージ設定
        const message = baseAge > 18 ? "You are an adult." : "You are a minor.";
    
        // 現在の日時
        const currentDate = new Date().toLocaleDateString();
    
        // JSX内で値を使う
        return (
            <div>
                <h1>Hello, {name}!</h1>
                <p>Your age: {baseAge}</p>
                <p>Double your age: {doubleAge}</p>
                <p>{message}</p>
                <p>Today's date: {currentDate}</p>
            </div>
        );
    }

    このように、コンポーネント内の前半部分で色々な処理を書き、JSX内で{}を使って値を扱います。

    {}の中に入れられるのは厳密には値そのものでなくても「値を返す式」であれば入れられます。

    実際に動きを確認しましょう。app/page.jsでJScodeコンポーネントを読み込みます。

    import JScode from "./components/javascript";
     <JScode />

    表示できました。

    JScodeコンポーネント内を書き換えてみましょう。

    それぞれ式の右側をそのまま{}に入れてみましたが、表示内容は変わりません。

    これは入れ替えた3つの処理が「値を返す式」なのでJSX内でそのまま扱えるということです。

    逆にJSX内で扱えないものは「文」と呼ばれるものです。下記のようなif文などがそれにあたります。

        if (baseAge > 18) {
            message = "You are an adult.";
        } else {
            message = "You are a minor.";
        }

    この場合if文は値を返さないので、JSXではmessageを表示させるには下記のような書き方になります。

        let message;
        if (baseAge > 18) {
            message = "You are an adult.";
        } else {
            message = "You are a minor.";
        }

    JSX内

    <p>{message}</p>

    You are an adult.が追加されました。

    このように、Reactではコンポーネント内に、表示させたい内容にまつわるJavascriptの処理とHTML(JSX)をセットにして記述できるので、管理しやすくなっています。

    三項演算子

    さきほど出てきた

     const message = baseAge > 18 ? "You are an adult." : "You are a minor.";

    この見慣れない記述について解説します。これは三項演算子と呼ばれるもので、if文を式として扱えるようにしたものです。

    条件式がTrueのときの値とfalseのときの値を上記のように書いて、それに基づいて値を返します。

    今回は以上です。

  • Next.js構築 その⑦

    CSSをあてよう

    CSSをあてていきましょう。

    まずは「public」フォルダ内に「asset」フォルダを作成し、その中に「css」フォルダを作成し、更にその中に「style.css」ファイルを作成します。

    style.cssの中にスタイルを記述します。

    /* h1スタイル */
    h1 {
        font-size: 2.5rem;
        /* 大きな見出しサイズ */
        color: #333;
        /* 濃いグレー */
        text-align: center;
        /* 中央揃え */
        margin: 20px 0;
        /* 上下に余白 */
        text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.1);
        /* 軽い影 */
    }
    
    /* aタグのスタイル */
    a {
        color: #0070f3;
        /* 明るい青色 */
        text-decoration: none;
        /* 下線を削除 */
        font-weight: bold;
        /* 太字 */
        transition: color 0.3s ease;
        /* 色変化のアニメーション */
    }
    
    a:hover {
        color: #0056b3;
        /* ホバー時の濃い青色 */
        text-decoration: underline;
        /* 下線を追加 */
    }

    次に、layout.jsでstyle.cssを読み込みます。

    import '../public/asset/css/style.css';

    npm run devで開発サーバーを立ち上げ、http://localhost:3000にアクセスし、下のように表示されれば成功です。

    特定のページのみであてたいCSS

    場合によってはページごとにCSSを管理したいことがあります。aboutページを例にとって作成してみます。

    まずはapp/aboutフォルダに「about.css」を作成します。

    about.css内にスタイルを記述します。

    /* Aboutページ専用スタイル */
    h1 {
        font-size: 2.5rem;
        color: #ff6347; /* トマト色 */
        text-align: left;
        margin: 20px 0;
    }
    
    p {
        font-size: 1rem;
        line-height: 1.6;
        color: #333;
    }

    次にapp/about/page.jsでabout.cssを読み込みます。

    http://localhost:3000/aboutにアクセスし、下のように表示されれば成功です。

    それぞれの画面を検証ツールで見てましょう

    about

    top

    aboutページにはh1に対して2つのスタイルがあたっているのに対し、トップページでは1つだけです。

    about.cssがaboutページにのみあたっていることが確認できます。

    ファイルの置き場所について

    CSSファイルの置き場所ですが、現在下図のようになっています。

    これは置き場所に決まりがあるわけではなく、一般的な配置の仕方にしていますが、
    実際は管理しやすいように自由に配置できます。
    その際はimportでよみこむ際のパスに気をつけましょう。

    画像を配置しよう

    画像の配置について見ていきます。

    まずはpublic/assetに「img」フォルダを作成し、適当な画像を配置します。

    次に、app/components/welcome.jsでImageコンポーネントをインポートし、Welcomeコンポーネント内に配置します。

    import Image from "next/image";
     <Image
           src="/asset/img/image.jpg"
           alt="Example Image"
           width={500}
           height={300}
      />

    表示できました。

    今回のImageコンポーネントについて、srcのパスが

     src="/asset/img/image.jpg"

    となっています。

    これはpublic/ディレクトリはルートパス(/)として扱われるため、このような記述になっています。

    また、下記記述

    width={500}
    height={300}

    これはimageタグのwidthとheightを指定するものですが、Imageコンポーネントでは指定必須になっています。CSSで上書きできるので、一旦適当な数値を入れておきましょう。

    書き方について、imageタグであればwidth=”500″と記述しますが、width={500}となっています。

    この書き方について次回説明していきます。

  • Next.js構築 その⑥

    ページの追加

    現在はトップページのみですので、ページ追加をしてみましょう。

    まず、appフォルダ内にページのフォルダを作成します。
    ここでは「about」ページを作る想定です。

    次にaboutフォルダ内にpage.jsを作成します。

    page.jsに下記コンポーネントを定義します。

    export default function About() {
        return (
            <div>
                <h1>About Page</h1>
                <p>これはAboutページです。</p>
            </div>
        );
    }

    これでブラウザでhttp://localhost:3000/aboutにアクセスすると、新しいページが表示されます。

    トップページにリンク作成

    トップページに先ほど作成したaboutページへのリンクを作成します。

    Reactでは<Link>コンポーネントを使用することが推奨されているので、まずはwelcome.js内で<Link>コンポーネントをインポートします。

    import Link from "next/link";

    次にwelcomeコンポーネント内に<Link>コンポーネントを記述します。

     <Link href="/about">About</Link >

    ここで、
    「JSX式には1つの親要素が必要です。」
    というエラーが出ています。
    これは
    ・コンポーネントのreturn内は1つのタグで囲われている必要がある。

    という意味です。ですので、
    <h1>タグと<Link>コンポーネントを1つのタグで囲んでみます。

    エラーが消えました。

    またReactではフラグメントというJSXの親要素用の特殊なタグが用意されています。

    <></>

    書き方は他にもありますが、これで覚えてしまって良いです。

    <div>を<>に置き換えてもエラーが出ません。
    これで動作を確認してみましょう。

    Aboutリンクをクリックすると

    Aboutページに飛んでこれました。

    Reactではこのようにしてページ作成ができます。

  • Next.js構築 その⑤

    コンポーネントとは

    コンポーネントの言葉の定義から見ていきます。

    まず、REACTにおけるコンポーネントというのは、画面の各構成要素をREACTで定義したものだと捉えてください。

    ページにはいろいろな部品。例えばヘッダーやサイドバーがあったりします。

    色々な構成要素がありますが、このそれぞれの部品をREACTで定義したものをコンポーネントという風に呼びます。

    コンポーネントを使用するメリット

    1. 再利用性の向上
      まず、コンポーネントで部品を定義するので、コードの再利用性が上がります。
      例えば、一つ定義したコンポーネントを、またページの別の部分で使いたいといった場合にも、同じコードをもう一回書く必要はなく、コンポーネントを使いたい部分で再度読み込み直せばいいので、再利用性が上がります。
    2. 可読性の向上
      REACTではコンポーネントごとにそのコンポーネントに含まれる制御を記述しますので、色々な場所のコードを見る必要がありません。一つの場所を見るだけでいいので、コードを追いやすくなります。
    3. 疎結合になる
      プログラミングになじみのない方は聞き慣れない言葉だと思いますが、これはコンポーネント同士の結びつきをなるべく緩くすることができるという意味合いです。
      それにより再利用性が上がったり、コンポーネントごとにテストができるようになるので、バグの混入を防ぐことができます。

    コンポーネントの定義

    コンポーネントはJavascritの関数で下記にようにして定義します。

    ここではWelcomeという関数を定義していますが、関数名の先頭を大文字することによって、コンポーネントであることを表わします。

    またコンポーネントはJSXを返します。

    コンポーネントの作成

    では実際にコンポーネントを作成してみましょう。

    まず、page.jsのreturnの中身をすべて削除します。

    export default function Home() {
      return (
    //この中をすべて削除
    );
    }

    結果

    次に、下記コードを記入して下さい。

     function Welcome(){
      return<h1>Hello</h1>;
     }

    returnに()がありませんが、returnで記述するコードが1行であれば()は省略できます。
    結果

    さらに、Homeコンポーネント内に下記コードを記述してください。

    <Welcome />

    結果

    そしてターミナルで下記入力し開発サーバーを起動してhttp://localhost:3000/にアクセスしてください。

    npm run dev

    このように表示されていれば成功です。

    コンポーネントをファイル分割

    コンポーネントは上記のように同じファイルで記述するのでなく、ファイルを分割して書くことが一般的です。さきほどのコンポーネントを別ファイルに分割してみましょう。

    まず分割するファイルとそれを設置するディレクトリを作成します。
    app/components/welcome.js

    次にpage.jsからコンポーネントをカットしてください。

    結果

    先ほどカットしたコンポーネントをwelcome.jsに貼り付けます。

    続けて、welcome.jsのWelcomコンポーネンㇳを他のファイルで扱えるように下記コードを追記します。

    export default

    「default」 をつけるかつけないかで、読み込み先での扱い方が変わるのですが、詳細の説明は今回は省きます。

    次にpage.jsに下記コードを書いてWelcomeコンポーネントを読み込みます。

    import Welcome from "./components/welcome";

    書き方は

    import 「コンポーネント名」 from 「ファイルのパス」

    です。

    ページを読み込み直しても結果が先程と同じになります。

    見えている画面は先程と同じですが、現在のページの構成は下記のようになっています。

    ここまででコンポーネントについて学んできました。

  • Next.js構築 その④

    プロジェクト構造の理解(App Router版)

    主なフォルダとファイル

    • app/: ルート構造を管理するディレクトリ。
      • 各サブフォルダがルート(ページ)になります。
      • フォルダ内のpage.jsが、そのルートのコンポーネントを定義します。
    • public/: 静的ファイルを配置する場所(例:画像やフォント)。
    • package.json: プロジェクトの依存関係やスクリプトが記載されています。
    my-next-app/
    ├── app/
    │   ├── page.js      # ルートページのコンポーネント
    │   └── layout.js    # 共通のレイアウト(ヘッダーやフッターなど)
    │   └── favicon.ico  # サイトのアイコン
    │   ├── globals.css  # グローバルスタイル
    ├── public/           # 画像
    ├── package.json
    

    実際にpage.jsとlayout.jsの中身を見てみましょう。

    app\page.js

    簡単に説明すると上から、

    importを使って他のディレクトリからコンポーネントと呼ばれるものを呼び出しています。
    (ここではImageコンポーネントをnext/imageから呼び出しています。)

    import Image from "next/image";

    関数定義のように見える下の箇所はコンポーネントを定義しています。

    export default function Home() {
    ...
    }

    return内でこのコンポーネントの戻り値を記述しています。HTMLのように見えますが、

    JSX

    と呼ばれるReactの記述です。ここで出力するHTMLを記述しています。

    return(
    ...
    );

    JSX自体はほぼHTMLと記法が変わりありませんが異なる点として、

    「class」が「className」になっています。

     <div className="...">

    classの代わりにこう書くと覚えておいて下さい。

    またimgタグが「<Image>」になっています。

    <Image
              className="dark:invert"
              src="/next.svg"
              alt="Next.js logo"
              width={180}
              height={38}
              priority
            />

    これはファイルの冒頭でインポートしたImageコンポーネントを利用するため、このような記述になっています。<img>タグでも動作します。

    app\layout.js

    冒頭では使用するフォント設定とCSSを呼び出しています。

    import { Geist, Geist_Mono } from "next/font/google";
    import "./globals.css";

    中盤の部分でフォントとmeta情報に関する定数が設定されています。

    const geistSans = Geist({
      variable: "--font-geist-sans",
      subsets: ["latin"],
    });
    
    const geistMono = Geist_Mono({
      variable: "--font-geist-mono",
      subsets: ["latin"],
    });
    
    export const metadata = {
      title: "Create Next App",
      description: "Generated by create next app",
    };

    最後にJSXを戻り値とするコンポーネントが設定されています。

    export default function RootLayout({ children }) {
      return (
        <html lang="en">
          <body
            className={`${geistSans.variable} ${geistMono.variable} antialiased`}
          >
            {children}
          </body>
        </html>
      );
    }

    layouts.jsのこのような構成はReactではよく見られる構成です。

    1. importで必要なコンポーネントやファイルを読み込む。
    2. 使用する関数や定数を設定する。
    3. JSXを返すコンポーネントを記述する。

    トップページの成り立ち

    ターミナルで下記入力をし、開発サーバーを起動します。

    npm run dev

    そのうえで http://localhost:3000 にアクセスすると下記画面が表示されます。

    これはNext.jsデフォルトのトップページです。
    このトップページはこれまで見てきた、

    • page.js
    • layout.js

    により構成されています。
    具体的にはそれぞれのファイルで定義されているコンポーネントが入れ子構造なっており、それをNext.jsが内部的に処理してHTMLを出力(レンダリング)しています。

    コンポーネントはそれぞれ下記のことです。

    ・page.js

    export default function Home() {
      return (
    ...
    );
    ]

    ・layout.js

    export default function RootLayout({ children }) {
      return (
    ...
    );
    }

    次章ではこのコンポーネントについて詳しく解説します。