如何在同一反应组件中使用本地状态以及redux存储状态?

sta*_*lei 14 javascript state reactjs redux react-redux

我有一个显示联系人的表,我想按名字对联系人排序.contacts数组来自redux商店,然后来到道具,但我希望本地状态能够保存这些联系人的排序方式,因为它是本地UI状态.我该如何实现这一目标?到目前为止,我已将联系人放入,componentWillReceiveProps但由于某种原因,它在更改时不会收到道具.每次redux存储状态更改时,如何更新本地状态?

const Table = React.createClass({
  getInitialState () {
    return {contacts: []}
  },
  componentWillReceiveProps () {
    this.setState({ contacts: this.props.data.contacts})
  },
  sortContacts (parameter, e){
    ...
  },
  render () {
    return (
      <table>
        <thead>
          <tr>
            <th onClick={this.sortContacts.bind(this, "firstName")}>First Name</th>
          </tr>
        </thead>
        <tbody>
          {contactRows}
        </tbody>
      </table>
    )
  }
})
Run Code Online (Sandbox Code Playgroud)

更新包含过滤的当前代码

import React, {Component} from 'react'
import TableRow from './TableRow'

class Table extends Component {
  constructor (props) {
    super(props)
    this.state = { sortBy: "fistName" }
  }
  sortContacts (parameter) {
    console.log('in sortContacts')

    this.setState({ sortBy: parameter })
  }
  sortedContacts () {
    console.log('in sortedContacts')

    const param = this.state.sortBy
    return (
      this.props.data.contacts.sort(function (a, b){
        if (!a.hasOwnProperty(param)){
          a[param] = " ";
        }
        if (!b.hasOwnProperty(param)){
          b[param] = " ";
        }
        const nameA = a[param].toLowerCase(), nameB = b[param].toLowerCase();
        if (nameA > nameB) {
          return 1;
        } else {
          return -1;
        }
      })
    )
  }
  filteredSortedContacts () {
    console.log('in filteredSortedContacts')

    const filterText = this.props.data.filterText.toLowerCase()
    let filteredContacts = this.sortedContacts()
    if (filterText.length > 0) {
      filteredContacts = filteredContacts.filter(function (contact){
        return (
          contact.hasOwnProperty('lastName') &&
          contact.lastName.toLowerCase().includes(filterText)
        )
      })
    }
    return filteredContacts
  }
  contactRows () {
    console.log('in contactRows')
    return this.filteredSortedContacts().map((contact, idx) =>
      <TableRow contact={contact} key={idx}/>
    )
  }
  render () {
    return (
      <div className="table-container">
        <table className="table table-bordered">
          <thead>
            <tr>
              <th className="th-cell" onClick={this.sortContacts.bind(this, "firstName")}>First Name</th>
              <th onClick={this.sortContacts.bind(this, "lastName")}>Last Name</th>
              <th>Date of Birth</th>
              <th>Phone</th>
              <th>Email</th>
              <th>Notes</th>
            </tr>
          </thead>
          <tbody>
            {this.contactRows()}
          </tbody>
        </table>
      </div>
    )
  }
}

export default Table
Run Code Online (Sandbox Code Playgroud)

我现在看到的问题contactRows, filteredSortedContacts, sortedContacts是被多次调用,每个TableRow调用一次.如果我只是contactRows在体内打一次,我不明白这是怎么回事.

Mic*_*jbe 10

您使用redux存储和本地存储的方法是正确的.

只是不要尝试从组件中的redux store复制状态.通过道具继续引用它.

而是创建一个sortedContacts函数,通过将本地存储的sortBy参数应用于redux存储的联系人来动态计算值.

const Table extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      sortBy: 'id' // default sort param
    }
  }

  sortContacts(param) {
    this.setState({ sortBy: param})
  }

  sortedContacts() {
    return this.props.contacts.sort(...); // return sorted collection
  }

  render() {
    return (
      <table>
        <thead>
          <tr>
            <th onClick={() => this.sortContacts("firstName")}>First Name</th>
          </tr>
        </thead>
        <tbody>
          {this.sortedContacts()}
        </tbody>
      </table>
    )
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 因为如果您只有一个事实来源,则不需要任何同步代码.在您的情况下,您不仅可以轻松地应用排序,还可以以相同的方式应用过滤,转换等. (4认同)
  • @MichałSzajbe关于真理的一个好观点。我唯一关心的是如果我有1000行-每次组件渲染时这种方法都不会排序吗?说我有分页,每当我单击“下一步”时,它将使用1000个数据CMIIW。有更好的方法吗? (2认同)

tob*_*sen 3

componentWillReceiveProps()初始渲染不会调用该方法。如果您只想使用 props 中的数据作为初始数据,可以执行以下操作:

getInitialState () {
  return {
    contacts: this.props.data.contacts
  }
}
Run Code Online (Sandbox Code Playgroud)

在React 文档中,他们建议您将 props 命名为initialContacts,只是为了清楚地表明 props 的唯一目的是在内部初始化某些内容。

现在,如果您希望它在this.props.contacts更改时更新,您可以componentWillReceiveProps()像以前一样使用。但我不确定这是最好的主意。来自文档:

使用 props 在 getInitialState 中生成状态通常会导致“事实来源”的重复,即真实数据的位置。这是因为 getInitialState 仅在首次创建组件时调用。

只要有可能,即时计算值,以确保它们以后不会不同步并导致维护麻烦。