ReactJS: Images are sometimes not appearing on button click - javascript

I am a React noob. I am using Material UI and Material UI icons and React to create a title with a forward and back button, so the user can scroll through the pictures on display. When I press the forward button, the picture in "index 2" shows nothing. When I press the back button, the picture in "index 0" is blank (weird, right?). This seems like a super weird bug in my mind. Is there something I am missing here? It is making no sense to me.
Here is my code (as you can see I'm still editing things, so I still have the default text from when I grabbed this from Material UI).
import React from 'react';
import { makeStyles } from '#material-ui/core/styles';
import clsx from 'clsx';
import Card from '#material-ui/core/Card';
import CardHeader from '#material-ui/core/CardHeader';
import CardMedia from '#material-ui/core/CardMedia';
import CardContent from '#material-ui/core/CardContent';
import CardActions from '#material-ui/core/CardActions';
import Collapse from '#material-ui/core/Collapse';
import Avatar from '#material-ui/core/Avatar';
import IconButton from '#material-ui/core/IconButton';
import Typography from '#material-ui/core/Typography';
import { red } from '#material-ui/core/colors';
import FavoriteIcon from '#material-ui/icons/Favorite';
import ShareIcon from '#material-ui/icons/Share';
import ExpandMoreIcon from '#material-ui/icons/ExpandMore';
import MoreVertIcon from '#material-ui/icons/MoreVert';
import ArrowForwardIosIcon from '#material-ui/icons/ArrowForwardIos';
import ArrowBackIosIcon from '#material-ui/icons/ArrowBackIos';
import image2019_0201 from '../images/2019_0201.jpeg';
import image2019_0202 from '../images/2019_0202.jpeg';
import image2019_0203 from '../images/2019_0203.jpeg';
const images = [
image2019_0201,
image2019_0202,
image2019_0203,
];
const imageText = [
"February 15, 2019",
"text2",
"text3"
]
const useStyles = makeStyles((theme) => ({
root: {
maxWidth: 345,
},
media: {
height: 0,
paddingTop: '56.25%', // 16:9
},
expand: {
transform: 'rotate(0deg)',
marginLeft: 'auto',
transition: theme.transitions.create('transform', {
duration: theme.transitions.duration.shortest,
}),
},
expandOpen: {
transform: 'rotate(180deg)',
},
avatar: {
backgroundColor: red[500],
},
}));
export default function Year2019() {
const classes = useStyles();
const [expanded, setExpanded] = React.useState(false);
const [currentImageIndex, setCurrentImageIndex] = React.useState(0)
const handleExpandClick = () => {
setExpanded(!expanded);
};
const handleForwardClick = () => {
console.log("current index", currentImageIndex);
if (currentImageIndex < images.length) {
setCurrentImageIndex(currentImageIndex + 1);
}
else {
setCurrentImageIndex(0);
}
console.log("new index", currentImageIndex);
}
const handleBackClick = () => {
console.log("current index", currentImageIndex);
if (currentImageIndex == 0) {
setCurrentImageIndex(images.length);
}
else {
setCurrentImageIndex(currentImageIndex - 1);
}
console.log("new index", currentImageIndex);
}
return (
<Card className={classes.root}>
<CardHeader
title="Title"
subheader="February 15, 2019"
/>
<CardMedia
className={classes.media}
image={images[currentImageIndex]}
title="image2019_0201"
/>
<CardContent>
<Typography variant="body2" color="textSecondary" component="p">
Waiting for the shuttle.
</Typography>
</CardContent>
<CardActions disableSpacing>
<IconButton aria-label="back" onClick={handleBackClick}>
<ArrowBackIosIcon/>
</IconButton>
<IconButton aria-label="forward" onClick={handleForwardClick}>
<ArrowForwardIosIcon/>
</IconButton>
<IconButton
className={clsx(classes.expand, {
[classes.expandOpen]: expanded,
})}
onClick={handleExpandClick}
aria-expanded={expanded}
aria-label="show more"
>
<ExpandMoreIcon />
</IconButton>
</CardActions>
<Collapse in={expanded} timeout="auto" unmountOnExit>
<CardContent>
<Typography paragraph>Method:</Typography>
<Typography paragraph>
Heat 1/2 cup of the broth in a pot until simmering, add saffron and set aside for 10
minutes.
</Typography>
<Typography paragraph>
Heat oil in a (14- to 16-inch) paella pan or a large, deep skillet over medium-high
heat. Add chicken, shrimp and chorizo, and cook, stirring occasionally until lightly
browned, 6 to 8 minutes. Transfer shrimp to a large plate and set aside, leaving chicken
and chorizo in the pan. Add pimentón, bay leaves, garlic, tomatoes, onion, salt and
pepper, and cook, stirring often until thickened and fragrant, about 10 minutes. Add
saffron broth and remaining 4 1/2 cups chicken broth; bring to a boil.
</Typography>
<Typography paragraph>
Add rice and stir very gently to distribute. Top with artichokes and peppers, and cook
without stirring, until most of the liquid is absorbed, 15 to 18 minutes. Reduce heat to
medium-low, add reserved shrimp and mussels, tucking them down into the rice, and cook
again without stirring, until mussels have opened and rice is just tender, 5 to 7
minutes more. (Discard any mussels that don’t open.)
</Typography>
<Typography>
Set aside off of the heat to let rest for 10 minutes, and then serve.
</Typography>
</CardContent>
</Collapse>
</Card>
);
}
Picture of the Forward and Backward Icons

In your handler functions, the array index may go out of bound. So you should modify your handler functions like below:
const handleForwardClick = () => {
if (currentImageIndex < (images.length - 1)) {
setCurrentImageIndex(currentImageIndex + 1);
}
else {
setCurrentImageIndex(0);
}
}
const handleBackClick = () => {
if (currentImageIndex == 0) {
setCurrentImageIndex(images.length - 1);
}
else {
setCurrentImageIndex(currentImageIndex - 1);
}
}

Related

Warning: Each child in a list should have a unique "key" prop. how to fix this?

Ive been using this project with out a problem and now all of a sudden I keep getting this error and it won't show my notes when I click on the my notes section. What do I have to do for it to go away. The backend is up and running and I can see the static data but it wont show on the app
import { makeStyles } from '#mui/styles'
import React from 'react'
import { Drawer } from '#mui/material'
import { Typography } from '#mui/material'
import List from '#mui/material/List'
import ListItem from '#mui/material/ListItem'
import ListItemIcon from '#mui/material/ListItemIcon'
import ListItemText from '#mui/material/ListItemText'
import { AddCircleOutlineOutlined, SubjectOutlined } from '#mui/icons-material'
import { useHistory, useLocation } from 'react-router-dom'
import AppBar from '#mui/material/AppBar'
import Toolbar from '#mui/material/Toolbar'
import { format } from 'date-fns'
import { red } from '#mui/material/colors'
const drawerWidth = 240 // 500 - subtract this number from
const useStyles = makeStyles((theme) => {
return{
page: {
background: '#E5E4E2',
width: '100%',
padding: theme.spacing(3)
},
drawer: {
width: drawerWidth
},
drawerPaper: {
width: drawerWidth
},
root: {
display: 'flex' //places the drawer side by side with the page content
},
active: {
background: '#E5E4E2'
},
// title:{
// padding: theme.spacing(13),
// alignItems: 'center'
// },
}})
export default function Layout({ children }) {
const classes = useStyles()
const history = useHistory()
const location = useLocation()
const menuItems = [
{
text: 'My Projects',
icon: <SubjectOutlined color="secondary" />,
path: '/'
},
{
text: 'Create Project',
icon: <AddCircleOutlineOutlined color="secondary" />,
path: '/create'
}
]
return (
<div className={classes.root}>
{/* side drawer */}
<Drawer
className={classes.drawer}
variant='permanent' //Lets MUI know we want it on the page permanently
anchor="left" // position of drawer
classes={{ paper: classes.drawerPaper}}
>
<div>
<Typography variant="h5" sx={{textAlign: 'center'}}>
Projects
</Typography>
</div>
{/* List / Links */}
<List>
{menuItems.map(item => (
<div className={location.pathname == item.path ? classes.active : null}>
<ListItem key={item.text} button onClick={() => history.push(item.path)}>
<ListItemIcon>{item.icon}</ListItemIcon>
<ListItemText primary={item.text} />
</ListItem>
</div>
))}
</List>
</Drawer>
<div className={classes.page}>
<div className={classes.toolbar}></div>
{children}
</div>
</div>
)
}
enter image description here
Updated
I'm sorry, of course, you should just move key to the parent div. I didn't notice it. Chris who answered in the comments is right and my answer was not needed. I rewrote the answer.
To have an unique key use index in map or like you did item.text if text is unique for each element in map.
menuItems.map((item,index) =>
The idea is that map has to contain unique key for each element.
In result we have:
<div key={item.text} className={location.pathname == item.path ? classes.active : null}>
or
<div key={index} className={location.pathname == item.path ? classes.active : null}>
And you need to remove key from the List.
Hope this helps! Regards,

React Manage Multiple Audios on Same Page and play one at a time using function based components

I am making a new react app which have multiple music cards on same page. I want to change the state of previous card before updating the state of new card. In short I want to pause previous audio before playing new one.
import React, { useState , useEffect , useRef} from "react";
import Card from '#mui/material/Card';
import CardContent from '#mui/material/CardContent';
import CardMedia from '#mui/material/CardMedia';
import Typography from '#mui/material/Typography';
import { CardActionArea } from '#mui/material';
import PlayArrowIcon from '#mui/icons-material/PlayArrow';
import IconButton from '#mui/material/IconButton';
import PauseICon from "#mui/icons-material/Pause";
import { logDOM } from "#testing-library/react";
export default function ActionAreaCard(props) {
const audioRef = useRef(new Audio("http://myinstants.org/games/22ecaa5e-f90f-4e81-96b1-b240751439fa.mp3"));
const [clicked, setClicked] = useState(false);
useEffect(() => {
audioRef.current.addEventListener('ended', () => setClicked(false));
if (clicked) {
audioRef.current.play();
} else {
audioRef.current.pause();
}
},[clicked]);
return (
<Card sx={{ maxWidth: 256 }} >
<CardMedia
component="img"
height="140"
image="https://picsum.photos/400/200"
alt="green iguana"
/>
<CardContent style={{ display: 'flex', flexDirection: 'column' }}>
<Typography gutterBottom variant="h5" component="div" style={{ textAlign: 'center', overflow: 'hidden', whiteSpace: 'nowrap', textOverflow: 'ellipsis' }}>
lorem Spem kjb j kl lk n lkn lk nlk n kln lkn kln kln kl nlk n vdr rtgvrt rtwbtr rtbvrt vbwrt vwretvw
</Typography>
{/* <PlayArrowIcon sx={{ height: 38, width: 38}}/> */}
<IconButton onClick={() => setClicked(!clicked)}>
{
clicked ? <PauseICon sx={{ height: 38, width: 38 }} /> : <PlayArrowIcon sx={{ height: 38, width: 38 }} />
}
</IconButton>
</CardContent>
</Card>
);
}
The above one is my playing card component.
The above GIF is the working app. In which when I play the second Audio it starts it before stopping the old when. MY background is from android development in which we have only one object of media player and we can manage this using that object. But here i found no solution may be we can do it by accessing the other component state in an other component or may be using a hook etc.
Make a common state in parent storing active playing:
const [activePlaying,setActivePlaying]=useState(null);
Make a handler for it:
const activePlayerhandler=useCallback((id)=>{
setActivePlaying(id);
},[id]);
Pass this handler as a prop:
...
{players.map((player,index)=>(
< ActionAreaCard onPlay={()=>activePlayerhandler(index)} playing={activePlaying===index}/>
))
...
now you just need to call this prop on play button click.

How to know from which DOM click event is triggered

I have few Card component from material UI, each of them contain an EDIT button and there is a handler available for it, they are being added dynamically using Map traversing (In example, i have just hard coded two of them).
Now, i am trying to make the card editable in button click but not able to find out how to get to know from which Card, event is triggered and then make "Typography" of that editable to 'TextField'.
<CardContent>
<Typography>ID: '1'</Typography>
<Typography
className={classes.title}
color="textSecondary"
gutterBottom
>
Word of the Day
</Typography>
<Typography>Name: 'RAAM'</Typography>
<Typography>Blood group: 'AB+'</Typography>
<Typography>"Patient Ram is having bloodgroup AB+"</Typography>
</CardContent>
<CardActions>
<Button size="small" onClick={click}>
Edit
</Button>
</CardActions>
<CardContent>
Here is my codeSandbox example
CodeSandbox
The usual solution is to have the card pass back some identifying information or an object that you've passed it, since there's very little you can do with the React element.
If you want the DOM element, it's the currentTarget property of the event object that your click function receives.
Here's a simple example showing both with stand-ins for Card and its parent, in this case the Card component returns the id you pass it as a second argument to the click function:
"use strict";
const cards = Array.from(Array(5), (_, index) => ({
id: index + 1,
value: `Card ${index + 1}`
}));
function Parent() {
const click = (evt, id) => {
console.log(`evt.currentTarget.tagName = ${evt.currentTarget.tagName}, id = ${id}`);
};
return cards.map(({id, value}) =>
<Card
key={id}
value={value}
onClick={evt => click(evt, id)}
/>
);
}
function Card({value, onClick}) {
return <div onClick={onClick}>{value}</div>;
}
ReactDOM.render(<Parent />, document.getElementById("root"));
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.0/umd/react-dom.production.min.js"></script>
import React, { useRef } from "react";
import { makeStyles } from "#material-ui/core/styles";
import Card from "#material-ui/core/Card";
import CardActions from "#material-ui/core/CardActions";
import CardContent from "#material-ui/core/CardContent";
import Button from "#material-ui/core/Button";
import Typography from "#material-ui/core/Typography";
const useStyles = makeStyles({
root: {
minWidth: 275
},
bullet: {
display: "inline-block",
margin: "0 2px",
transform: "scale(0.8)"
},
title: {
fontSize: 14
},
pos: {
marginBottom: 12
}
});
export default function OutlinedCard() {
const refs = useRef([]);
const classes = useStyles();
const click = (event) => {
const { currentTarget: { id = "" } = {} } = event;
const clickedCard = refs.current[id]; // This is the card whose button got clicked
console.log(clickedCard);
};
const createRefs = (id, node) => (refs.current[id] = node);
return (
<Card className={classes.root} variant="outlined">
<CardContent ref={(node) => {createRefs('card_1', node)}}>
<Typography>ID: '1'</Typography>
<Typography
className={classes.title}
color="textSecondary"
gutterBottom
>
Word of the Day
</Typography>
<Typography>Name: 'RAAM'</Typography>
<Typography>Blood group: 'AB+'</Typography>
<Typography>"Patient Ram is having bloodgroup AB+"</Typography>
</CardContent>
<CardActions>
<Button size="small" id="card_1" onClick={click}>
Edit
</Button>
</CardActions>
<CardContent ref={(node) => {createRefs('card_2', node)}}>
<Typography>ID: '2'</Typography>
<Typography
className={classes.title}
color="textSecondary"
gutterBottom
>
Word of the Day
</Typography>
<Typography>Name: 'RAAM'</Typography>
<Typography>Blood group: 'AB+'</Typography>
<Typography>"Patient Ram is having bloodgroup AB+"</Typography>
</CardContent>
<CardActions>
<Button size="small" id="card_2" onClick={click}>
Edit
</Button>
</CardActions>
</Card>
);
}

How do I center TabPanel in React material UI?

I am trying to create a list of articles with switching to a list of other entities in React + material UI. But I faced some problems, namely, I can't center Card, which displays an article in the way, that will correspond to centered Tabs. So, I get something like this:
Can anyone help me to make it to look symmetric?
I want the Card to be centered in the same way, the Tabs are.
TabsMenu.js, which itself is displayed:
import React from "react";
import {makeStyles} from "#material-ui/core/styles";
import Paper from "#material-ui/core/Paper";
import Tabs from "#material-ui/core/Tabs";
import Tab from "#material-ui/core/Tab";
import Box from "#material-ui/core/Box";
import Typography from "#material-ui/core/Typography";
import * as PropTypes from "prop-types";
import ArticlesList from "./ArticlesList";
function TabPanel(props) {
const {children, value, index, ...other} = props;
return (
<div
role="tabpanel"
hidden={value !== index}
id={`simple-tab-${index}`}
aria-labelledby={`simple-tab-${index}`}
{...other}
>
{value === index && (
<Box p={3}>
<Typography>{children}</Typography>
</Box>
)}
</div>
);
}
TabPanel.propTypes = {
children: PropTypes.node,
index: PropTypes.any.isRequired,
value: PropTypes.any.isRequired,
};
const useStyles = makeStyles({
root: {
flexGrow: 1,
},
tabpanel: {
marginLeft: "auto"
}
});
function a11yProps(index) {
return {
id: `simple-tab-${index}`,
'aria-controls': `simple-tabpanel-${index}`,
};
}
export default function CenteredTabs(props) {
const classes = useStyles();
const [value, setValue] = React.useState(0);
const handleChange = (event, newValue) => {
setValue(newValue);
}
return (
<Paper className={classes.root}>
<article>
<Tabs
value={value}
onChange={handleChange}
indicatorColor="primary"
textColor="primary"
centered
>
<Tab label="Articles" {...a11yProps(0)}/>
<Tab label="News" {...a11yProps(1)}/>
<Tab label="Authors" {...a11yProps(2)}/>
</Tabs>
<TabPanel value={value} index={0} className={classes.tabpanel}>
<ArticlesList articles={[{
imageSrc: "https://frontendmasters.com/static-assets/learn/og-learning-path-react.jpg",
authorImageSrc: "https://lh5.googleusercontent.com/--OlyHl449xI/AAAAAAAAAAI/AAAAAAAAAAA/ACevoQNk7ZZElQ_vKIQT_6d4HZw_wN3Qxg/mo/photo.jpg?sz=64",
authorName: "Denis Ivanenko",
dateTime: "2017-02-14",
imageAlt: "Article Image",
title: "Test title",
subtitle: "Test subtitle"
}]}/>
</TabPanel>
<TabPanel value={value} index={1} className={classes.tabpanel}>
Item Two
</TabPanel>
<TabPanel value={value} index={2} className={classes.tabpanel}>
Item Three
</TabPanel>
</article>
</Paper>
);
}
ArticlesList.js, which is used in TabsMenu.js
import React from 'react';
import {makeStyles} from '#material-ui/core/styles';
import List from '#material-ui/core/List';
import ArticleCard from "./ArticleCard";
import Box from "#material-ui/core/Box";
import Grid from '#material-ui/core/Grid';
const useStyles = makeStyles((theme) => ({
root: {
width: '100%',
maxWidth: 360,
backgroundColor: theme.palette.background.paper,
},
}));
export default function ArticlesList(props) {
const classes = useStyles();
return (
<React.Fragment>
<div className={classes.root}>
<Grid container
spacing={0}
direction="column"
alignItems="center"
justify="center"
style={{minHeight: '100vh'}}>
<Grid item xs={12}>
<Box width={"150%"}>
<List component="nav" aria-label="secondary mailbox folders">
<ArticleCard title={"Introducing \"Dead Simple Python\"\n"}
text={"Ever spent three hours trying to find that bit of knowledge that everyone seemed to have but you?\n" +
"\n" +
"As a self-trained Python developer, I've sometimes found myself stuck in that knowledge crater, between tutorials far simpler than real life, and articles more advanced than I could comprehend. Even the documentation felt like a firehose of information, making it nearly impossible to find the one basic thing I needed to know.\n" +
"\n" +
"In this series, I'll be exploring a few of these topics, in a way that hopefully makes them dead simple!\n" +
"\n" +
"Intended Audience\n" +
"While programmers at all experience levels may find this series useful, I'm specifically targeting Python novices. I am assuming, however, that you have a very basic understanding of programming. The coding topics especially will be more focused on the Python way of doing things, not on the underlying generic concept.\n" +
"\n" +
"With that said, if you're an intermediate-level Python developer, you may still find it helpful to follow along with the series. Although I've been working with Python for nearly eight years, some of these topics didn't really \"click\" for me until recent years. These are the explanations I wish I'd had!\n" +
"\n" +
"What You Won't Find Here\n" +
"All of the topics I'm discussing here go much, much deeper. However, I don't want to muddy the waters, so I'll be omitting a considerable amount of detail. Once you're comfortable with a topic, and have done it a few times yourself, I recommend going back and reading through the official Python documentation on the topic.\n" +
"\n" +
"A Note on Python Versions\n" +
"The official end-of-life for Python 2 is rapidly approaching, so you should learn and begin using Python 3 as soon as possible! This entire series is geared towards Python 3, with a bias towards 3.6 and 3.7, except as otherwise noted.\n" +
"\n" +
"Edits\n" +
"The articles in this series are frequently being reviewed by my fellow Python experts, and by the Dev community at large. I will expand and revise accordingly. Always check the edit timestamp at the top of the article.\n" +
"\n" +
"Roadmap\n" +
"The current series plan is below. Please note, I may rearrange, add, or remove planned sections."}
imageSrc={"https://insights.dice.com/wp-content/uploads/2017/09/shutterstock_315465929.jpg"}
authorImageSrc={"https://lh5.googleusercontent.com/--OlyHl449xI/AAAAAAAAAAI/AAAAAAAAAAA/ACevoQNk7ZZElQ_vKIQT_6d4HZw_wN3Qxg/mo/photo.jpg?sz=64"}
authorName={"Denis Ivanenko"}/>
</List>
</Box>
</Grid>
</Grid>
</div>
</React.Fragment>
);
}
ArticleCard.js
import React from "react";
import {red} from '#material-ui/core/colors';
import makeStyles from "#material-ui/core/styles/makeStyles";
import Card from "#material-ui/core/Card";
import CardHeader from "#material-ui/core/CardHeader";
import Avatar from "#material-ui/core/Avatar";
import IconButton from "#material-ui/core/IconButton";
import CardMedia from "#material-ui/core/CardMedia";
import CardContent from "#material-ui/core/CardContent";
import Typography from "#material-ui/core/Typography";
import CardActions from "#material-ui/core/CardActions";
import clsx from "clsx";
import FavoriteIcon from '#material-ui/icons/Favorite';
import ShareIcon from '#material-ui/icons/Share';
import Button from "#material-ui/core/Button";
const useStyles = makeStyles((theme) => ({
root: {
width:"155%",
gridColumn: "2/span 7"
},
media: {
height: 0,
paddingTop: '56.25%',
},
expand: {
transform: 'rotate(0deg)',
marginLeft: 'auto',
transition: theme.transitions.create('transform', {
duration: theme.transitions.duration.shortest,
}),
},
avatar: {
backgroundColor: red[500],
},
}));
export default function ArticleCard(props) {
const classes = useStyles();
const [expanded] = React.useState(false);
const title = props.title;
const date = props.dateTime;
const imageSrc = props.imageSrc;
const imageAlt = props.imageAlt;
const previewText = props.text.substring(0,158)+"...";
return (
<Card className={classes.root}>
<CardHeader
avatar={
<Avatar aria-label="recipe" className={classes.avatar}>
<img src={props.authorImageSrc} alt={props.authorName}/>
</Avatar>
}
title={title}
subheader={date}
/>
<CardMedia
className={classes.media}
image={imageSrc}
title={imageAlt}
/>
<CardContent>
<Typography variant="body2" color="textSecondary" component="p">
{previewText}
</Typography>
</CardContent>
<CardActions disableSpacing>
<IconButton aria-label="add to favorites">
<FavoriteIcon/>
</IconButton>
<IconButton aria-label="share">
<ShareIcon/>
</IconButton>
<Button
className={clsx(classes.expand, {
[classes.expandOpen]: expanded,
})}
aria-expanded={expanded}
aria-label="show more"
href={"/article"}
>
Read More
</Button>
</CardActions>
</Card>
);
}
This has got nothing to do with material-ui,
you've applied marginLeft: auto, which will not apply marginRight: auto, so it would not be center aligned
you should add marginRight: auto, as well to center it.
const useStyles = makeStyles({
root: {
flexGrow: 1,
},
tabpanel: {
marginLeft: "auto",
marginRight: "auto"
}
});

How to add styles to an unknown child in React with Material-UI?

The below function is going to be run on a loop. I want to add styles to the icon which I want to pass as an argument to the function.
The icon is a going to be an unknown React Material-UI Icon component.
const renderStyledCard = (lightMode, heading, num, icon) => {
const classes = lightMode ? useLightCardStyles(): useDarkCardStyles();
return (
<Card className={classes.root}>
<CardContent>
<Typography variant="h4" component="h4" className={classes.textColor}>
{heading}
</Typography>
<div className={classes.content}>
<Typography variant="h4" component="h4" className={classes.textColor}>
{num}
</Typography>
{icon}
// Ex. <VpnKey className={[classes.icon, classes.textColor]} />
// Ex. <AccountCircle className={[classes.icon, classes.textColor]} />
{icon}
</div>
</CardContent>
</Card>
);
};
Loop execution is going to be like -
return [
{light: true,
heading: 'Accounts',
num: 100,
icon: <AccountCircle />
},
...theRest
].map(ele => renderStyledCard(...ele))
The loop code could be wrong I just wrote it here as an example to show how I wanted to execute it. Is there a better way? Any help would be awesome.
Some notice points:
add {} like ({ light, heading, num, icon }) to list the props
props lightMode not match list attribute light, need to change one of them
use Material-UI nesting selector & svg to customize the icon style from its parent div
Full code sample:
import React from "react";
import "./styles.css";
import GetApp from "#material-ui/icons/GetApp";
import AccountCircle from "#material-ui/icons/AccountCircle";
import { Card, CardContent, Typography, makeStyles } from "#material-ui/core";
const useLightCardStyles = makeStyles(theme => ({
root: {},
content: {
"& svg": {
color: "red"
}
}
}));
const useDarkCardStyles = makeStyles(theme => ({}));
const data = [
{ light: true, heading: "Accounts", num: 100, icon: <AccountCircle /> },
{ light: true, heading: "Accounts", num: 100, icon: <GetApp /> }
];
const StyledCard = ({ light, heading, num, icon }) => {
const lightCardClasses = useLightCardStyles();
const darkCardClasses = useDarkCardStyles();
const classes = light ? lightCardClasses : darkCardClasses;
return (
<Card className={classes.root}>
<CardContent>
<Typography variant="h4" component="h4" className={classes.textColor}>
{heading}
</Typography>
<div className={classes.content}>
<Typography variant="h4" component="h4" className={classes.textColor}>
{num}
</Typography>
{icon}
</div>
</CardContent>
</Card>
);
};
export default function App() {
return (
<div className="App">
{data.map(props => (
<StyledCard {...props} />
))}
</div>
);
}
I think this should work:
const renderStyledCard = (lightMode, heading, num, icon) => {
const classes = lightMode ? useLightCardStyles(): useDarkCardStyles();
icon.style.color = "red";
return(/*....*/)
}
Try console.log(icon.style)

Categories

Resources