【问题标题】:How to select all checkboxes in React?如何选择 React 中的所有复选框?
【发布时间】:2017-06-12 19:04:59
【问题描述】:

我有这个模块:

import React, { Component } from 'react'
import EmailListItem from './EmailListItem'
import { createContainer } from 'meteor/react-meteor-data'
import { Emails } from '../../../../../imports/collections/emails/Emails'

class EmailList extends Component {
  constructor (props) {
    super(props)
    this.state = {
      selectedEmails: new Set(),
      checked: false
    }
  }

  handleSelectedEmails (selectedEmail, checked) {
    let selectedEmails = this.state.selectedEmails
    if (checked) {
      selectedEmails.add(selectedEmail)
    } else {
      selectedEmails.delete(selectedEmail)
    }
    this.setState({selectedEmails})
    console.log('selectedEmails', this.state.selectedEmails)
  }
  removeSelected () {
    const selectedEmails = Array.from(this.state.selectedEmails)
    Meteor.call('emails.remove', selectedEmails, (err, result) => {
      if (err) console.log(err)
      if (result) console.log(result)
    })
  }
  checkedClick () {
    this.setState({checked: !this.state.checked})
    console.log('chcekedClick')
  }
  renderList () {
    console.log(this.props)
    return this.props.emails.map(email => {
      console.log(email)
      const { name, opr, ctr, _id } = email
      const createdAt = email.createdAt.toDateString()
      const link = `/dashboard/emailpreview/${_id}`
      return (
        <EmailListItem
          selecetedAllEmails={this.state.checked}
          handleSelectedEmails={this.handleSelectedEmails.bind(this)}
          name={name}
          createdAt={createdAt}
          opr={opr}
          ctr={ctr}
          link={link}
          key={email._id}
          id={email._id} />
        )
    })
  }
  render () {
    // TODO: make checks with state
    return (
      <div className="email_list">
        <table>
          <thead>
            <tr>
              <td><input onChange={this.checkedClick.bind(this)} type="checkbox" checked={this.state.checked} /></td>
              <td>Title<button onClick={this.removeSelected.bind(this)} className="btn btn-danger">Remove</button></td>
              <td>Dates</td>
              <td>Open Rates</td>
              <td>CTA</td>
            </tr>
          </thead>
          <tbody>
            {this.renderList()}
          </tbody>
        </table>

      </div>
  )
  }
}

export default createContainer(() => {
  Meteor.subscribe('emails')
  return { emails: Emails.find({}).fetch() }
}, EmailList)

它会渲染这个模块

import React, { Component } from 'react'
import { Link } from 'react-router'

class EmailListItem extends Component {
  constructor (props) {
    super(props)
    this.state = {
      checked: false
    }
  }

  checkedClick () {
    this.setState({checked: !this.state.checked})
    console.log('chcekedClick')
  }

  componentDidUpdate () {
    console.log('componentDidUpdate')
    const { myCheckbox } = this.refs
    console.log('myCheckbox', myCheckbox)
    console.log('myCheckbox.name', myCheckbox.name)
    console.log('myCheckbox.checked', myCheckbox.checked)
    if (this.props.selecetedAllEmails) {
      console.log('componentDidUpdate IF')
      this.checkedClick()
      this.props.handleSelectedEmails(myCheckbox.name, myCheckbox.checked)
    }
  }
  render () {
    console.log('_id', this.props.id)
    return (
      <tr>
        <td><input ref="myCheckbox"
          onChange={(event) => {
            this.checkedClick()
            this.props.handleSelectedEmails(event.target.name, event.target.checked)
          }}
          checked={this.state.checked}
          type="checkbox" name={this.props.id} /></td>
        <td><Link to={this.props.link}>{this.props.name}</Link></td>
        <td>{this.props.createdAt}</td>
        <td>Open Rates</td>
        <td>CTA</td>
      </tr>
    )
  }
}

export default EmailListItem

如您所见,对于每个电子邮件项目,我都有一个复选框。我可以选择几个复选框,然后单击删除按钮,该按钮将调用删除我的选定项目。现在在顶部我有一个复选框,应该选择所有复选框。我对此的解决方案是存储选中的全局复选框并将其作为道具传递给所有项目。然后在项目中我对 componentDidUpdate 进行检查,如果选中了全局复选框,那么我也会检查该项目。但这会导致无限循环。这里最好的解决方案是什么?

【问题讨论】:

    标签: javascript reactjs meteor checkbox


    【解决方案1】:

    您可以使用componentWillReceiveProps 代替componentDidUpdate

    class EmailListsItem extends Component {
      // ...
      componentWillReceiveProps (nextProps) {
        const { myCheckbox } = this.refs
    
        // if selecetedAllEmails is updated from false to true
        if (nextProps.selecetedAllEmails && !this.props.selecetedAllEmails) {
          this.checkedClick()
          this.props.handleSelectedEmails(myCheckbox.name, myCheckbox.checked)
        }
      }
      // ...
    }
    

    【讨论】:

      【解决方案2】:

      我认为,不需要为每个电子邮件 ID 维护单独的状态,您已经将值存储在 parent 组件中,将值从 parent 传递到 props,其他事情是选择所有电子邮件 ID,您在 parent 中维护一个 bool,在传递 props 中的值时检查该 bool,如果 bool 为 true,则传递 true,否则检查 set 并传递 set 返回的结果。

      查看jsfiddle的工作解决方案:https://jsfiddle.net/h17mcjwa/

      试试这个renderList 方法:

      renderList () {
       return this.props.emails.map(email => {
            const { name, opr, ctr, _id } = email
            const createdAt = email.createdAt.toDateString()
            const link = `/dashboard/emailpreview/${_id}`
            return (
              <EmailListItem
                handleSelectedEmails={this.handleSelectedEmails.bind(this)}
                name={name}
                createdAt={createdAt}
                opr={opr}
                ctr={ctr}
                link={link}
                key={email._id}
                id={email._id} 
                value={this.state.checked || this.state.selectedEmails.has(email._id)}
              />
            )
         })
       }
      

      并使用这个组件:

      class EmailListItem extends Component {
        constructor (props) {
          super(props)
          //this.state = {
          //  checked: false
          //}
        }
      
        //checkedClick () {
        //  this.setState({checked: !this.state.checked})
        //  console.log('chcekedClick')
        //}
      
        //componentDidUpdate () {
        //  if (this.props.selecetedAllEmails) {
        //    this.checkedClick()
        //    this.props.handleSelectedEmails(myCheckbox.name, myCheckbox.checked)
        //  }
        //}
      
        render () {
          return (
            <tr>
              <td><input ref="myCheckbox"
                onChange={(event) => {
                  this.props.handleSelectedEmails(event.target.name, event.target.checked)
                }}
                checked={this.props.value}
                type="checkbox" name={this.props.id} /></td>
              <td><Link to={this.props.link}>{this.props.name}</Link></td>
              <td>{this.props.createdAt}</td>
              <td>Open Rates</td>
              <td>CTA</td>
            </tr>
          )
        }
      }
      

      如果它不适合你,请告诉我。

      【讨论】:

      • 这似乎是一个优雅的解决方案,尽管我目前并不完全理解它。我现在正在研究它。但是,这里有一些问题,我注意到选择全部然后检查一个或几个呢?当我选择所有复选框时,所有复选框都已设置,但没有添加到我的 Set
      • 没有写完所有的case,只是提供了一个基本的工作模板,你只需要在提供的函数中处理所有的case。除此之外,如果您遇到任何问题,请告诉我。
      【解决方案3】:

      虽然一些答案提供了选择所有复选框的特定功能,但我还需要通用功能,例如取消全选,全选然后取消选择一些,当手动选择所有全选复选框时等等......所以我写了所有这些并将其作为答案发布在这里。感谢所有回复的人。此代码基于 Mayank Shuklas 的回答。请注意,它可能仍然不完美,因为我还没有正确测试它,它肯定需要一些重构。

      import React, { Component } from 'react'
      import EmailListItem from './EmailListItem'
      import { createContainer } from 'meteor/react-meteor-data'
      import { Emails } from '../../../../../imports/collections/emails/Emails'
      
      class EmailList extends Component {
        constructor (props) {
          super(props)
          this.state = {
            selectedEmails: new Set(),
            checked: false
          }
        }
      
        handleSelectedEmails (allSelected, individualSelected, selectedEmail, checked) {
          console.log('allSelected', allSelected)
          console.log('individualSelected', individualSelected)
          console.log('selectedEmail', selectedEmail)
          console.log('checked', checked)
          let selectedEmails = this.state.selectedEmails
          if (allSelected && !individualSelected) {
              this.props.emails.forEach((email) => {
                selectedEmails.add(email._id)
              })
          } else if (!allSelected && !individualSelected) {
            selectedEmails.clear()
          } else if (individualSelected) {
            if (checked) {
              selectedEmails.add(selectedEmail)
              if (selectedEmails.size === this.props.emails.length) {
                this.checkAll()
              }
            } else {
              selectedEmails.delete(selectedEmail)
              this.setState({checked})
            }
          }
          this.setState({selectedEmails})
          console.log('selectedEmails', this.state.selectedEmails)
        }
        removeSelected () {
          const selectedEmails = Array.from(this.state.selectedEmails)
          Meteor.call('emails.remove', selectedEmails, (err, result) => {
            if (err) console.log(err)
            if (result) console.log(result)
          })
        }
        checkAll () {
          this.setState({checked: !this.state.checked})
          console.log('chcekedClick', this.state.checked)
          this.handleSelectedEmails(!this.state.checked, false)
        }
        renderList () {
          console.log(this.props)
          return this.props.emails.map(email => {
            // console.log(email)
            const { name, opr, ctr, _id } = email
            const createdAt = email.createdAt.toDateString()
            const link = `/dashboard/emailpreview/${_id}`
            return (
              <EmailListItem
                handleSelectedEmails={this.handleSelectedEmails.bind(this)}
                name={name}
                createdAt={createdAt}
                opr={opr}
                ctr={ctr}
                link={link}
                key={email._id}
                id={email._id}
                value={this.state.checked || this.state.selectedEmails.has(email._id)} />
              )
          })
        }
        render () {
          // TODO: make checks with state
          return (
            <div className="email_list">
              <table>
                <thead>
                  <tr>
                    <td><input onChange={this.checkAll.bind(this)} type="checkbox" checked={this.state.checked} /></td>
                    <td>Title<button onClick={this.removeSelected.bind(this)} className="btn btn-danger">Remove</button></td>
                    <td>Dates</td>
                    <td>Open Rates</td>
                    <td>CTA</td>
                  </tr>
                </thead>
                <tbody>
                  {this.renderList()}
                </tbody>
              </table>
      
            </div>
        )
        }
      }
      
      export default createContainer(() => {
        Meteor.subscribe('emails')
        return { emails: Emails.find({}).fetch() }
      }, EmailList)
      

      还有 EmailListItem

      import React, { Component } from 'react'
      import { Link } from 'react-router'
      
      class EmailListItem extends Component {
        render () {
          console.log('_id', this.props.id)
          return (
            <tr>
              <td><input ref="myCheckbox"
                onChange={(event) => {
                  this.props.handleSelectedEmails(false, true, event.target.name, event.target.checked)
                }}
                checked={this.props.value}
                type="checkbox" name={this.props.id} /></td>
              <td><Link to={this.props.link}>{this.props.name}</Link></td>
              <td>{this.props.createdAt}</td>
              <td>Open Rates</td>
              <td>CTA</td>
            </tr>
          )
        }
      }
      
      export default EmailListItem
      

      【讨论】:

        猜你喜欢
        • 2019-05-20
        • 2017-07-27
        • 2016-02-02
        • 1970-01-01
        • 1970-01-01
        • 2011-10-09
        • 2016-05-13
        • 2019-10-31
        • 1970-01-01
        相关资源
        最近更新 更多