Реакция: Как заменить .querySelectorAll на отдельные ссылки для нескольких элементов - PullRequest
0 голосов
/ 04 апреля 2020

Я хотел бы отсортировать строки таблицы при нажатии на заголовки таблицы. У меня есть код, работающий с обычным html / javascript сниппетом здесь . Однако это не работает как метод React. Я думаю, что проблема заключается в использовании метода .querySelectorAll() и .parentNode. Я уже заменил метод .getElementById() на this.refs.rows, добавив ссылку к <tbody>, но я не думаю, что одна ссылка может указывать на несколько элементов (чтобы получить все элементы <td>). Я ищу аналогичный способ заменить оба метода, которые, кажется, не работают. Или это совсем другая проблема?


Редактировать: Добавлен весь компонент React, как это было указано в комментариях

import React from "react";

import { Row, Col, Table } from "reactstrap";

export class ComparePlayers extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            players: [],
        };
    }

    componentDidMount() {
        fetch("/players")
            .then((response) => response.json())
            .then((state) => {
                this.setState({ players: state });
            });
    }

    handleSort(n) {
        let rows, switching, i, x, y, shouldSwitch;
        switching = true;
        while (switching) {
            switching = false;
            rows = this.refs.rows; /* replaced document.getElementById("myTable").rows; */
            for (i = 0; i < rows.length; i++) {
                shouldSwitch = false;
                x = rows[i].querySelectorAll("td")[n]; // how to replace?
                y = rows[i + 1].querySelectorAll("td")[n]; // how to replace?
                if (!isNaN(Number(x.innerHTML))) {
                    if (Number(x.innerHTML) > Number(y.innerHTML)) {
                        shouldSwitch = true;
                        break;
                    }
                } else {
                    if (x.innerHTML.toLowerCase() > y.innerHTML.toLowerCase()) {
                        shouldSwitch = true;
                        break;
                    }
                }
            }
            if (shouldSwitch) {
                rows[i].parentNode.insertBefore(rows[i + 1], rows[i]); // how to replace?
                switching = true;
            }
        }
    }

    render() {
        return (
            <Row>
                <Col>
                    <Table bordered>
                        <thead>
                            <tr>
                                {this.state.players.length > 0 &&
                                    Object.keys(this.state.players[0]).map((key, id) => (
                                        <th
                                            key={"header_" + key}
                                            onClick={() => this.handleSort(id)}
                                        >
                                            {key.toUpperCase()}
                                        </th>
                                    ))}
                            </tr>
                        </thead>
                        <tbody ref="rows">
                            {this.state.players.length > 0 &&
                                this.state.players.map((player, id) => {
                                    return (
                                        <tr key={"row" + id}>
                                            {Object.values(player).map((value) => (
                                                <td key={"table_value_" + value}>{value}</td>
                                            ))}
                                        </tr>
                                    );
                                })}
                        </tbody>
                    </Table>
                </Col>
            </Row>
        );
    }
}

ОБНОВЛЕНИЕ И РЕШЕНИЕ:

Я использовал ответ @MahdyAslamy и адаптировался к своему состоянию, которое представляет собой массив объектов. Я использовал этот урок для сортировки массива объектов по значениям свойств. Вот окончательный код:

handleSort(el) {
  const compareValues = (key) => {
    return function innerSort(a, b) {
      if (!a.hasOwnProperty(key) || !b.hasOwnProperty(key)) {
        // property doesn't exist on either object
        return 0;
      }

      const varA = typeof a[key] === "string" ? a[key].toUpperCase() : a[key];
      const varB = typeof b[key] === "string" ? b[key].toUpperCase() : b[key];

      let comparison = 0;
      if (varA > varB) {
        comparison = 1;
      } else if (varA < varB) {
        comparison = -1;
      }
      return comparison;
    };
  };
  const sorted = this.state.players.sort(compareValues(el));
  this.setState({
    players: sorted
  });
}

1 Ответ

1 голос
/ 04 апреля 2020

Это не очень хороший способ сортировки таблицы путем изменения позиции тегов на DOM. Реакция предлагает использовать состояния и обычный жизненный цикл компонента для изменения внешнего вида.

например:

class Game extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      list: [5,6,8,9,6,5,4,22,4]
    }
  }

  render() {
    return (
      <div className="game">
        <button onClick={() => this.setState({ list: this.state.list.sort() })}>sort</button>
        <ul>
          {this.state.list.map(el => <li>{el}</li>)}
        </ul>
      </div>
    );
  }
}

// ========================================

ReactDOM.render(
  <Game />,
  document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

<div id="root"></div>

Сортируйте только свой список, а затем отобразите отсортированный список при рендеринге.

...