如何在<list>中将元素数组渲染为<dialog>

时间:2017-03-22 22:10:09

标签: javascript arrays reactjs material-ui

我正在构建一个组件<ElementList>,它接收道具中的元素数组,并构建一个<List>,其中每个<ListItem>都是数组的元素。 我将<ListItem>一个名为<ElementShow>的单独组件传递给了<Dialog>,它包裹了一个材料-ui <ListItem>组件。
单击<Dialog>后,应该会打开特定<ElementShow>组件的<ListItem>

目前,当我点击任意<Dialog>时,无论我点击哪个<ListItem>,它都会为数组的最后一个元素打开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

以下是参考代码:

ElementList.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.js

{{1}}

我认为我需要将对话状态与特定字符相关联,但我还没有找到可行的方法。

感谢任何帮助/提示!

3 个答案:

答案 0 :(得分: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

答案 1 :(得分:0)

您需要为每个呈现的对话框提供单独的状态(true或false)。

将每个元素的索引传递给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>
        )
      })

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

  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 })
  }

答案 2 :(得分:0)

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

  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}
         />
      )}
    ))}
  )