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

时间:2016-10-12 06:38:17

标签: javascript reactjs redux state 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>
    )
  }
})

更新包含过滤的当前代码

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 个答案:

答案 0 :(得分:8)

您使用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>
    )
  }
}

答案 1 :(得分:3)

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

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

React docs中,他们建议你将道具命名为initialContacts,只是为了让道具的唯一目的是在内部初始化内容。

现在,如果您希望在this.props.contacts更改时更新,则可以像使用componentWillReceiveProps()一样使用<!doctype html> <html> <head> <meta charset="utf-8"> <title>:jQuery Attribute:</title> <link href="css/main.css" rel="stylesheet" type="text/css" /> <style> .one {font-size:20px;} .second {color:red;} </style> <script src="js/jquery-1.11.3.min.js"></script> </head> <body> <h2>All jQuery Attribute</h2> <p class="one">First Para </p> <p class="one">Second Para </p> <p class="one">Third Para </p> <p class="one">Fourth Para </p> <p class="one">Fifth Para </p> <script> $('p:nth-child(1)').addClass('second'); </script> </body> </html> 。但我不确定这是最好的主意。来自文档:

  

使用props在getInitialState中生成状态通常会导致   重复“真相来源”,即真实数据所在的地方。这是   因为只有在第一个组件时才会调用getInitialState   创建

     

尽可能即时计算值以确保它们不会   稍后会失去同步并导致维护问题。

答案 2 :(得分:2)

React 16.3包含一个静态函数ano2015.groupby("UO_Ajustada").Empenhado.agg(['sum','count']) ,它将在初始挂载后以及收到新道具时调用。见https://reactjs.org/docs/react-component.html#static-getderivedstatefromprops