react 入門 3

これまで、入門1では、コンポーネントという形でファイル毎に分割する方法、JSXによりHTMLの役割をjavascriptに組み込む方法、コンポーネントに読み取り専用の引数を与える方法を示しました。
入門2では、コンポーネントにそれぞれの内部の状態を変数として保持する方法、イベントにより内部の関数を呼び出し、状態変数を更新し表示に反映する方法を学びました。
入門3では、JSX内で、動的に別のJSXを生成、選択する方法を示します。

JSXの動的な選択、追加や削除

JSXのループ生成と選択について、例をつかって説明します。次のように、都市の選択リストと選択された都市に応じたメッセージの表示です。

アプリケーションイメージ

index.html

いつものテンプレートです。

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>test</title>
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>


index.js

Forコンポーネントを呼び出しています。また、Forコンポーネントには、選択される都市の名前とIDがセットになったJSONオブジェクトの配列を読み取り専用の引数、localesという名前のpropsとして渡しています。

import React, { StrictMode } from 'react'
import ReactDOM from 'react-dom/client'
import For from './For'

const list_locale = [
    {
        "locale":"東京",
        "locale_id":"tokyo"
    },
    {
        "locale":"神奈川",
        "locale_id":"kanagawa"
    },
    {
        "locale":"大阪",
        "locale_id":"osaka"
    },
]

    
const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(
    <StrictMode>
        <For locales={list_locale}/>
    </StrictMode>
)


For.js

ForコンポーネントはJSXとして、上位からPropsとして渡された都市をoption要素として選択できるselect要素と、選択された都市を表示するp要素、選択された都市を渡すとメッセージを返すIfコンポーネントを返します。
状態変数として、選択された都市名を保存するStateを持ちます。また、ループ処理でselectのoptionをJSXの配列として変数に保存します。
JSXを返す部分では、このoptionをJSXの配列が入った変数を{}で括って表示します。JSXは文字列ではないので、たとえば”+”演算子で繋げたりすることはできません。JSXは、変数に格納できる式で、さらにいうとJSX のそれぞれの要素は React.createElement() を呼ぶための単なる糖衣構文です。
とりあえず、JSXの中で別のJSXを呼び出す際にはJSXが格納された変数を{}で括って記載すること、変数はJSXの配列でも問題なく表示されることを覚えておいてください。

import { useState } from "react"
import If from "./If"

const For = (props) => {

    const [locale,setLocale] = useState(props.locales[0].locale) 

    const list_jsx_options = []
    for(let i=0; i<props.locales.length;i++){
        const jsx = <option value={props.locales[i].lcale_id} key={i}>{props.locales[i].locale}</option>
        list_jsx_options.push(jsx)
    }

 
    const handle_select_locale = (e) =>{
        setLocale(e.target.value)
    }

    return(
        <div>
            <select onChange={handle_select_locale} name="locale">
                {list_jsx_options}
            </select>
            <p>{locale}が選択されました</p>
            <If locale={locale}/>
        </div>
    )
}

export default For

セレクト要素で選択された都市が変化すると、handle_select_localeが呼び出されて、State変数が書き換えられます。
Ifコンポーネントには、State変数が、propsとして渡されています。

If.js

Ifコンポーネントでは、以下のように、PropsによりJSX変数のmessageを選択してreturnの一部として返しています。コンポーネントは、必ず最上位のタグを1つ持つ必要があります。ここでは、message自体がタグを持ったり持たなかったりしているので、sectionタグでmessageを囲っています。

const If = (prop)=>{

    let message = ""
    if(prop.locale === "東京"){
        message = <h3>"大雨のため中止になりました"</h3>
    }else if(prop.locale === "大阪"){
        message = <h4>"雨です。注意してください"</h4>
    }

    return(
        <section>{message}</section>
    )

}

export default If


削除?

index.jsのlist_localeから大阪を削除して下記の部分を削除してみてください。For.jsにそもそも大阪の情報が渡されず、レンダリングされなくなりました。

const list_locale = [
    {
        "locale":"東京",
        "locale_id":"tokyo"
    },
    {
        "locale":"神奈川",
        "locale_id":"kanagawa"
    },
]

しかし、誰が再レンダリングを命じたのでしょうか。reactにおいて、レンダリング、関数コンポーネントの再呼び出しは次の時に発生します。

  • stateが更新された時

  • propsが更新された時

  • 親コンポーネントが再レンダリングされた時

便利ですね。ただ、reactが要求する設計思想が、この動作からわかります。実際に描画に関するコンポーネントは末端に配置しましょう。


おまけ:JSのループ

Forコンポーネントのlist_jsx_optionsは次のようにForEachで書くこともできます。

   const list_jsx_options = []
    props.locales.forEach((item,index) => {
        const jsx = <option value={item.lcale_id} key={index}>{item.locale}</option>
        list_jsx_options2.push(jsx)
    });

    

あるいはmap関数を活用してシンプルに書くこともできます。

const list_jsx_options = props.locales.map((item,index) => 
        <option value={item.lcale_id} key={index}>{item.locale}</option>
    )


この記事が気に入ったらサポートをしてみませんか?