【React】map関数で作ったリストを並び替え・ソートする方法

React

map関数で作ったリストの並び替えに苦戦したので、解決方法を記載します。

やりたかったこと

親コンポーネントでstateに格納した配列を、子コンポーネントにPropsとして渡し、それを子コンポーネントで一覧表示にしていました。そして、それを配列内の各オブジェクトのキーを基準に並び替えたかったです。

起こっていた問題

親コンポーネントのstateの配列順を変えることができ、それが子コンポーネントにも伝わっていたが、mapのリスト順は全く変わらない。という謎現象でした。

解決策

公式ドキュメントを見ていた際にこんな文章がありました。

必要に応じてキーを変更することで、コンポーネントにその内部の state を「リセット」させることができます。

In order to reset the value when moving to a different item (as in our password manager scenario), we can use the special React attribute called key. When a key changes, React will create a new component instance rather than update the current one. Keys are usually used for dynamic lists but are also useful here. In our case, we could use the user ID to recreate the email input any time a new user is selected:

実際のページ:React公式ブログ

そうです!キーが変わるように設定すればいいのです!!

私の場合はこのような形になりました

ひとことで言うと、mapのkeyの一部分になるstringをPropsで渡すという形です!

※propsでなくても、map関数によって生成される子要素にkeyを設定できればOKです。

親コンポーネント

const App: React.FC = () => {
  const [ list, setList ] = useState([]);
  const [ sort, setSort ] = useState('default')

  // 配列の並び替え(配列内のオブジェクトのnameキーが基準)
  const sortName = () => {
    let newList: any;
    newList = list.sort((el1, el2) => {
      if (el1['name'] < el2['name']) {
        return 1;
      }
      if (el1['name'] > el2['name']) {
        return -1;
      }
        return 0;
    });
    setSort('name');
    setList(newList);
  }

  return (
    <div>
      <Child
        info = {list}
        sortType = {sort} {/* ソート名をPropsで渡す(keyの名前に使用する) */}
      />
    </div>
  )
}

子コンポーネント

const Child: React.FC<Props> = ({info, sortType}) => {
  return (
    <div>
      {info.map((el) => (
        <div key={`${sortType}-${el.id}`}>
          {/* ... */}
        </div>
      ))}
    </div>
  )
}

これで上手く動きました。一安心です。

keyに良さそうなプロパティがない場合は、indexを使うという手もあります。

const Child: React.FC<Props> = ({info, sortType}) => {
  return (
    <div>
      {info.map((el, index) => (
      <div key={`info-${index}`}>
        <p>{el.title}</p>
      </div>
    ))}
    </div>
  )
}
タイトルとURLをコピーしました