如何在 <List> 中将元素数组呈现为 <Dialog>

How to render array of elements as <Dialog> in a <List>

我正在构建一个组件,<ElementList>,它接收 props 中的元素数组,并且 builds 一个 <List>,其中每个 <ListItem> 是数组的一个元素。 我正在向 <ListItem> 传递一个名为 <ElementShow> 的单独组件,它包装了一个 material-ui <Dialog> 组件。
单击 <ListItem> 时,它应该打开特定 <ElementShow> 组件的 <Dialog>

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

参考代码如下:

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

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

任何 help/tips 不胜感激!

好吧,你遇到的一个问题是 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

您需要为呈现的每个对话框设置单独的状态(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/close 函数中包含索引以访问部分数组。

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

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

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