React Material UI Множественный свернуть

В настоящее время все мои списки сворачиваются, но они связаны с одним состоянием «открыто», поэтому, если я открываю один список, открываются все остальные списки. Каков наилучший способ отделить схлопывания друг от друга, не имея большого количества состояний для каждого списка.

РЕДАКТИРОВАТЬ: приложение проходит через бесконечный цикл

App.tsx

interface IState {
error: any,
intro: any,
threads: any[],
title: any,
}

export default class App extends React.Component<{}, IState> {
    constructor (props : any) {
        super (props);

        this.state = {
            error: "",
            intro: "Welcome to RedQuick",
            threads: [],
            title: ""
        };

        this.getRedditPost = this.getRedditPost.bind(this)
        this.handleClick = this.handleClick.bind(this)
    }

    public getRedditPost = async (e : any) => {
        e.preventDefault();

        const subreddit = e.target.elements.subreddit.value;
        const redditAPI = await fetch('https://www.reddit.com/r/'+ subreddit +'.json');
        const data = await redditAPI.json();

        console.log(data);

        if (data.kind) {
            this.setState({
                error: undefined,
                intro: undefined,
                threads: data.data.children,
                title: data.data.children[0].data.subreddit.toUpperCase()
            });
        } else {
            this.setState({
                error: "Please enter a valid subreddit name",
                intro: undefined,
                threads: [],
                title: undefined
            });
        }
    }

    public handleClick = (index : any)  => {
        this.setState({ [index]: true });
    }

    public render() {
        return (
            <div>
                <Header 
                    getRedditPost={this.getRedditPost}
                />
                <p className="app__intro">{this.state.intro}</p>
                {
                    this.state.error === "" && this.state.title.length > 0 ?
                    <LinearProgress />:
                    <ThreadList 
                        error={this.state.error}
                        handleClick={this.handleClick}
                        threads={this.state.threads}
                        title={this.state.title}
                    />
                }   
            </div>
        );
    }
}

Threadlist.tsx

<div className="threadlist__subreddit_threadlist">
    <List>
        { props.threads.map((thread : any, index : any) => 
            <div key={index} className="threadlist__subreddit_thread">
                <Divider />
                <ListItem button={true} onClick={props.handleClick(index)}/* component="a" href={thread.data.url}*/ >
                    <ListItemText primary={thread.data.title} secondary={<p><b>Author: </b>{thread.data.author}</p>} />
                    {props[index] ? <ExpandLess /> : <ExpandMore />}
                </ListItem>
                <Collapse in={props[index]} timeout="auto" unmountOnExit={true}>
                    <p>POOP</p>
                </Collapse>
                <Divider />
            </div>
        ) }
    </List> 
</div>

person Hyokune    schedule 31.08.2018    source источник
comment
это действительно расплывчато, но вы можете ввести список и передать открытое состояние, в которое один из них   -  person Ricardo Costa    schedule 31.08.2018
comment
Извините, я отредактировал вопрос, чтобы он был более понятным   -  person Hyokune    schedule 01.09.2018
comment
я добавил ответ с возможным решением. Динамическое открытое состояние   -  person Ricardo Costa    schedule 03.09.2018


Ответы (2)


Вы должны создать другое состояние для каждого коллапса, я предлагаю использовать setState динамически с индексом, который вы получили из функции карты, вам, вероятно, придется передать параметр индекса в функцию handleClick и изменить состояние на основе этого

<div className="threadlist__subreddit_threadlist">
    <List>
        { props.threads.map((thread : any, index : any) => 
            <div key={index} className="threadlist__subreddit_thread">
                <Divider />
                <ListItem button={true} onClick={props.handleClick(index)}/* component="a" href={thread.data.url}*/ >
                    <ListItemText primary={thread.data.title} secondary={<p><b>Author: </b>{thread.data.author}</p>} />
                    {props[index] ? <ExpandLess /> : <ExpandMore />}
                </ListItem>
                <Collapse in={props[index]} timeout="auto" unmountOnExit={true}>
                    <p>POOP</p>
                </Collapse>
                <Divider />
            </div>
        ) }
    </List> 
</div>

Ваш handleClick должен выглядеть примерно так:

public handleClick = (index : any)  => {
        this.setState({ [index]: true });
    }
person Ricardo Costa    schedule 02.09.2018
comment
При изменении функции handleClick мне выдает ошибку TS1005: ':' Ожидается. в части openArray[index]. Также не лучше ли использовать prevState, чтобы разрешить закрытие коллапса после открытия? Но я также получаю сообщение об ошибке при использовании prevState - person Hyokune; 03.09.2018
comment
да, вы можете сделать это с prevState, я дал вам небольшой пример, а не полный ответ, я отредактировал, но он должен работать как есть. это дает вам ошибку машинописного текста, и с этим я не могу вам помочь - person Ricardo Costa; 03.09.2018
comment
Я также не знаю, как вы создали свой handleClick, потому что вы не поделились им, так трудно помочь - person Ricardo Costa; 03.09.2018
comment
stackoverflow.com/questions/29280445 / - person Ricardo Costa; 03.09.2018
comment
Мой handleClick и состояние взяты из другого компонента App.tsx, я обновил вопрос с помощью моего handleClick внутри файла App.tsx. - person Hyokune; 03.09.2018
comment
посмотрите на код, который я сделал, он сильно отличается от вашего, вам нужно динамическое состояние для каждого отдельного компонента, а не общее, поэтому я делаю [index]: правда, попробуйте это, пожалуйста - person Ricardo Costa; 04.09.2018
comment
Это не позволяет мне поместить handleClick как this.setState({ [index]: true }); Это дает мне ошибку аргумента, говорящую, что Аргумент типа '{ [x: number]: boolean; }» нельзя присвоить параметру типа «IState... - person Hyokune; 04.09.2018
comment
потому что вы должны передать индекс, когда вы можете использовать функцию в компоненте следующим образом: props.handleClick(index), вы пробовали мой код? - person Ricardo Costa; 04.09.2018
comment
Кажется, я решил эту проблему, добавив [index:number]: any в интерфейс IState, но теперь я получаю сообщение об ошибке бесконечного цикла. - person Hyokune; 04.09.2018
comment
Я думаю, что это совершенно другой вопрос, если хотите, примите этот ответ и создайте новый, объясняющий новую проблему. - person Ricardo Costa; 04.09.2018
comment
О, хорошо, извините, новичок в stackoverflow. Спасибо за помощь - person Hyokune; 04.09.2018
comment
Не проблема, чувак, это просто потому, что мы уже потеряли из виду первоначальную проблему. - person Ricardo Costa; 04.09.2018
comment
Давайте продолжим обсуждение в чате. - person Hyokune; 04.09.2018

Я сделал это таким образом:

function DrawerMenuItems() {
  const [selectedIndex, setSelectedIndex] = React.useState("")

  const handleClick = index => {
    if (selectedIndex === index) {
      setSelectedIndex("")
    } else {
      setSelectedIndex(index)
    }
  }
  return (
    <List
      component="nav"
      aria-labelledby="nested-list-subheader"
      subheader={
        <ListSubheader component="div" id="nested-list-subheader">
          Nested List Items
        </ListSubheader>
      }
    >
      {drawerMenuItemData.map((item, index) => {
        return (
          <List>
            <ListItem
              key={index}
              button
              onClick={() => {
                handleClick(index)
              }}
            >
              <ListItemIcon>
                <item.icon />
              </ListItemIcon>
              <ListItemText primary={item.title} />
              {index === selectedIndex ? <ExpandLess /> : <ExpandMore />}
            </ListItem>
            <Collapse in={index === selectedIndex} timeout="auto" unmountOnExit>
              <List component="div" disablePadding>
                {item.submenu.map((sub, index) => {
                  return (
                    <ListItem button >
                      <ListItemText primary={sub.name} />
                    </ListItem>
                  )
                })}
              </List>
            </Collapse>
          </List>
        )
      })}
    </List>
  )
}
person Md.Abdul Halim Rafi    schedule 13.05.2020
comment
Я тоже решил свою проблему, но в настоящее время у меня есть проблема: как сделать так, чтобы она сохранялась в открытом состоянии, когда вы щелкнули вложенные элементы? - person Favour George; 16.04.2021
comment
В этом случае вы можете использовать массив вместо строки в файле useState. Затем просто сохраните в нем ключ элемента и удалите его при сворачивании. - person Md.Abdul Halim Rafi; 17.04.2021