如何在同一个 React 组件中使用本地状态和 redux 存储状态?

IT技术 javascript reactjs redux state react-redux
2021-05-08 06:00:08

我有一个显示联系人的表格,我想按名字对联系人进行排序。联系人数组来自 redux 商店,然后通过props来,但我希望本地状态保存这些联系人的排序方式,因为它是本地 UI 状态。我如何实现这一目标?到目前为止,我已经放置了联系人,componentWillReceiveProps但由于某种原因,它在更改时不会收到props。每次 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>
    )
  }
})

更新当前代码,包括过滤

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

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

3个回答

您同时使用 redux store 和 local store 的方法是正确的。

只是不要尝试从组件中的 redux 存储中复制状态。继续通过 props 引用它。

而是创建一个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>
    )
  }
}

componentWillReceiveProps()不会为初始渲染调用方法。如果您只想使用 props 中的数据作为初始数据,可以做什么,例如:

getInitialState () {
  return {
    contacts: this.props.data.contacts
  }
}

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

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

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

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

React 16.3 包含一个静态函数getDerivedStateFromProps(nextProps, prevState),它将在初始挂载后以及接收新props时调用。请参阅https://reactjs.org/docs/react-component.html#static-getderivedstatefromprops