Почему массив состояний не заполняется при визуализации компонента? - PullRequest
0 голосов
/ 23 апреля 2019

Я создал компонент, который сортирует и фильтрует таблицу HTML. Функциональность верна, но у меня проблема в том, что моя таблица отображает «Записи активов не найдены». , но когда я нажимаю на один из заголовков, он отображает содержимое массива данных в состоянии. Я действительно застрял и запутался в этом странном поведении. Я думаю, что проблема может быть с функцией filterAssets, потому что, если я изменю это:

let filterAssets = this.state.data.filter(a => {
  return a.name.toLowerCase().indexOf(this.state.search) !== -1
})

к этому:

let filterAssets = this.props.assetManagement.filter(a => {
  return a.name.toLowerCase().indexOf(this.state.search) !== -1
})

Вот код ниже, если это поможет

import React, { Component, Fragment } from 'react'
import { connect } from 'react-redux'
import PropTypes from 'prop-types'
import { getAssetManagement } from '../../actions/asset-management'

class AssetManagement extends Component {
  static propTypes = {
    assetManagement: PropTypes.array.isRequired,
    getAssetManagement: PropTypes.func.isRequired
  }

  componentDidMount() {
    this.props.getAssetManagement()
  }

  state = {
    name: '',
    search: '',
    data: []
  }

  sortBy = this.sortBy.bind(this)
  compareBy = this.compareBy.bind(this)

  onSubmit = e => {
    e.preventDefault()
  }

  onChange = e =>
    this.setState({
      [e.target.name]: e.target.value
    })

  updateSearch = e =>
    this.setState({
      search: e.target.value.substr(0, 20)
    })

  compareBy(key) {
    return (a, b) => {
      if (a[key] < b[key]) return -1
      if (a[key] > b[key]) return 1
      return 0
    }
  }

  sortBy(key) {
    let arrayCopy = [...this.props.assetManagement]
    this.state.data.sort(this.compareBy(key))
    this.setState({ data: arrayCopy })
  }

  render() {
    let filterAssets = this.state.data.filter(a => {
      return a.name.toLowerCase().indexOf(this.state.search) !== -1
    })

    return (
      <Fragment>
        {/* Search input */}
        <div class="input-group mb-1">
          <div class="input-group-prepend">
            <span class="input-group-text btn-secondary">
              <i class="fas fa-search" />
            </span>
          </div>
          <input
            className="form-control"
            type="text"
            placeholder="Search Asset"
            onChange={this.updateSearch.bind(this)}
            value={this.state.search}
          />
        </div>

        {/* Asset management table */}
        <div className="table-responsive">
          <table className="table table-bordered text-center">
            <thead>
              <tr>
                <th onClick={() => this.sortBy('id')}>ID</th>
                <th onClick={() => this.sortBy('name')}>Name</th>
              </tr>
            </thead>
            <tbody>
              {filterAssets != 0 ? (
                filterAssets.map(a => (
                  <tr key={a.id}>
                    <td>{a.id}</td>
                    <td>{a.name}</td>
                  </tr>
                ))
              ) : (
                <tr>
                  <td colSpan={6}>No asset records found.</td>
                </tr>
              )}
            </tbody>
          </table>
        </div>
      </Fragment>
    )
  }
}

const mapStateToProps = state => ({
  assetManagement: state.assetManagement.assetManagement
})

export default connect(
  mapStateToProps,
  { getAssetManagement }
)(AssetManagement)

Ответы [ 3 ]

1 голос
/ 23 апреля 2019

Настоящая проблема, с которой вы столкнулись, состоит в том, что у вас есть два источника данных: state.data и props.assetManagement - вы извлекаете данные из избыточного числа и получаете новейшие данные из props.assetManagement, но когда вам нужно запустить сортировку, вы делаете скопировать в state.data. Тогда возникает проблема, поскольку вы не копируете из props.assetManagement в state.data, пока не запустите функцию sortBy.

Решением для этого является избавление от state.data и сохранение ключа сортировки в состоянии. Вы можете обновить, сбросить это значение ключа, и логика сортировки должна применяться только к props.assetManagement:

class AssetManagement extends Component {
  static propTypes = {
    assetManagement: PropTypes.array.isRequired,
    getAssetManagement: PropTypes.func.isRequired
  }

  componentDidMount() {
    this.props.getAssetManagement()
  }

  state = {
    name: '',
    search: '',
    sortingKey: ''
  }

  sortBy = this.sortBy.bind(this)
  compareBy = this.compareBy.bind(this)

  onSubmit = e => {
    e.preventDefault()
  }

  onChange = e =>
    this.setState({
      [e.target.name]: e.target.value
    })

  updateSearch = e =>
    this.setState({
      search: e.target.value.substr(0, 20)
    })

  compareBy(key) {
    return (a, b) => {
      if (a[key] < b[key]) return -1
      if (a[key] > b[key]) return 1
      return 0
    }
  }

  sortBy(key) {
    if (key !== this.state.sortingKey) {
      this.setState({ sortingKey: key });
    }
  }

  render() {
    let sortAssets = !!this.state.sortingKey ?
      this.props.assetManagement.sort(this.compareBy(this.state.sortingKey)) :
      this.props.assetManagement;
    let filterAssets = sortAssets.filter(a => {
      return a.name.toLowerCase().indexOf(this.state.search) !== -1
    });
    return (
      <Fragment>
        {/* Search input */}
        <div class="input-group mb-1">
          <div class="input-group-prepend">
            <span class="input-group-text btn-secondary">
              <i class="fas fa-search" />
            </span>
          </div>
          <input
            className="form-control"
            type="text"
            placeholder="Search Asset"
            onChange={this.updateSearch.bind(this)}
            value={this.state.search}
          />
        </div>

        {/* Asset management table */}
        <div className="table-responsive">
          <table className="table table-bordered text-center">
            <thead>
              <tr>
                <th onClick={() => this.sortBy('id')}>ID</th>
                <th onClick={() => this.sortBy('name')}>Name</th>
              </tr>
            </thead>
            <tbody>
              {filterAssets != 0 ? (
                filterAssets.map(a => (
                  <tr key={a.id}>
                    <td>{a.id}</td>
                    <td>{a.name}</td>
                  </tr>
                ))
              ) : (
                <tr>
                  <td colSpan={6}>No asset records found.</td>
                </tr>
              )}
            </tbody>
          </table>
        </div>
      </Fragment>
    )
  }
}

Пример кода: https://codesandbox.io/s/n91pq7073l

0 голосов
/ 23 апреля 2019

Когда вы используете альтернативный синтаксис для React Component без использования конструктора, у вас больше нет доступа к реквизиту.Поэтому, если вы вернетесь к использованию стандартного конструктора, проблема исчезнет, ​​например:

constructor(props) {
    super(props);
    this.state = {
      name: "",
      search: "",
      data: this.props.assetManagement
    };

    this.sortBy = this.sortBy.bind(this);
    this.compareBy = this.compareBy.bind(this);
  }
0 голосов
/ 23 апреля 2019

Изменить filterAssets != 0 на filterAssets.length > 0

Один первый рендер:

let filterAssets = this.state.data.filter(a => {
  return a.name.toLowerCase().indexOf(this.state.search) !== -1
})

Ваш this.state.data пуст, только this.props.assetManagement доступен, если вы правильно обрабатываете избыточность, поэтому неудивительноесли вы не можете получить ничего от фильтрации.

Кстати: filterAssets != 0 абсолютно неверно, поэтому сначала измените эту строку.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...