React отображает элементы массива в неправильном порядке, хотя ключи уникальны

#arrays #reactjs #typescript #rendering

Вопрос:

У меня есть таблица показателей компонентов, которая отображает данные реквизитов в виде таблицы html. Проблема в том, что react отображает некоторые строки в неправильном порядке. Ключи уникальны и статичны. Я использую useEffect для печати данных всякий раз, когда они меняются. Код, вывод консоли и таблица визуализации приведены ниже.

Код:

 interface Props {
  title: string;
  data?: ScoreboardT | null;
  keys?: string[];
  variant?: string;
}

export const ScoreTable: React.FC<Props> = ({
  data,
  title,
  keys = [
    'No.',
    'Name',
    'Played',
    'Won',
    'Tied',
    'Lost',
    'GF',
    'GA',
    'GD',
    'Points'
  ],
  variant = 'normal'
}) => {
  useEffect(() => {
    console.log('new data', data);
  }, [data]);
  return (
    <Table striped bordered variant={variant}>
      <thead>
        <tr>
          <th colSpan={12} className='text-center'>
            {title}
          </th>
        </tr>
        <tr>
          {keys.map((key, index) => (
            <th key={index}>{key}</th>
          ))}
        </tr>
      </thead>
      <tbody>
        {data amp;amp;
          data.map((row, index) => (
            <tr key={row.id}>
              <td>{index   1}</td>
              <th>
                <Badge>{row.in_group_id}</Badge>
                {row.name}
              </th>
              <td>{row.played_matches}</td>
              <td>{row.won_matches}</td>
              <td>{row.tied_matches}</td>
              <td>{row.lost_matches}</td>
              <td>{row.scored_goals}</td>
              <td>{row.lost_goals}</td>
              <td>{row.goals_difference}</td>
              <th>{row.points}</th>
            </tr>
          ))}
      </tbody>
    </Table>
  );
};
 

Вывод на консоль

 new data: null
new data: [
  {
    "id": "5",
    "in_group_id": "A5",
    "group_name": "A",
    "name": "Polonia Kraków 2",
    "tourney_id": 1,
    "scored_goals": "23",
    "lost_goals": "7",
    "points": "17",
    "won_matches": "5",
    "tied_matches": "2",
    "lost_matches": "0",
    "played_matches": "7",
    "goals_difference": "16"
  },
  {
    "id": "2",
    "in_group_id": "A2",
    "group_name": "A",
    "name": "Progress Angdrychów",
    "tourney_id": 1,
    "scored_goals": "21",
    "lost_goals": "5",
    "points": "17",
    "won_matches": "5",
    "tied_matches": "2",
    "lost_matches": "0",
    "played_matches": "7",
    "goals_difference": "16"
  },
  {
    "id": "8",
    "in_group_id": "A8",
    "group_name": "A",
    "name": "AP Wieliczka",
    "tourney_id": 1,
    "scored_goals": "9",
    "lost_goals": "9",
    "points": "10",
    "won_matches": "3",
    "tied_matches": "1",
    "lost_matches": "3",
    "played_matches": "7",
    "goals_difference": "0"
  },
  {
    "id": "1",
    "in_group_id": "A1",
    "group_name": "A",
    "name": "Sandecja Nowy Sącz",
    "tourney_id": 1,
    "scored_goals": "12",
    "lost_goals": "14",
    "points": "9",
    "won_matches": "2",
    "tied_matches": "3",
    "lost_matches": "2",
    "played_matches": "7",
    "goals_difference": "-2"
  },
  {
    "id": "7",
    "in_group_id": "A7",
    "group_name": "A",
    "name": "Futbol Brzączowice",
    "tourney_id": 1,
    "scored_goals": "12",
    "lost_goals": "13",
    "points": "9",
    "won_matches": "3",
    "tied_matches": "0",
    "lost_matches": "4",
    "played_matches": "7",
    "goals_difference": "-1"
  },
  {
    "id": "4",
    "in_group_id": "A4",
    "group_name": "A",
    "name": "Clepardia Kraków",
    "tourney_id": 1,
    "scored_goals": "16",
    "lost_goals": "12",
    "points": "9",
    "won_matches": "2",
    "tied_matches": "3",
    "lost_matches": "2",
    "played_matches": "7",
    "goals_difference": "4"
  },
  {
    "id": "6",
    "in_group_id": "A6",
    "group_name": "A",
    "name": "Orliki Myślenice",
    "tourney_id": 1,
    "scored_goals": "3",
    "lost_goals": "23",
    "points": "4",
    "won_matches": "1",
    "tied_matches": "1",
    "lost_matches": "5",
    "played_matches": "7",
    "goals_difference": "-20"
  },
  {
    "id": "3",
    "in_group_id": "A3",
    "group_name": "A",
    "name": "AS Progres Kraków",
    "tourney_id": 1,
    "scored_goals": "5",
    "lost_goals": "18",
    "points": "2",
    "won_matches": "0",
    "tied_matches": "2",
    "lost_matches": "5",
    "played_matches": "7",
    "goals_difference": "-13"
  }
]
 

Таблица
визуализированная таблица

Мой вопрос: Как я могу заставить React отображать эти элементы в том же порядке, в каком массив регистрируется в консоли.

Ответ №1:

Вы должны отсортировать свой массив, прежде чем сопоставлять его:

JS Родной:

  <tbody>
    {data amp;amp;
      data
        .sort((a,b) => a.id - b.id) // <-- this is the line to be added
        .map((row, index) => (
        <tr key={row.id}>
          <td>{index   1}</td>
          <th>
            <Badge>{row.in_group_id}</Badge>
            {row.name}
          </th>
          <td>{row.played_matches}</td>
          <td>{row.won_matches}</td>
          <td>{row.tied_matches}</td>
          <td>{row.lost_matches}</td>
          <td>{row.scored_goals}</td>
          <td>{row.lost_goals}</td>
          <td>{row.goals_difference}</td>
          <th>{row.points}</th>
        </tr>
      ))}
  </tbody>
 

Lodash:

  <tbody>
    {data amp;amp;
      _.sortBy(data, 'id')
        .map((row, index) => (
 

Комментарии:

1. Я хочу отображать элементы в том же порядке, в каком они находятся в массиве прямо сейчас. Сортировка не является опцией. Если вы посмотрите на вывод консоли и таблицу визуализации, вы увидите разницу в том, как они упорядочены, и это моя проблема.