Таблица может быть отсортирована по алфавиту, но не в обратном алфавитном порядке - PullRequest
0 голосов
/ 06 августа 2020

Мне удалось сделать так, чтобы таблица была отсортирована по каждому из ее столбцов, нажав кнопку рядом с заголовком столбца.

Однако я ожидал, что он будет отсортировать ее в обратном алфавитном порядке при нажатии во второй раз и до go возврата в исходное состояние при третьем щелчке.

Сейчас он работает только для первого щелчка - сортирует его по алфавиту - но после этого не работает » Я ничего не делаю независимо от того, сколько раз на него нажимали.

import { Table } from 'semantic-ui-react';

export default class GenericTable extends React.PureComponent {
  constructor(props) {
    super(props);

    this.state = { 
      currentSort: 'default',
      rows: this.props.rows, // the original rows are saved in state
    };
  }

  onSortChange = index => {
    let nextSort;

    const newRows = this.props.rows.sort(function(a, b) {
      if (a.cells[index] < b.cells[index]) {
        nextSort = 'up';
        return -1;
      }
      if (a.cells[index] > b.cells[index]) {
        nextSort = 'default';
        return 1;
      }
      nextSort = 'down';
      return 0;
    });
    this.setState({ rows: newRows, currentSort: nextSort });
  };

  render() {

    const { currentSort } = this.state; // added state
    const sortTypes = { // added constant
      up: {
       class: 'sort-up',
       fn: (a, b) => a.name - b.name,
      },
      down: {
        class: 'sort-down',
        fn: (a, b) => b.name - a.name,
      },
     default: {
       class: 'sort',
       fn: (a, b) => a,
     },
   };
    const { headers, rows, idList } = this.props;
    
    return (
      <Table>
        <Table.Header>
          <Table.Row>
             {headers.map(header => (
                <Table.HeaderCell key={headers.indexOf(header)}>
                 {header}
                 // added button
                 <button onClick={() => this.onSortChange(index)} type="button">
                   <i className={`fas fa-${sortTypes[currentSort].class}`} />
                 </button>
                </Table.HeaderCell>
             )}
          </Table.Row>
        </Table.Header>

        <Table.Body>
         // added below
         {rows.map((row, rowIndex) => (
            <Table.Row key={idList && idList[rowIndex]}>
                <Table.Cell>
                  ...
                </Table.Cell>
         
            </Table.Row>
          )}
        </Table.Body>
      </Table>
    );
  }
}

Думаю, что-то не так в onSortChange, но не знаю что.

Ответы [ 2 ]

0 голосов
/ 07 августа 2020
onSortChange = index => {
  const sortMap = {
    default: 'up',
    up: 'down',
    down: 'default',
  };

  let { currentSort, currentIndex } = this.state;

  let nextSort = currentIndex === index ? sortMap[currentSort] : 'default';

  let newRows = [...this.props.rows];

  switch (nextSort) {
    case 'up':
      newRows.sort((a, b) => (a.cells[index] <= b.cells[index] ? -1 : 1));
      break;
    case 'down':
      newRows.sort((a, b) => (b.cells[index] <= a.cells[index] ? -1 : 1));
      break;
  }

  this.setState({ rows: newRows, currentSort: nextSort, currentIndex: index });
};

Во-первых, вы не должны вызывать метод sort непосредственно на props.rows. Потому что он напрямую изменит props.rows вместо того, чтобы возвращать отсортированный новый массив. Итак, мы сначала получаем копию исходных данных через [...this.props.rows], а затем сортируем ее.

Во-вторых, использование sort в вашем коде неверно. Первый параметр compareFn из sort сравнивает только соотношение размеров между двумя элементами, не беспокоясь ни о чем другом. И порядок должен определяться последним порядком сортировки, записанным в состоянии. В любом случае два элемента, переданные в compareFn по sort, не указаны по порядку. Он будет отличаться в зависимости от алгоритма, но, говоря простым языком, вы можете подумать, что задача compareFn состоит только в том, чтобы сравнить размер двух случайных элементов в массиве.

Окончательно, чтобы не быть зависит от последнего результата сортировки при нажатии на другой столбец. Мы добавили индекс последнего отсортированного столбца к state. Если индексы двух последних отсортированных столбцов не совпадают, используйте порядок up для прямой сортировки.

0 голосов
/ 06 августа 2020

Javascript сортировка, возможно, не так проста, как кажется. Я пытаюсь объяснить это вам, чтобы вы могли исправить свою функцию.

Предположим, у нас есть следующие значения:

var items = [
  { name: 'Edward', value: 21 },
  { name: 'Sharpe', value: 37 },
  { name: 'And', value: 45 },
  { name: 'The', value: -12 },
  { name: 'Magnetic', value: 13 },
  { name: 'Zeros', value: 37 }
];

И мы напишем эту функцию:

items.sort()

мало что происходит. Это потому, что мы имеем дело со списком объектов и поэтому хотим добавить compareFunction. Вы сделали это довольно хорошо, но я полагаю, вы не совсем понимаете, что он делает. Если мы используем, например, compareFunction:

items.sort(function (a, b) {
  var nameA = a.name.toUpperCase(); // ignore upper/lower case!
  var nameB = b.name.toUpperCase(); // ignore upper/lower case!
  if (nameA < nameB) {
    return -1;
  }
  if (nameA > nameB) {
    return 1;
  }

  // Namen müssen gleich sein
  return 0;
});

Наш список будет отсортирован по алфавиту. Зачем? Потому что мы говорим функции прямо здесь:

var nameA = a.name.toUpperCase(); // ignore upper/lower case!
var nameB = b.name.toUpperCase(); // ignore upper/lower case!

, что мы ищем свойства «name» нашего объекта. Мы могли бы легко заменить a.name.toUpperCase() на a.value, и теперь мы будем сортировать наш массив по значению внутри свойства value нашего объекта.

При этом ваша функция сортировки в настоящее время запрограммирована на всегда сортировать по алфавиту (от a до z). Вы никогда не реализовывали logi c, чтобы сделать обратное или остановить сортировку. Я думаю, вы, вероятно, предположили, что compareFunction уже выполняет функцию переключения сортировки, но это не так.

Чтобы выполнить сортировку по убыванию (z - a), вы можете использовать функцию .reverse (). Это будет выглядеть примерно так:

items.sort(function (a, b) {
  var nameA = a.name.toUpperCase(); // ignore upper/lower case!
  var nameB = b.name.toUpperCase(); // ignore upper/lower case!
  if (nameA < nameB) {
    return -1;
  }
  if (nameA > nameB) {
    return 1;
  }

  // Namen müssen gleich sein
  return 0;
}).reverse();

et voilà - теперь ваш список отсортирован в порядке убывания (z - a). (подробнее читайте здесь: Сортировка строк в порядке убывания в Javascript (наиболее эффективно)? ).

Все, что вам нужно сейчас сделать, это реализовать правильную функцию сортировки в правильное время - я думаю, это должно быть то, чем вы можете управлять сами. В остальном я рад помочь :)

подробнее о сортировке массивов (javascript документы: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/sort)

...