【React】配列の表示方法(リスト表示、map,filter)配列の取り出し | 表示されない場合の原因と対処方法

2022年11月27日React

Reactで配列を表示する方法について紹介します。
まずはReactではどんな方法で配列を表示できるのか単純なリスト表示から解説を始めます。
その後、Reactでよく使うmapとfilterで配列を編集したり必要な要素のみ取り出したりする方法を紹介します。
最後に、よくあるReactでmapを使用してしてもリストが表示されない場合の原因と対処方法を説明しています。

Reactで配列を表示する方法

べた書きする(ほぼ使わない)

まず、以下のような方法は非効率なため、通常とりません。

const animals = ["犬", "ゴリラ", "たぬき"];

const Example = () => {

  return (
    <>
      <h3>配列の操作</h3>
      <ul>
        <li>{animals[0]}</li>
        <li>{animals[1]}</li>
        <li>{animals[2]}</li>
      </ul>
    </>
  );
};

export default Example;

for文で表示


const animals = ["犬", "ゴリラ", "たぬき"];

const Example = () => {

  const list = [];
  for (const animal of animals) {
    list.push(<li>{animal}</li>)
  }
  return (
    <>
      <h3>配列</h3>
      <ul>
        {list}
      </ul>
    </>
  );
};

export default Example;

for文で、pushしているのはJSXのため、JavaScriptオブジェクトとなります。
最終的には上のベタ書きと同じ形式になります。

for文のデメリット

for文を使用すると、以下のような欠点があります:

  • list.pushを明示的に呼び出す必要があるため、コードが冗長になりやすい。
  • 配列の要素数が多い場合、可読性が低下する。
  • JSX内に直接記述できないため、コード構造がやや複雑になる。

これらの理由から、通常はmapを使用することが推奨されます。

mapで表示(推奨)


const animals = ["犬", "ゴリラ", "たぬき"];

const Example = () => {

  const list = animals.map(animal => <li>{animal}</li>)
  return (
    <>
      <h3>配列</h3>
      <ul>
        {list}
      </ul>
    </>
  );
};

export default Example;

mapを使うとかなりスッキリとした見た目になります。
mapについて、JavaScriptの配列を加工するmap(),filter(),reduce()メソッドの使い方を参照してみてください。
また、for文は文のため、JSX内には記述できないのですが、mapは式のため、下の例のようにJSXに直接記述することも可能です。

const animals = ["犬", "ゴリラ", "たぬき"];

const Example = () => {
  return (
    <>
      <h3>配列の操作</h3>
      <ul>
        {animals.map((animal) => (
          <li key={animal}>{animal}</li>
        ))}
      </ul>
    </>
  );
};

export default Example;

このコードのように、mapを直接JSXに組み込むことで、リストの生成が簡潔になります。
for文ではこのように直接記述することはできません。
JSX内にJavaScriptの式を埋め込む方法と式と文の違いは、JSX内にJavaScriptの式を埋め込む方法と式と文の違いを参照してみてくさだい。

Reactで配列を表示するときには必ずキーを設定する

const animals = ["犬", "ゴリラ", "たぬき"];

const Example = () => {
  const list = animals.map((animal) => <li key={animal}>{animal}</li>);
  return (
    <>
      <h3>配列</h3>
      <ul>{list}</ul>
    </>
  );
};

export default Example;

Reactは、React要素ツリーの差分を検出してDOMを更新(commit)しています。
その差分の検出にkeyがあることで、子要素をすべて洗い直しする必要なく、差分のみを検出できるようになります。
そのため、key属性を必ずつける必要があります。

key属性の注意点

  • keyは、必ず一意の値であること
  • keyに設定した値は、変更しないこと
  • keyは、配列のインデックスは極力使わないこと

配列のインデックスを使わないほうがいいのは、先頭に要素を追加したり削除したりすると、
配列の0番目の要素が変更されるにも関わらず、インデックスが再度振られて、異なる要素にひもづくようになります。
つまり、正しく差分を検出できなくなります。
要素を全部洗い替えしないといけなくなるため、パフォーマンスの低下につながります。

Reactでフィルターメソッドを使う

import { useState } from "react";

const animals = ["犬", "ゴリラ", "たぬき","abc", "def"];

const Example = () => {
  const [filteredVal, setFilteredVal] = useState("");
  const list = animals
    .filter((animal) => animal.indexOf(filteredVal) !== -1)
    .map((animal) => <li key={animal}>{animal}</li>);

  return (
    <>
      <h3>
        配列:
        <input type="text" value={filteredVal} onChange={(e) => setFilteredVal(e.target.value)} />
      </h3>
      <ul>{list}</ul>
    </>
  );
};

export default Example;

filterメソッドを使うことで、一致したものだけを新しい配列に格納することができます。
mapとfilterはチェーンでつなげることができます。
合わせてよく使うものに、indexOfがあります。
indexOfメソッドに関しては、JavaScriptで文字列を操作するを参照してみてくさだい。
簡単にいうと、一致する文字列が含まれている場合は、-1以外を返して、含まれていない場合は-1を返します。
そのため、indexOfで指定した文字列に一致しないかどうかは、indexOfで返される値が-1かどうかを判定すればいいことになります。

animals
    .filter((animal) => animal.toLowerCase().indexOf(filteredVal) !== -1)

小文字でも一致させたいときは、toLowerCase()を使ったりします。

Reactでmapを使用してしてもリストが表示されない場合

以下を確認するといいです。

  • 配列が空、undefined、またはnullではないか確認する。
  • key属性が設定されているか確認する。
  • アロー関数の返り値を正しく記述する。
  • 親コンポーネントからのデータ受け渡しを確認する。
  • 非同期処理の場合、ローディング状態を考慮する。

それぞれ具体的にみてみましょう。

配列が空またはundefined/null

原因:

mapを使用する際、元の配列が空、undefined、またはnullの場合、mapは動作しません。

解決策:

配列が正しく定義されているか、データが正しく取得できているか確認します。
必要に応じてデフォルト値を設定することで、空配列であればエラーを回避できます。

const animals = null; // または空の配列 []

const Example = () => {
  const list = (animals || []).map(animal => <li key={animal}>{animal}</li>);

  return (
    <>
      <h3>配列</h3>
      <ul>{list}</ul>
    </>
  );
};

export default Example;

配列に一意のkeyが設定されていない

原因:

Reactでは、リストの各要素にkeyが必要です。keyが欠如している場合、警告が表示されるほか、リストが正しく更新されない可能性があります。

解決策:

各要素に一意のkey属性を追加します。
一意の値がない場合はインデックスを使用できますが、可能であれば避けるべきです。

const animals = ["犬", "ゴリラ", "たぬき"];

const Example = () => {
  const list = animals.map((animal, index) => (
    <li key={index}>{animal}</li> // 一意の`key`を追加
  ));

  return (
    <>
      <h3>配列</h3>
      <ul>{list}</ul>
    </>
  );
};

export default Example;

map関数の中で返り値を明示していない

原因:

アロー関数で要素を返す際に{}を使用した場合、返り値がundefinedになります。これは、{}がブロックとして解釈されるためです。

解決策:

明示的にreturnを記述するか、括弧()を使用して暗黙的な返り値にします。

const animals = ["犬", "ゴリラ", "たぬき"];

// NG: {}を使うとブロックとして扱われる
const list = animals.map(animal => { 
  <li key={animal}>{animal}</li>; // これでは動作しない
});

// OK: returnを明示的に記述する
const listFixed = animals.map(animal => {
  return <li key={animal}>{animal}</li>;
});

// または括弧()を使う
const listAlternative = animals.map(animal => (
  <li key={animal}>{animal}</li>
));

コンポーネントが正しくレンダリングされていない

原因:

親コンポーネントで状態の更新やデータの受け渡しが正しく行われていない場合、子コンポーネントが正しくレンダリングされません。

解決策:

コンポーネントがレンダリングされる条件を確認します。
データ取得が非同期の場合、ローディング状態やエラーハンドリングを追加します。

import { useState, useEffect } from "react";

const Example = () => {
  const [animals, setAnimals] = useState(null); // 初期値はnull
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    // データを非同期で取得する例
    setTimeout(() => {
      setAnimals(["犬", "ゴリラ", "たぬき"]);
      setLoading(false);
    }, 1000);
  }, []);

  if (loading) return <p>Loading...</p>;
  if (!animals) return <p>No data</p>;

  return (
    <>
      <h3>配列</h3>
      <ul>
        {animals.map(animal => (
          <li key={animal}>{animal}</li>
        ))}
      </ul>
    </>
  );
};

export default Example;

JSXの記述ミス

原因:

タグの書き忘れや、構文エラーが原因でリストが表示されないことがあります。
例えば、要素を返す際に複数の要素が存在する場合、<>(Fragment)でラップする必要があります。

解決策:

タグのペアが正しいか確認します。
必要に応じて<>で要素をラップします。

const animals = ["犬", "ゴリラ", "たぬき"];

// NG: 複数のliが直接返される
// const list = animals.map(animal => <li>{animal}</li><span>詳細</span>);

// OK: Fragmentでラップする
const list = animals.map(animal => (
  <>
    <li key={animal}>{animal}</li>
    <span>詳細</span>
  </>
));

React

Posted by devsakaso