React JS - Material UI ListItem (with Collapse API) onClick expands/collapse all sub list items instead of the selected one

React JS - Material UI ListItem (with Collapse API) onClick expands/collapse all sub list items instead of the selected one

我正在使用 React JS 实现 List 的 Expand/Collapse 功能 - Material UI ListItem(带折叠 API)

当我单击 ListItem 时,它 expands/collapse 所有子列表项而不是选定项。

这是示例代码。看起来我在其中一个元素中不正确地设置了键值,但无法弄清楚。有人能帮我吗?如果信息不足请告诉我

贾法尔

class CategoriesResults extends Component {
  constructor(props) {
    super(props);
    this.state = {
      open: false
    };
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    console.log("Handle Clicked....");
     this.setState(prevState => ({
       open: !prevState.open
     }));
  }

  render() {
    const docs = data.documents;  //this coming from a json file, please see below for the sample json
     return (
      <div>
        <List component='nav' aria-labelledby='nested-list-subheader'>
          {docs.map(doc => {
            return (
              <div key={doc.Id}>
                <ListItem button key={doc.Id} onClick={this.handleClick}>
                  <ListItemText primary={doc.Name} />
                  {this.state.open ? <ExpandLess /> : <ExpandMore />}
                </ListItem>
                <Collapse
                  key={doc.Sheets.Id}
                  in={this.state.open}
                  timeout='auto'
                  unmountOnExit
                >
                  <List component='li' disablePadding key={doc.Id}>
                    {doc.Sheets.map(sheet => {
                      return (
                        <ListItem button key={sheet.Id}>
                          <ListItemIcon>
                            <InsertDriveFileTwoToneIcon />
                          </ListItemIcon>
                          <ListItemText key={sheet.Id} primary={sheet.Title} />
                        </ListItem>
                      );
                    })}
                  </List>
                </Collapse>
                <Divider />
              </div>
            );
          })}
        </List>     
      </div>
    );
  }
}


**Sample JSON**

{
  "documents": [
    {
      "Id": 1,
      "Name": "Category 1",
      "Sheets": [
        {
          "Id": 1,
          "Title": "Title1 "
        },
        {
          "Id": 2,
          "Title": "Title 2"
        },
        {
          "Id": 3,
          "Title": "Title 3"
        }
      ]
    }
}

您的所有 ListItem 都基于相同的状态展开。
如果 open 是 true,它们的 Collapse 组件中都会得到 in=true,所以它们都被展开了。
要解决这个问题,您应该将可扩展的 ListItem 提取到一个单独的组件中,该组件将管理它自己的状态:

 class CustomizedListItem extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
        open: false
      };
      this.handleClick = this.handleClick.bind(this);
    }

    handleClick() {
      console.log("Handle Clicked....");
       this.setState(prevState => ({
         open: !prevState.open
       }));
    }

  render(){
  const { doc } = this.props;
  return (
    <div>
      <ListItem button key={doc.Id} onClick={this.handleClick}>
        <ListItemText primary={doc.Name} />
        {this.state.open ? <ExpandLess /> : <ExpandMore />}
      </ListItem>
      <Collapse
        key={doc.Sheets.Id}
        in={this.state.open}
        timeout='auto'
        unmountOnExit
      >
      <List component='li' disablePadding key={doc.Id}>
        {doc.Sheets.map(sheet => {
          return (
            <ListItem button key={sheet.Id}>
              <ListItemIcon>
                {/* <InsertDriveFileTwoToneIcon /> */}
              </ListItemIcon>
              <ListItemText key={sheet.Id} primary={sheet.Title} />
            </ListItem>
          );
        })}
      </List>
    </Collapse>
    <Divider />
    </div>
    )
  }
}

export default class CategoriesResults extends React.Component {
  render() {
    const docs = data.documents;  //this coming from a json file, please see below for the sample json
     return (
      <div>
        <List component='nav' aria-labelledby='nested-list-subheader'>
          {docs.map(doc => {
            return (
              <CustomizedListItem key={doc.id} doc={doc} />
            );
          })}
        </List>     
      </div>
    );
  }
}

我使用了 class 组件,因为您在问题中使用了它。如果你想看到与 react-hooks 相同的解决方案,请告诉我:)

我已经把它转换成一个基于函数的组件,使用 hooks 这样未来的人可以很容易地理解它:

import React, { useState } from 'react'

const CustomizedListItem = ({ doc }) => {
    const [ open, setOpen ] = useState(false)
    const handleClick = () => {
        setOpen(!open)
    }
    
    return (
        <div>
            <ListItem button key={doc.Id} onClick={handleClick}>
                <ListItemText primary={doc.Name} />
                {open ? <ExpandLess /> : <ExpandMore />}
            </ListItem>
            <Collapse
                key={doc.Sheets.Id}
                in={open}
                timeout='auto'
                unmountOnExit
            >
                <List component='li' disablePadding key={doc.Id}>
                    {doc.Sheets.map(sheet => {
                        return (
                            <ListItem button key={sheet.Id}>
                                <ListItemIcon>
                                    {/* <InsertDriveFileTwoToneIcon /> */}
                                </ListItemIcon>
                                <ListItemText key={sheet.Id} primary={sheet.Title} />
                            </ListItem>
                        )
                    })}
                </List>
            </Collapse>
            <Divider />
        </div>
    )
}


export default function CategoriesResults() {
    const docs = data.documents  //this coming from a json file
    return (
        <div>
            <List component='nav' aria-labelledby='nested-list-subheader'>
                {docs.map(doc => {
                    return (
                        <CustomizedListItem key={doc.id} doc={doc} />
                    )
                })}
            </List>
        </div>
    )
}