【问题标题】:How to render array of elements as <Dialog> in a <List>如何在 <List> 中将元素数组呈现为 <Dialog>
【发布时间】:2017-08-15 06:32:43
【问题描述】:

我正在构建一个组件&lt;ElementList&gt;,它接收道具中的元素数组并构建一个&lt;List&gt;,其中每个&lt;ListItem&gt; 都是数组的一个元素。 我将&lt;ListItem&gt; 传递给一个名为&lt;ElementShow&gt; 的单独组件,它包装了一个material-ui &lt;Dialog&gt; 组件。
当单击&lt;ListItem&gt; 时,它应该为特定的&lt;ElementShow&gt; 组件打开&lt;Dialog&gt;

目前,当我单击任何&lt;ListItem&gt; 时,它会为数组的最后一个元素打开&lt;Dialog&gt;,无论我单击哪个&lt;ListItem&gt;

下面是代码供参考:

元素列表.js

import React from 'react'
import {List, ListItem} from 'material-ui/List'
import Subheader from 'material-ui/Subheader'
import ElementShow from './ElementShow'

class ElementList extends React.Component {
  constructor() {
    super()
    this.state = {
      dialogOpen: false
    }
  }

  handleOpen = () => {
    this.setState({dialogOpen: true})
  }

  handleClose = () => {
    this.setState({dialogOpen: false})
  }

  renderElements () {
    const {elements} = this.props
    if (elements.length < 1) {
      return (
        <ListItem
          key='empty_element'
          primaryText='No Elements Yet'
        />
      )
    } else {
      return elements.map(element => {
        return (
          <ListItem
            key={element._id}
            primaryText={element.name}
            onClick={this.handleOpen}
          >
            <ElementShow
              dialogOpen={this.state.dialogOpen}
              handleClose={this.handleClose} element={element} />
          </ListItem>
        )
      })
    }
  }

  render () {
    return (
      <List className='box'>
        <Subheader>Elements</Subheader>
        {this.renderElements()}
      </List>
    )
  }
}
export default ElementList

ElementShow.js

import React from 'react'
import Dialog from 'material-ui/Dialog'

class ElementShow extends React.Component {
  constructor (props) {
    super(props)
    this.state = {
      open: props.dialogOpen
    }
  }

  render () {
    const { element, handleClose } = this.props
    return (
      <Dialog
        title={element.name}
        modal={false}
        open={this.props.dialogOpen}
        onRequestClose={handleClose}>
        {element}
      </Dialog>
    )
  }
}

export default ElementShow

我想我需要将对话状态链接到特定角色,但我还没有找到可行的方法。

感谢任何帮助/提示!

【问题讨论】:

  • 不能在 ElementShow 中使用 onRequestClose 代替吗?为什么父母需要传递handleClose
  • 我猜父母不需要传递handleClose。问题是我需要为每个元素附加一个 dialogOpen 状态,并能够从父组件更改它的值。

标签: javascript arrays reactjs material-ui


【解决方案1】:

好吧,您遇到的一个问题是this.state 是父组件的状态,而不是特定于每个子组件 - 所以当您编写时

elements.map((element) => {
    ...
    <ElementShow dialoagOpen={ this.state.dialogOpen } />
})

它将影响所有元素。

我会做类似的事情

class ElementList {
    onClickElement = (element) => {
        this.setState({
            dialogOpen: true,
            selectedElement: element
        });
    }

    render() {
        const mElements = elements.map((element) => {
            /* I would suggest using a partial here, as opposed to what I've written */
            return <ListItem onClick={ () => { this.onClickElement(element) } } />
        });

        const { selectedElement } = this.state;

        return (
            <div>
                <List className='box'>
                    <Subheader>Elements</Subheader>
                    { mElements } 
                </List>

                { selectedElement && (
                    <Dialog
                        title={ selectedElement.name }
                        modal={ false}
                        open={ this.state.dialogOpen }
                        element={ selectedElement }
                        onRequestClose={ this.handleClose }
                    >
                        { selectedElement }
                    </Dialog>
                ) }
            </div>
        )
    }
}

我认为这将完成您想要的。如果要隐藏对话框,请将this.state.dialogOpen 设置为false 并清除this.state.selectedElement

【讨论】:

  • 谢谢!!这按预期工作。我可以传递&lt;ElementShow&gt; 组件而不是selectedElement &amp;&amp; 块内的对话框。
【解决方案2】:

您需要为每个渲染的对话框设置单独的状态(真或假)。

将每个元素的索引传递给您的 handleOpenhandleClose 函数,并使用它来切换正确的状态。

return elements.map((element, index) => {
        return (
          <ListItem
            key={element._id}
            primaryText={element.name}
            onClick={() => this.handleOpen(index)}
          >
            <ElementShow
              dialogOpen={this.state.dialogOpen[index]}
              handleClose={this.handleClose(index)} element={element} />
          </ListItem>
        )
      })

接下来,将您的状态设置为等于元素数量的数组,并将第一个对话框初始化为打开。在您的打开/关闭函数中包含索引以访问数组的各个部分。

  constructor(props) {
    super(props)
    this.state = {
      dialogOpen: props.element.map((element, index) => {
        return index === 0 ? true : false;
      }
    }
  }

  handleOpen = (index) => {
    this.setState({ dialogOpen[index]: true })
  }

  handleClose = (index) => {
    this.setState({ dialogOpen[index]: false })
  }

【讨论】:

    【解决方案3】:

    对于任何使用钩子的人,这是我的解决方案:

      const [openDialog, setDialogOpen] = React.useState(false);
      const [selectedElement, setSelectedElement] = React.useState();
    
      const handleDialogOpen = (element) => {
        setDialogOpen(true);
        setSelectedElement(element);
      };
      return (
        {elements.map((e) => (
         ...
         <CardActionArea onClick={() => handleDialogOpen(e)}>
         ...
         {selectedElement && (
            <EditDialog
             selectedElement={selectedElement}
             openDialog={openDialog}
             setOpenDialog={setDialogOpen}
             />
          )}
        ))}
      )
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-07-09
      • 2010-12-23
      • 1970-01-01
      • 2022-01-08
      • 1970-01-01
      • 2020-06-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多