最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to add dynamic content to React Material UI expansion panels whilst keeping only one active tab at at time func

programmeradmin2浏览0评论

I have WebGL/React project that generates a list of users from a mock data on click.

I want this content to appear in an accordion and, as I've had good experience with material ui before I thought I'd use their expansion panel.

It works well straight from the demo page, however if I wanted to map over my user data base and populate the expansion panels with this instead, it appears to get rid of the handy functionality.

I would like the first expansion panel open by default and then as you click on one panel, any other panels close, which is the default behaviour from the example.

When I pass in props

      <ExpansionPanel
        square
        expanded={expanded === "panel1"}
        onChange={handleChange("panel1")}
      >
        <ExpansionPanelSummary
          aria-controls="panel1d-content"
          id="panel1d-header"
        >
          {props.country}
        </ExpansionPanelSummary>
        <ExpansionPanelDetails>{props.children}</ExpansionPanelDetails>
      </ExpansionPanel>
    </div>

then use it here....

              {users &&
                users.map(user => (
                  <Accordion title={user.name} key={user.name}>
                    <div className="overlay-container">
                      <div className="overlay overlay-anim">
                        <div className="overlay-content-container">
                          <div className="name-container">
                            <h1 key={user.id} className="user_name">
                              {user.name}
                            </h1>
                          </div>
                        </div>
                      </div>
                    </div>
                  </Accordion>
                ))}

It opens all the panels by default and doesn't close the others when one is active. (again not real data and the gif makes it a little buggy but I can't generate an example as the code base is too huge).

Would anyone have some ideas or examples of how to achieve this?

EDIT

as per below suggestion have added added an id into the mapping function and adapted the expansion ponent, unfortunately getting the same effect/issues

  const [expanded, setExpanded] = React.useState("panel" + props.id);

  const handleChange = panel => (event, newExpanded) => {
    setExpanded(newExpanded ? panel : false);
  };

  return (
    <div>
      <ExpansionPanel
        expanded={expanded === "panel" + props.i}
        onChange={handleChange("panel" + props.i)}
      >
        <ExpansionPanelSummary
          aria-controls={"panel" + props.id + "d" + "-content"}
          id={"panel" + props.id + "d" + "-header"}
        >
          {props.country}
        </ExpansionPanelSummary>
        <ExpansionPanelDetails>{props.children}</ExpansionPanelDetails>
      </ExpansionPanel>
    </div>
  );
}```

I have WebGL/React project that generates a list of users from a mock data on click.

I want this content to appear in an accordion and, as I've had good experience with material ui before I thought I'd use their expansion panel.

It works well straight from the demo page, however if I wanted to map over my user data base and populate the expansion panels with this instead, it appears to get rid of the handy functionality.

I would like the first expansion panel open by default and then as you click on one panel, any other panels close, which is the default behaviour from the example.

When I pass in props

      <ExpansionPanel
        square
        expanded={expanded === "panel1"}
        onChange={handleChange("panel1")}
      >
        <ExpansionPanelSummary
          aria-controls="panel1d-content"
          id="panel1d-header"
        >
          {props.country}
        </ExpansionPanelSummary>
        <ExpansionPanelDetails>{props.children}</ExpansionPanelDetails>
      </ExpansionPanel>
    </div>

then use it here....

              {users &&
                users.map(user => (
                  <Accordion title={user.name} key={user.name}>
                    <div className="overlay-container">
                      <div className="overlay overlay-anim">
                        <div className="overlay-content-container">
                          <div className="name-container">
                            <h1 key={user.id} className="user_name">
                              {user.name}
                            </h1>
                          </div>
                        </div>
                      </div>
                    </div>
                  </Accordion>
                ))}

It opens all the panels by default and doesn't close the others when one is active. (again not real data and the gif makes it a little buggy but I can't generate an example as the code base is too huge).

Would anyone have some ideas or examples of how to achieve this?

EDIT

as per below suggestion have added added an id into the mapping function and adapted the expansion ponent, unfortunately getting the same effect/issues

  const [expanded, setExpanded] = React.useState("panel" + props.id);

  const handleChange = panel => (event, newExpanded) => {
    setExpanded(newExpanded ? panel : false);
  };

  return (
    <div>
      <ExpansionPanel
        expanded={expanded === "panel" + props.i}
        onChange={handleChange("panel" + props.i)}
      >
        <ExpansionPanelSummary
          aria-controls={"panel" + props.id + "d" + "-content"}
          id={"panel" + props.id + "d" + "-header"}
        >
          {props.country}
        </ExpansionPanelSummary>
        <ExpansionPanelDetails>{props.children}</ExpansionPanelDetails>
      </ExpansionPanel>
    </div>
  );
}```
Share Improve this question edited Feb 5, 2020 at 15:35 LAT89 asked Feb 5, 2020 at 11:08 LAT89LAT89 1714 silver badges15 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 3

Hard to say what you are doing with the ExpansionPanel, but it would appear you have same

<ExpansionPanel expanded={expanded === 'panel1'} onChange={handleChange('panel1')}>

for everyone of them, you need to have unique names (panel1, panel2, panel3) for them.

EDIT:

You could add iterator into the map function:

users.map((user, i) => (

and have i passed to the ExpansionPanel as prop for

<ExpansionPanel expanded={expanded === 'panel' + props.i} onChange={handleChange('panel' + props.i)}>

EDIT #2: updated answer with working code and reason why yours didn't work.

Main function, note that u should add the useState here and give them to the CustomizedExpansionPanels child.

example.jsx

import React, { useState } from 'react'
import { withStyles } from '@material-ui/core/styles'
import CustomizedExpansionPanels from './TestTab.jsx'

const styles = (theme) => ({
/* ... your styles... */
})

const users = [
    { name: '5001', color: 'green', type: 'None' },
    { name: '5002', color: 'blue', type: 'Glazed' },
    { name: '5003', color: 'red', type: 'Chocolate' },
    { name: '5004', color: 'orange', type: 'Maple' }
]

function Example(props) {
    const [expanded, setExpanded] = useState('panel_0') // change 0 to the number u want to be open by default
    return (
            <div>
                {users.map((user, i) => CustomizedExpansionPanels(user, i, expanded, setExpanded))}
            <div/>
    )

export default withStyles(styles, { withTheme: true })(Example)

TestTab.jsx

import React from 'react'
import { withStyles } from '@material-ui/core/styles'
import MuiExpansionPanel from '@material-ui/core/ExpansionPanel'
import MuiExpansionPanelSummary from '@material-ui/core/ExpansionPanelSummary'
import MuiExpansionPanelDetails from '@material-ui/core/ExpansionPanelDetails'
import Typography from '@material-ui/core/Typography'

const ExpansionPanel = withStyles({
    root: {
        border: '1px solid rgba(0, 0, 0, .125)',
        boxShadow: 'none',
        '&:not(:last-child)': {
            borderBottom: 0,
        },
        '&:before': {
            display: 'none',
        },
        '&$expanded': {
            margin: 'auto',
        },
    },
    expanded: {},
})(MuiExpansionPanel)

const ExpansionPanelDetails = withStyles((theme) => ({
    root: {
        padding: theme.spacing(2),
    },
}))(MuiExpansionPanelDetails)

const ExpansionPanelSummary = withStyles({
    root: {
        backgroundColor: 'rgba(0, 0, 0, .03)',
        borderBottom: '1px solid rgba(0, 0, 0, .125)',
        marginBottom: -1,
        minHeight: 56,
        '&$expanded': {
            minHeight: 56,
        },
    },
    content: {
        '&$expanded': {
            margin: '12px 0',
        },
    },
    expanded: {},
})(MuiExpansionPanelSummary)

export default function CustomizedExpansionPanels(user, id, expanded, setExpanded) {
    const handleChange = (panel) => (event, newExpanded) => {
        setExpanded(newExpanded ? panel : false)
    }
    const { name, color, type } = user

    return (
        <div>
            <ExpansionPanel square expanded={expanded === `panel_${id}`} onChange={handleChange(`panel_${id}`)}>
                <ExpansionPanelSummary aria-controls={`panel_${id}d-content`} id={`panel_${id}d-header`}>
                    <Typography style={{ color }}>{`Collapsible Group Item #${id}`}</Typography>
                </ExpansionPanelSummary>
                <ExpansionPanelDetails>
                    <Typography>
                        {`name: ${name} type: ${type}`}
                    </Typography>
                </ExpansionPanelDetails>
            </ExpansionPanel>
        </div>
    )
}

Hard to say for sure, but it looks like you are looping the creation of one and same panel where the extended hook exists in each one of them and has the value id of it's own panel => not related to the other panels opening and closing. You need to create each ExpansionPanel with it's own variables and have 1 hook to control them all.

发布评论

评论列表(0)

  1. 暂无评论