tips / react

Reactで配列の要素をソートする機能

ブログの記事や商品の一覧ページなどに、日付順、タイトル順、カテゴリー順など特定の基準に従って並べ替えができる機能が実装されている場合があります。配列の要素を、あるプロパティを基準に昇順または降順に並べ替えをするには sort() メソッドを使用します。

本記事ではReactでリストを表示し、ボタンをクリックすると特定のプロパティでソート(並べ替え)ができるページを作成します。ソートするプロパティ名のボタンを用意し、一度目のクリックで昇順に、続けて同じボタンをクリックすると降順になるようにします。

※ 本記事はReactでコードを書ける環境が整っていることを前提とします。
※ CSSは省略します。適宜スタイルを追加してください。

環境

webpack / babel / React / SCSS

実現したいこと

  • Reactでリストを表示するページを作成
  • ボタンを設置し、特定のプロパティを基準にソート
  • ボタンをクリックする度に昇順・降順を切り替える

配列のリストを表示する

List.js を作成して、配列の項目を表示するための List コンポーネントを作成します。

List.js
import React from 'react';

const List = () => (
  <li>
    <p>ID : 1</p>
    <p>The Dark Knight(2008</p>
    <p>Category : Action</p>
  </li>
);

export default List;

App コンポーネントに List コンポーネントをimportして表示します。

App.js
import List from './List';

const App = () => {
  return (
    <ul>
      <List />
    </ul>
 );
}

export default App;

ローカルのwebサーバーを起動するとListコンポーネントの内容が表示されます。

how to sort items with react 01

配列を用意してApp コンポーネントから props を通して List コンポーネントに渡します。配列の要素をそれぞれ表示するには map() メソッドを使用します。

App.js
const DATA = {
  movies: [
    {
      id: 1,
      title: 'Dunkirk',
      category: 'Action',
      year: '2017'
    },
    {
      id: 2,
      title: 'Interstellar',
      category: 'Sci-Fi',
      year: '2014'
    },
  ]
};

const App = () => {
  return (
    <div className="app">
      <ul className="list">
        {
          DATA.movies.map((data, index) => (
            <List
              key={index}
              data={data} />
          ))
        }
      </ul>
    </div>
  );
}

List コンポーネントでは、受け取った値を表示するように書き換えます。 {data}props として、表示する部分を {props.data.id} などとしても同じ表示結果になります。

List.js
const List = ({data}) => (
  <li>
    <p className="list_id"><span>ID :</span> {data.id}</p>
    <p>{data.title}{data.year}</p>
    <p className="list_cat"><span>Category :</span> {data.category}</p>
  </li>
);

配列の各要素がリストになって表示されました。

how to sort items with react 02

ソート用のボタンを設置する

Button.js を作成し、 Button コンポーネントを作成します。

Button.js
import React from 'react';

const Button = () => (
  <button>ID</button>
);

export default Button;

Appコンポーネントでimportして button を表示します。

App.js
import Button from './Button';

const App = () => {
  return(
    <div className="app">
      <Button />
    </div>
  );
}

ソートに使用するプロパティをボタンに渡すために、データの配列から基準になるプロパティ名のみを抽出します。指定したオブジェクトのプロパティ名の配列を取得できる Object.keys() メソッドを使用します。

App.js
const KEYS = Object.keys(DATA.movies[0]);

取得したプロパティ名の配列をリストと同様に props として map() メソッドを使用して Button コンポーネントに渡します。

App.js
{
  KEYS.map((key, index) => (
    <Button
      key={index}
      button={key} />
  ))
}

Button コンポーネントを props を通して受け取った内容を表示するように書き換えます。

Button.js
const Button = ({button}) => (
  <button>
    {button.toUpperCase()}
  </button>
);

配列の各オブジェクトのプロパティ名になっている「id」「title」「category」「year」の名前のボタンが表示されました。

how to sort items with react 03

ソート機能の追加

ボタンをクリックする度にソートされるようにしたいので、App.js にボタンをクリックした際に実行される関数を作成します。ソートに使用するプロパティ名を引数に指定します。関数は props として Button コンポーネントに渡します。

App.js
const handleSort = (key) => {
  console.log('click : ' + key);
};
App.js
<Button
  key={index}
  button={key}
  handleSort={handleSort} />

Button コンポーネントでは、 props として渡された関数を onclick イベントに指定します。画面上のボタンをクリックすると console に「click : プロパティ名」と表示されるのが確認できます。

Button.js
const Button = ({button, handleSort}) => (
  <button onClick={() => handleSort(button)}>
    {button.toUpperCase()}
  </button>
);

handleSort の中身を実際の処理に書き換えます。ボタンをクリックした際に「どのプロパティ名」を基準に「昇順 or 降順」に並び替えるか、ソートの条件を保有するための state を設定します。 state の設定・更新には hookuseState を使用します。 state の初期値は空にします。ソート用の state の更新は setSort で行います。

App.js
import React, { useState } from 'react';

const App = () => {
  const [sort, setSort] = useState({});
  
  return(
    ...
  );
};

同じボタンを続けてクリックしたか、直前とは異なるボタンをクリックしたかで処理を分けるため if/else で条件分岐します。同じボタンを続けてクリックした場合は、ソートの並びを反転させたいので stateorder: 1 の数値にマイナスを付与します。直前とは異なるボタンをクリックした場合は、ソートの基準になるプロパティ名( key )の値を更新して、昇順になるよう order: 1 を設定します。

App.js
const handleSort = (key) => {
  if (sort.key === key) {
    setSort({ ...sort, order: -sort.order });
  } else {
    setSort({
      key: key,
      order: 1
    })
  }
};

並び替えには sort() メソッドを使用します。昇順・降順に並べ替えるには、戻り値の数値の大小によって順番を決める比較関数を指定します。ソート後のデータを格納する変数 sortedMovies を宣言して、 sort() メソッドの返り値が格納されるようにします。このとき配列に変更があった場合にのみ、 sortedMovies の値を更新したいので、hookuseMemo を使用します。useMemo はメモ化された値を返す機能で、指定した配列の要素に変化があった場合にのみ値を更新します。

App.js
import React, { useState, useMemo } from 'react';

const App = () => {
  const [sort, setSort] = useState({});

  let sortedMovies = useMemo(() => {
    let _sortedMovies = DATA.movies;
    if (sort.key) {
      _sortedMovies = _sortedMovies.sort((a, b) => {
        a = a[sort.key];
        b = b[sort.key];

        if(a === b) {
          return 0;
        }
        if(a > b) {
          return 1 * sort.order;
        }
        if(a < b) {
          return -1 * sort.order;
        }
      });
    }
    return _sortedMovies;
  }, [sort, movies]);

  ...

  return (
    ...
  );
}

デモ

デモページではボタンに昇順・降順かわかる矢印を付け、アクティブ/非アクティブかで色が変わるようにしています。

Reactで配列の要素をソートする機能
Source

参考サイト

k.ishiwata「React Hooks でリストの絞り込み検索と並び替え機能のサンプル」(参照2019-09-15)

< Prev PostNext Post >