【问题标题】:Should a react component have the knowledge of the state of its parent component反应组件是否应该知道其父组件的状态
【发布时间】:2016-11-14 21:18:37
【问题描述】:

所以我写了这个带有复选框的表格行组件,作为其他表格组件使用的第一列。以下是组件的简化版本

表格行:

import React, { Component, PropTypes } from 'react'
import { Checkbox } from 'react-bootstrap'

export default class TableRow extends Component {
  constructor(props) {
    super(props)
    this.handleClickCheckbox = this.handleClickCheckbox.bind(this)
  }

  handleClickCheckbox() {
    this.props.onClickCheckbox(this.props.entity.id)
  }

  render() {
    const { checked, children } = this.props 

    return (
      <tr>
        <Checkbox
          checked={checked}
          onChange={this.handleClickCheckbox}
        >&nbsp;</Checkbox>
        {children}
      </tr>
    }

}
TableRow.propTypes = {
  entity: PropTypes.shape({
    id: PropTypes.number
  }),
  checked: PropTypes.bool,
  onClickCheckbox: PropTypes.func
}

表:

import React, { Component, PropTypes } from 'react'
import { Table } from 'react-bootstrap'
import TableRow from './TableRow'

class SampleTable extends Component {
  constructor(props) {
    super(props)
    this.state = {
      checkedEntitiesIds: []
    }
    this.handleChangeChecked = this.handleChangeChecked.bind(this)
  }

  handleChangeChecked(id) {
    const { checkedEntitiesIds } = this.state
    const indexOfEntity = checkedEntitiesIds.indexOf(id)
    // uncheck it if it's already checked, vice versa
    this.setState({
      checkedEntitiesIds : indexOfEntity > -1 ?
      checkedEntitiesIds.filter((id, index) => index != indexOfEntity) :
      [...checkedEntitiesIds, id]
    })
  }

  render() {
    const { entities } = this.props // can come from either parent component or subcribe to redux state
    return (
      <Table>
        <thead>
          <tr>
            <th>placeholder for checkbox column</th>
            <th>dummy header 1</th>
            <th>dummy header 2</th>
          </tr>
        </thead>
        <tbody>
        {entities.map(entity => 
          <TableRow
            key={entity.id}
            entity={entity}
            checked={this.state.checkedIds.indexOf(action.id) > -1}
            onClickCheckbox={this.handleChangeChecked}
          >
            <td>dummy table cell 1</td>
            <td>dummy table cell 2</td>
          </TableRow>
        )}
        </tbody>
      </Table>
    )
  }
}

我将复选框设置为受控输入,因为选中的道具的值可能来自数据库。每个表行都有一个实体道具,可以唯一标识该行。我在表格组件中维护checkedEntitiesIds 状态,而不是在TableRow 组件中维护checked 状态,因为我觉得它为我提供了最大的灵活性。

我的一位同事不喜欢他必须在每个表组件中维护checkedEntitiesIds 状态以及handleChangeChecked 函数这一事实。他提出将checkedEntitiesIds状态加入TableRow,将handleChangeChecked的函数体移到TableRow。它的工作方式是每次单击/更改复选框时,TableRow 中的checkedEntitiesIds 状态将首先更新,然后传递回父表,因此父组件的checkedEntitiesIds 状态也会更新。这样他就不需要一遍又一遍地编写检查/取消检查逻辑。

有几件事困扰着我做出这样的改变:

  1. 让 TableRow 知道 checkedEntitiesIds,这应该是 Table 的一个状态,太违反直觉了。
  2. 重复的事实来源。
  3. TableRow 将有一个状态。如果我在这里错了,请纠正我。我的理解是那些低阶的哑组件应该很少有自己的状态。
  4. 在某些扫描仪中,复选框单击事件可能不一定会立即导致状态更改。例如,单击复选框时首先提示确认模式,并且仅在选择“是”时才更新状态。在 TableRow 中使用状态并不能提供这种灵活性。

我几乎可以肯定他的提议有点反模式。我只是不确定我放置组件的方式是否有意义,以及我列出的这些点是否有效。我是否遗漏了任何重要的东西来说服他?有没有办法在可重用性方面改进我的代码。任何见解将不胜感激。

【问题讨论】:

    标签: checkbox reactjs components


    【解决方案1】:

    您提出的所有观点似乎都是合法的。 Smart vs Dumb 组件模式似乎是每个人都在采用的模式(并且有充分的理由,如果没有这种明确的分离,代码会变得非常混乱)。

    您同事的建议存在根本性错误的另一件事是,从孩子到父母的数据是向上流动的。 React 的核心思想之一是单向数据流。要传播到父级的子级更改应该通过存储(或任何您的数据层)以保持此单向属性。

    React Data Flow

    通过让子节点通知父节点更新,它增加了一层复杂性(如果它触发子节点的更新,它会回到父节点并永远循环呢?)React 试图摆脱首先(正是这个问题让人们怀疑 Angular 应用程序的可扩展性,让它们在更大的范围内变得过于复杂)。

    【讨论】:

    • 非常感谢您的解释。它有很大帮助,尤其是单向数据流部分。如果没有其他答案提交,我稍后会将此作为正确答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-10
    • 2023-03-03
    • 1970-01-01
    • 2019-09-17
    • 2015-05-21
    • 2018-07-01
    相关资源
    最近更新 更多