React Material UI 多重折叠

Posted

技术标签:

【中文标题】React Material UI 多重折叠【英文标题】:React Material UI Multiple Collapse 【发布时间】:2019-02-06 01:25:09 【问题描述】:

目前我的列表都已折叠,但它们链接到“打开”的一种状态,因此如果我打开一个列表,则所有其他列表都会打开。 在每个列表没有很多状态的情况下,将折叠彼此分开的最佳方法是什么。

编辑:应用程序正在无限循环

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>

【问题讨论】:

这真的很模糊,但是您可以对列表进行集成并将其中一个传递给打开状态 对不起,我已经编辑了这个问题,所以它更容易理解 我已经添加了一个可能的解决方案的答案。动态打开状态 【参考方案1】:

你必须为每次折叠创建一个不同的状态,我建议动态使用 setState 和你从 map 函数获得的索引,你可能必须将索引参数传递给 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 );
    

【讨论】:

更改 handleClick 函数时,出现错误“错误 TS1005: ':' expected.”在 openArray[index] 部分。也不是最好使用 prevState 让折叠在打开后关闭吗?但是我在使用 prevState 时也会收到错误 是的,你可以用 prevState 做到这一点,我给你的是一个小例子而不是完整的答案,我编辑了但它应该可以正常工作。它给你一个打字错误,我帮不了你那么多 我也不知道你是如何创建你的handleClick的,因为你没有分享它,这样很难帮助 ***.com/questions/29280445/… 因为当你可以像这样在组件中的函数时,你必须传递索引:props.handleClick(index),你试过我的代码吗?【参考方案2】:

我是这样做的:

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

【讨论】:

我的也是这样解决的,但是我现在有一个问题,当你点击嵌套项目时如何让它保持打开状态? 在这种情况下,您可以在useState 中使用数组而不是字符串。然后只需将项目密钥存储在其中,并在折叠时将其删除。 非常感谢。 :)【参考方案3】:

您也可以使用 ant 设计的折叠组件。我用它做了一个嵌套的折叠组件。基本上,使用哪个库并不重要。重要的是您如何传递数据以及如何控制活动密钥。这是我的一个例子......

const ProductCatagoryHierarchy = () => 

 const [tree, setTree] = useState([])

 useEffect( async () => 

    const arr2 = [
            id: 1, name: 'gender', parent: null, parent_id: null ,
            id: 2, name: 'material', parent: null, parent_id: null,
             id: 3, name: 'male', parent: 1, parent_name: "gender" ,
             id: 5, name: 'female', parent: 1, parent_name: "gender" ,
             id: 4, name: 'shoe', parent: 3, parent_id: "male" ,
        ]

        let newarr=[];
        for(let i=0 ; i< arr2.length; i++ )

            if(arr2[i].id)
                if(newarr[i] !=  )
                    newarr[i] = 
                
                newarr[i].id = arr2[i].id 
            
            if( arr2[i].name )
                newarr[i].name = arr2[i].name 
            
            if( arr2[i].parent )
                newarr[i].parent = arr2[i].parent 
            
            if( arr2[i].parent_id )
                newarr[i].parent_id = arr2[i].parent_id 
            

            newarr[i].products = arr2[i].products;
        

        console.log('newarr', newarr );

        let tree = function (data, root) 
            var t = ;
            data.forEach(o => 
                Object.assign(t[o.id] = t[o.id] || , o);
                t[o.parent] = t[o.parent] || ;
                t[o.parent].children = t[o.parent].children || [];
                t[o.parent].children.push(t[o.id]);
            );
            return t[root].children;
        (newarr, undefined);
        
        console.log('tree ', tree);
        setTree(tree)
 , [])

  const childFunc = (children) => 
        // console.log('children', children );
        let childPanel = children.map((child, i) => 
            return(
                <Collapse /* defaultActiveKey=child.id */  
                style= margin: '10px 0'   key=i 
                expandIcon=( isActive ) => 
               <CaretRightOutlined rotate=isActive ? 90 : 0 />
                >
                    <Panel header=child.name key=child.id   >
                    <p>  child?.products?.length > 0 ? 
                    <p> Products: <strong> 
                   child.products.map(x =>  x.name  ).join(', ')  
                  </strong> </p> : 'No Product Available' </p> 

                    child?.children?.length > 0 ? 
                    childFunc(child.children) : null 
                    </Panel>
                </Collapse>
            )
        )

        return childPanel; 
    

    return(
        <div>

        <h1> Category Hierarchy </h1>

        /* <Button onClick=() => onclick() > test </Button> */


        <Collapse  >
            
                tree.map((x,i,l) => 
                console.log('x,i,l', x, i, l );
                return(
                <Panel header=x.name key=x.id  
               style= backgroundColor: 'darkgray'  >
                <p>  x?.products?.length > 0 ? 
               <p> Products: <strong> 
                x.products.map(x => x.name).join(', ')  
               </strong> </p> : 'No Product Available' </p> 
                
                    x?.children?.length > 0 ? 
                    childFunc(x.children)
                    :
                    null
                
                </Panel>
                )
                )
            

            
        </Collapse>

        </div>
    )


export default ProductCatagoryHierarchy;

【讨论】:

以上是关于React Material UI 多重折叠的主要内容,如果未能解决你的问题,请参考以下文章

Material UI 手风琴在折叠或展开时会导致页面闪烁

打字稿:React.forwardRef 带有来自@material-ui 的通用道具

Material-UI 中的多个展开/折叠 TableRow 组件

如何使用 Typescript 扩展 Material-UI 组件的道具?

Material-ui中网格项目的对齐方式

未找到模块:错误:无法解析“@material-ui/core/styles”(部署到 heroku 时)