为什么在渲染组件时不填充状态数组?

时间:2019-04-23 09:57:26

标签: javascript reactjs redux

我创建了一个对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 个答案:

答案 0 :(得分:1)

这里真正的问题是,您有两个数据源:state.dataprops.assetManagement-从redux检索并从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

答案 1 :(得分:0)

filterAssets != 0更改为filterAssets.length > 0

第一个渲染器:

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

您的this.state.data为空,如果正确处理redux,只有this.props.assetManagement可用,所以也就怪不得从过滤中得到任何东西。

顺便说一句:filterAssets != 0绝对是错误的,所以请先更改此行。

答案 2 :(得分:0)

在不使用构造函数的情况下对React Component使用替代语法的情况下,您将不再有权使用prop。因此,如果您返回使用标准构造函数,问题就会消失,例如:

21 = 14
22 = 9
11 = 22
12 = 4