【问题标题】:React - Mapped array not passing props correctly to child componentReact - 映射数组未将道具正确传递给子组件
【发布时间】:2019-10-07 21:31:15
【问题描述】:

我正在制作一个仪表板组件,它显示 HTML sn-ps 的渲染预览和代码。在仪表板组件内部,我使用.map 映射sn-ps 数组。每个映射的 sn-p 都会有一个删除功能(已经构建)和一个更新功能。

为了使更新功能起作用,每个 sn-p 都有自己的子模态组件。我需要将 sn-p 的 ID 传递给模态组件,在该组件中我可以在更新数据库和状态之前将 ID 与新内容结合起来。

但是,当我将 ID 作为道具传递给模式时,我在某处犯了错误。

.map 在我的 Dashboard.js Dashboard 类组件中使用。

{this.state.snippets.map(snippet => (
  <>
    <div key={snippet._id} className="holder--pod">
      <div className="content">
        <div className="content__snippet-preview">
          Snippet preview
        </div>
        <div className="content__body">
          <h4>{snippet.name}</h4>
          <p>{snippet.details}</p>
          <p>{snippet._id}</p> //THIS WORKS
          <pre>
            <code>{snippet.content}</code>
          </pre>
        </div>
        <div className="content__button">
          <button onClick={this.handleDelete(snippet._id)}>
            Delete
          </button>
          <button type="button" onClick={this.showModal}>
            Open
          </button>
        </div>
      </div>
    </div>
    <Modal
      sid={snippet._id} //PASS ID HERE
      show={this.state.show}
      handleClose={this.hideModal}
    ></Modal>
  </>
))}

这会呈现下面的 sn-ps(3 个 sn-p pod,包括它们的数据库 ID)。


打开按钮打开下面的模态(Modal.js)。

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

export default class Modal extends Component {
  constructor(props) {
    super(props)
    this.state = {
      name: '',
      details: '',
      content: '',
      message: null,
    }
  }
  handleInputChange = event => {
    this.setState({
      [event.target.name]: event.target.value,
    })
  }
  handleClick = id => event => {
    event.preventDefault()
    console.log(id)
  }

  render() {
    const { sid, show, handleClose } = this.props
    console.log(sid)
    const showHideClassName = show ? 'modal display-flex' : 'modal display-none'
    return (
      <div id="Modal" className={showHideClassName}>
        <div id="modal-main">
          <h4>Edit snippet {sid}</h4>
          <form>
            Name:{' '}
            <input
              type="text"
              value={this.state.name}
              name="name"
              onChange={this.handleInputChange}
            />{' '}
            <br />
            Details:{' '}
            <input
              type="text"
              value={this.state.details}
              name="details"
              onChange={this.handleInputChange}
            />{' '}
            <br />
            Content:{' '}
            <textarea
              value={this.state.content}
              name="content"
              cols="30"
              rows="10"
              onChange={this.handleInputChange}
            />{' '}
            <br />
            <button onClick={this.handleClick(sid)}>TEST ME</button>
          </form>
          <button onClick={handleClose}>Close</button>
          {this.state.message && (
            <div className="info">{this.state.message}</div>
          )}
        </div>
      </div>
    )
  }
}

渲染下方的console.log 实际上粘贴了正确的 3 个 ID 的控制台。

但是,在 Modal.js 返回中调用 ID (sid) 只会显示最后一个 sn-p ID,无论我打开哪个 Modal。将该 ID 推送到我打算将 ID 与更新包组合的 handleClick 函数也是如此。

【问题讨论】:

  • this.showModal 可能将 this.show 设置为 true,因此它会导致所有模式显示,您只能看到最后一个(顶部),但如果您按 F12 并检查元素或使用反应开发工具,你可以看到他们都把 show 属性设置为 true。
  • @HMR 你一针见血。不敢相信我没看到。
  • 正如其他人发布的那样; handleDelete 也是可疑的,除非它是一个柯里化函数handleDelete = (id)=&gt;()=&gt;....
  • @HMR 粘贴您的评论作为答案,以便我给您加分。

标签: javascript arrays reactjs


【解决方案1】:

以下由 HMR 在 cmets 中发起的解决方案。

问题是所有的模态都显示出来了,只有最后一个是可见的。 通过将模态移出.map 并将ID 从.map 更新到状态并将状态ID 传递给模态中的新嵌套组件来修复。

也切换到使用动态 CSS 来根据状态显示和隐藏模式。

仪表板.jsx

export default class Snippets extends Component {
  constructor(props) {
    super(props)
    this.showModal = React.createRef()
    this.state = {
      snippets: [],
      show: false,
      sid: '',
    }
  }

  handleDelete = id => event => {
    event.preventDefault()
    api
      .deleteSnippet(id)
      .then(result => {
        console.log('DATA DELETED')
        api.getSnippets().then(result => {
          this.setState({ snippets: result })
          console.log('CLIENT UPDATED')
        })
      })
      .catch(err => this.setState({ message: err.toString() }))
  }
  handleModal = id => {
    this.setState({ sid: id })
    this.showModal.current.showModal()
  }
  //<div id="preview">{ReactHtmlParser(snippet.content)}</div>

  render() {
    return (
      <>
        <Modal ref={this.showModal} handleClose={this.hideModal}>
          <ModalUpdate sid={this.state.sid} />
        </Modal>
        <div className="Dashboard">
          <div className="wrapper">
            <div className="container">
              <div className="holder">
                <div className="content">
                  <div className="content__body">
                    <h3>Dashboard</h3>
                  </div>
                </div>
              </div>
              <div className="break"></div>
              {this.state.snippets.map(snippet => (
                <div key={snippet._id} className="holder--pod">
                  <div className="content">
                    <div className="content__snippet-preview">
                      Snippet preview
                    </div>
                    <div className="content__body">
                      <h4>{snippet.name}</h4>
                      <p>{snippet.details}</p>
                      <p>{snippet._id}</p>
                      <pre>
                        <code>{snippet.content}</code>
                      </pre>
                    </div>
                    <div className="content__button">
                      <button onClick={this.handleDelete(snippet._id)}>
                        Delete
                      </button>
                      <button
                        type="button"
                        onClick={() => this.handleModal(snippet._id)}
                      >
                        Open
                      </button>
                    </div>
                  </div>
                </div>
              ))}
            </div>
          </div>
        </div>
      </>
    )
  }


Modal.jsx

import React, { Component } from 'react'

export default class Modal extends Component {
  constructor(props) {
    super(props)
    this.state = {
      show: false,
    }
  }
  showModal = () => {
    this.setState({ show: true })
  }
  hideModal = () => {
    this.setState({ show: false })
  }

  render() {
    return (
      <div
        id="Modal"
        style={{ display: this.state.show === true ? 'flex' : 'none' }}
      >
        <div id="modal-main">
          <h4>Edit snippet </h4>
          {this.props.children}
          <button onClick={() => this.hideModal()}>Close</button>
        </div>
      </div>
    )
  }
}


ModalUpdate.jsx

import React, { Component } from 'react'

export default class ModalUpdate extends Component {
  constructor(props) {
    super(props)
    this.state = {
      name: '',
      details: '',
      content: '',
      message: null,
    }
  }
  // handleInputChange = event => {
  //   this.setState({
  //     [event.target.name]: event.target.value,
  //   })
  // }
  // handleClick = id => event => {
  //   event.preventDefault()
  //   console.log(id)
  // }

  render() {
    return <h4>ID = {this.props.sid}</h4>
  }
}

【讨论】:

    【解决方案2】:

    我不确定 handleDelete 函数。但更换线路应该可以解决问题

    <button onClick={() => this.handleDelete(snippet._id)}>
    

    【讨论】:

      【解决方案3】:

      一个潜在的问题是this.handleDelete(snippet._id) 会立即触发而不是onClick,因此您需要在事件侦听器中添加一个匿名函数:

      () => this.handleDelete(snippet._id)
      

      而不是

      this.handleDelete(snippet._id)
      

      【讨论】:

        猜你喜欢
        • 2020-01-17
        • 2021-10-04
        • 1970-01-01
        • 2020-12-19
        • 2020-09-01
        • 2018-07-07
        • 2022-01-24
        • 2020-04-22
        相关资源
        最近更新 更多