Can I use react router Link with CardActionArea? - reactjs

Can I use react router Link with CardActionArea?
Here is my code where my css is broken because How can I use Link component
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
<Link to="/Blog">
<CardActionArea component="div" disableRipple>
<CardMedia
className={classes.media}
image="images/marmik.jpg"
title="Marmik Desai"
/>
<CardContent>
<Typography gutterBottom variant="h5" component="h2">
Marmik Desai
</Typography>
<Typography variant="body2" color="textSecondary" component="p">
I am front end developer.
</Typography>
</CardContent>
</CardActionArea>
</Link>
If i use below href="" in cardactionarea it will refresh page. I don't want to refresh page.
<CardActionArea href="/Blog" disableRipple>
FOUND SOLUTION
If I use Link as CardActionArea I need to overwrite Link css. I have found below solution.
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
<CardActionArea component={Link} to="/Blog">

import { Link as RouterLink } from 'react-router-dom';
import { CardActionArea } from '#material-ui/core';
<CardActionArea component={RouterLink} to={'/Blog'}>
// ...
</CardActionArea >

You can using like this, put you CardActionArea component in Link
return (
<Card className={classes.root}>
<Link to="/Blog" component={CardActionArea}>
<CardMedia
className={classes.media}
image={props.thumbnail}
title={props.thumbnail}
/>
<CardContent>
<Typography gutterBottom variant="h6" component="h6">
{props.title}
</Typography>
<Typography variant='caption' component={"sm"}>
Update at {(Date(props.date).substring(0, 16))}
on {props.category}
</Typography>
<Divider />
<Typography variant="body2" component="p">
{props.subtitle}
</Typography>
</CardContent>
</Link>
<CardActions>
{!props.isAdmin && <Link to={props.admin_url} component={Button} size="small" >Edit</Link>}
<Link to={props.public_url} component={Button} size="small" >Readmore</Link>
</CardActions>
</Card>
);

From the documentation CardActionArea takes two props classes and children, add the link as a child.
<CardActionArea component="div" disableRipple>
<Link to="/Blog">
<CardMedia
className={classes.media}
image="images/marmik.jpg"
title="Marmik Desai"
/>
<CardContent>
<Typography gutterBottom variant="h5" component="h2">
Marmik Desai
</Typography>
<Typography variant="body2" color="textSecondary" component="p">
I am front end developer.
</Typography>
</CardContent>
</Link>
</CardActionArea>

In CardActionArea set component prop to Link and to to your desired URL. This way you can use browser's back and forward button to navigate in your React application.
For example:
import { Link } from "react-router-dom";
import {
Card,
CardActionArea,
CardContent,
Typography,
} from "#mui/material";
<Card>
<CardActionArea
component={Link}
to="YOUR-URL"
>
<CardContent>
<Typography variant="h5">
Card Title
</Typography>
<Typography variant="body2" color="text.secondary">
Card Description
</Typography>
</CardContent>
</CardActionArea>
</Card>

This is my solution to keep the same Button style.
import { Link, LinkProps } from 'react-router-dom'
import Button from '#material-ui/core/Button'
const CardButton: React.FC<LinkProps> = ({ children, ...linkProps }) => (
<Link style={{ textDecoration: 'none' }} {...linkProps}>
<Button size="small" color="primary">
{children}
</Button>
</Link>
)

Related

Uncaught TypeError: Cannot read properties of undefined (reading 'source') react v16

I'm trying to access data from commerceJS API fetched on a different module and passed down as a prop, the code only breaks when I call a nested product object with this error Uncaught TypeError: Cannot read properties of undefined (reading 'source').
Here is my code
//Product.jsx
import React from 'react';
import { Card, CardMedia, CardContent, CardActions, Typography, IconButton } from '#material-ui/core';
import { AddShoppingCart } from '#material-ui/icons';
import useStyles from './styles';
const Product = ({ product, onAddToCart }) => {
const classes = useStyles();
const handleAddToCart = () => onAddToCart(product.id, 1);
return (
<Card className={classes.root}>
<CardMedia
className={classes.media}
image={product.media.source}
component="img"
title={product.name}
/>
<CardContent>
<div className={classes.cardContent}>
<Typography gutterBottom variant="h5" component="h2">
{product.name}
</Typography>
<Typography gutterBottom variant="h5" component="h2">
${product.price.formatted}
</Typography>
</div>
<Typography
dangerouslySetInnerHTML={{ __html: product.description }}
variant="body2"
color="textSecondary"
component="p"
/>
</CardContent>
<CardActions disableSpacing className={classes.cardActions}>
<IconButton aria-label="Add to Cart" onClick={handleAddToCart}>
<AddShoppingCart />
</IconButton>
</CardActions>
</Card>
);
};
export default Product;
import React from 'react';
import { Card, CardMedia, CardContent, CardActions, Typography, IconButton } from '#material-ui/core';
import { AddShoppingCart } from '#material-ui/icons';
import useStyles from './styles';
const Product = ({ product, onAddToCart }) => {
const classes = useStyles();
const handleAddToCart = () => onAddToCart(product.id, 1);
return (
<Card className={classes.root}>
<CardMedia
className={classes.media}
image={product.media.source}
component="img"
title={product.name}
/>
<CardContent>
<div className={classes.cardContent}>
<Typography gutterBottom variant="h5" component="h2">
{product?.name}
</Typography>
<Typography gutterBottom variant="h5" component="h2">
${product?.price?.formatted}
</Typography>
</div>
<Typography
dangerouslySetInnerHTML={{ __html: product.description }}
variant="body2"
color="textSecondary"
component="p"
/>
</CardContent>
<CardActions disableSpacing className={classes.cardActions}>
<IconButton aria-label="Add to Cart" onClick={handleAddToCart}>
<AddShoppingCart />
</IconButton>
</CardActions>
</Card>
);
};
export default Product;
try this code:
import React from 'react';
import { Card, CardMedia, CardContent, CardActions, Typography, IconButton } from '#material-ui/core';
import { AddShoppingCart } from '#material-ui/icons';
import useStyles from './styles';
const Product = ({ product, onAddToCart }) => {
const classes = useStyles();
const handleAddToCart = () => onAddToCart(product.id, 1);
return (
<Card className={classes.root}>
<CardMedia
className={classes.media}
image={product?.media?.source}
component="img"
title={product?.name}
/>
<CardContent>
<div className={classes.cardContent}>
<Typography gutterBottom variant="h5" component="h2">
{product?.name}
</Typography>
<Typography gutterBottom variant="h5" component="h2">
${product?.price?.formatted}
</Typography>
</div>
<Typography
dangerouslySetInnerHTML={{ __html: product?.description }}
variant="body2"
color="textSecondary"
component="p"
/>
</CardContent>
<CardActions disableSpacing className={classes.cardActions}>
<IconButton aria-label="Add to Cart" onClick={handleAddToCart}>
<AddShoppingCart />
</IconButton>
</CardActions>
</Card>
);
};
export default Product;
It'll display the image if I delete the className property and access to my object key
Code here:
<CardMedia
className={classes.media}
image={product.image.url}
component="img"
title={product?.name}
/>

With this code I get this error "onAddToCart is not a function" How can I fix it?

import React from "react";
import { CardMedia, Card, CardContent, CardActions, Typography, IconButton } from "#mui/material";
import { AddShoppingCart } from "#mui/icons-material";
import useStyles from "./styles"
const Product = ({ product, onAddToCart }) =>{
const classes = useStyles();
return(
<Card className={classes.root}>
<CardMedia className={classes.media} image={product.image.url} title={product.name}/>
<CardContent>
<div className={classes.cardContent}>
<Typography variant="h5" gutterBottom >
{product.name}
</Typography>
<Typography variant="h5" >
{product.price.formatted_with_symbol}
</Typography>
</div>
<Typography dangerouslySetInnerHTML= {{ __html: product.description }} variant="body2" color="textSecondary"/>
</CardContent>
<CardActions disableSpacing className={classes.cardActions}>
<IconButton aria-label="Add to card" onClick={() => onAddToCart(product.id, 1)}>
<AddShoppingCart />
</IconButton>
</CardActions>
</Card>
)
}
export default Product;
You need to look at how the prop onAddToCart is transferred to the component Product
Search something like: <Product ... />

How can I fix this problem while mapping in a card?

import * as React from 'react';
import Card from '#mui/material/Card';
import CardActions from '#mui/material/CardActions';
import CardContent from '#mui/material/CardContent';
import CardMedia from '#mui/material/CardMedia';
import Button from '#mui/material/Button';
import Typography from '#mui/material/Typography';
export default function MediaCard() {
return (
<Card sx={{ maxWidth: 345 }}>
{data.map((item) =>(
<CardMedia component="img" height="140" image={`${data.img}`} alt="home image looding......"/>
<CardContent>
<Typography gutterBottom variant="h5" component="div">{data.name}</Typography>
<Typography variant="body2" color="text.secondary">{data.description}</Typography>
</CardContent>
))}
<CardActions>
<Button size="small">Share</Button>
<Button size="small">Learn More</Button>
</CardActions>
</Card>
);
}
let data =[
{
name:'Property for sale',
img: '/home1.jpg',
description: 'This House is 5.5 cent with square feet area of 2000 and 3 km from palakkad city ;100 meters from main road.',
},
{
name:'Property for Rent',
img: '/home2.jpg',
title: 'Burger',
},
{
name:'Property for sale',
img: '/home3.jpg',
title: 'Camera',
},
{
name:'Property for Rent',
img: '/home4.jpg',
title: 'Coffee',
},
{
name:'Property for sale',
img: '/home5.jpg',
title: 'Hats',
},
{
name:'Property for Rent',
img: '/home7.jpg',
title: 'Honey',
},
];
I can't get the details of mapped items in the card. While doing this I had found an error
"ERROR in src\Components\Card\Card.js
Line 17:6: Parsing error: Adjacent JSX elements must be wrapped in an enclosing tag. Did you want a JSX fragment <>...</>? (17:6)."
I had used material UI and I don't understand whether the mistake had happened.
It should be wrapped in a parent element. e.g
export default function MediaCard() {
return (
<div>
<Card sx={{ maxWidth: 345 }}>
{data.map((item) =>(
<CardMedia component="img" height="140" image={`${data.img}`} alt="home image looding......"/>
<CardContent>
<Typography gutterBottom variant="h5" component="div">{data.name}</Typography>
<Typography variant="body2" color="text.secondary">{data.description}</Typography>
</CardContent>
))}
<CardActions>
<Button size="small">Share</Button>
<Button size="small">Learn More</Button>
</CardActions>
</Card>
</div>
);
}
Change this
{data.map((item) =>(
<CardMedia component="img" height="140" image={`${data.img}`} alt="home image looding......"/>
<CardContent>
<Typography gutterBottom variant="h5" component="div">{data.name}</Typography>
<Typography variant="body2" color="text.secondary">{data.description}</Typography>
</CardContent>
))}
to this
{data.map((item) =>(
<>
<CardMedia component="img" height="140" image={`${data.img}`} alt="home image looding......"/>
<CardContent>
<Typography gutterBottom variant="h5" component="div">{data.name}</Typography>
<Typography variant="body2" color="text.secondary">{data.description}</Typography>
</CardContent>
</>
))}
You should have wrapped the inner element of the map in an empty Tag and also wrap the whole component in an <> </> this empty tag

How to implement a style where the picture inside the Card Media will somehow pop out or like it will hover above?

This is the sample code of the Card from material-ui. How can I make the picture inside the card media to somehow pop out a bit when the mouse hovers on it? Or like a zoom once the mouse hovers on that picture
import { makeStyles } from '#material-ui/core/styles';
import Card from '#material-ui/core/Card';
import CardActionArea from '#material-ui/core/CardActionArea';
import CardActions from '#material-ui/core/CardActions';
import CardContent from '#material-ui/core/CardContent';
import CardMedia from '#material-ui/core/CardMedia';
import Button from '#material-ui/core/Button';
import Typography from '#material-ui/core/Typography';
const useStyles = makeStyles({
root: {
maxWidth: 345,
},
media: {
height: 140,
},
});
export default function MediaCard() {
const classes = useStyles();
return (
<Card className={classes.root}>
<CardActionArea>
<CardMedia
className={classes.media}
image="/static/images/cards/contemplative-reptile.jpg"
title="Contemplative Reptile"
/>
<CardContent>
<Typography gutterBottom variant="h5" component="h2">
Lizard
</Typography>
<Typography variant="body2" color="textSecondary" component="p">
Lizards are a widespread group of squamate reptiles, with over 6,000 species, ranging
across all continents except Antarctica
</Typography>
</CardContent>
</CardActionArea>
<CardActions>
<Button size="small" color="primary">
Share
</Button>
<Button size="small" color="primary">
Learn More
</Button>
</CardActions>
</Card>
);
}
You can use the 'hover' mediaquery. Here you can find an example that I made base on your code SandBox
import { makeStyles } from "#material-ui/core/styles";
import Card from "#material-ui/core/Card";
import CardActionArea from "#material-ui/core/CardActionArea";
import CardActions from "#material-ui/core/CardActions";
import CardContent from "#material-ui/core/CardContent";
import CardMedia from "#material-ui/core/CardMedia";
import Button from "#material-ui/core/Button";
import Typography from "#material-ui/core/Typography";
const useStyles = makeStyles({
root: {
maxWidth: 345
},
media: {
height: 140,
"&:hover": {
transform: "scale(1.5)"
}
}
});
export default function App() {
const classes = useStyles();
return (
<Card className={classes.root}>
<CardActionArea>
<CardMedia
className={classes.media}
image="assets/image.png"
title="Contemplative Reptile"
/>
<CardContent>
<Typography gutterBottom variant="h5" component="h2">
Lizard
</Typography>
<Typography variant="body2" color="textSecondary" component="p">
Lizards are a widespread group of squamate reptiles, with over 6,000
species, ranging across all continents except Antarctica
</Typography>
</CardContent>
</CardActionArea>
<CardActions>
<Button size="small" color="primary">
Share
</Button>
<Button size="small" color="primary">
Learn More
</Button>
</CardActions>
</Card>
);
}

How to put different content for each cards

I am using material ui album template for my react app
I want to put different image and different text for each cards for this when I remove this array it create the problems in responsiveness of the cards
I tried to put separte grid for each cards but thats some how solve the issue but that responsiveness of the template does not remain same
here is my demo code
https://codesandbox.io/s/material-demo-pz8df
Make sure you're updating the right cards array. Use an array of objects as well, where each object has a key for an image-link and one for the description. In the .map() we'll use these values to render the content. Here's a working sandbox: https://codesandbox.io/s/material-demo-3v44c
The responsiveness will work like expected.
Working code:
import React from "react";
import AppBar from "#material-ui/core/AppBar";
import Button from "#material-ui/core/Button";
import CameraIcon from "#material-ui/icons/PhotoCamera";
import Card from "#material-ui/core/Card";
import CardActions from "#material-ui/core/CardActions";
import CardContent from "#material-ui/core/CardContent";
import CardMedia from "#material-ui/core/CardMedia";
import CssBaseline from "#material-ui/core/CssBaseline";
import Grid from "#material-ui/core/Grid";
import Toolbar from "#material-ui/core/Toolbar";
import Typography from "#material-ui/core/Typography";
import { makeStyles } from "#material-ui/core/styles";
import Container from "#material-ui/core/Container";
import Link from "#material-ui/core/Link";
function MadeWithLove() {
return (
<Typography variant="body2" color="textSecondary" align="center">
{"Built with love by the "}
<Link color="inherit" href="https://material-ui.com/">
Material-UI
</Link>
{" team."}
</Typography>
);
}
const useStyles = makeStyles(theme => ({
icon: {
marginRight: theme.spacing(2)
},
heroContent: {
backgroundColor: theme.palette.background.paper,
padding: theme.spacing(8, 0, 6)
},
heroButtons: {
marginTop: theme.spacing(4)
},
cardGrid: {
paddingTop: theme.spacing(8),
paddingBottom: theme.spacing(8)
},
card: {
height: "100%",
display: "flex",
flexDirection: "column"
},
cardMedia: {
paddingTop: "56.25%" // 16:9
},
cardContent: {
flexGrow: 1
},
footer: {
backgroundColor: theme.palette.background.paper,
padding: theme.spacing(6)
}
}));
const cards = [
{
img:
"https://images.unsplash.com/photo-1564135624576-c5c88640f235?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=3300&q=80",
desc: "Campsite"
},
{
img:
"https://images.unsplash.com/photo-1564198879220-63f2734f7cec?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=2072&q=80",
desc: "Space"
}
];
export default function Album() {
const classes = useStyles();
return (
<React.Fragment>
<CssBaseline />
<AppBar position="relative">
<Toolbar>
<CameraIcon className={classes.icon} />
<Typography variant="h6" color="inherit" noWrap>
Album layout
</Typography>
</Toolbar>
</AppBar>
<main>
{/* Hero unit */}
<div className={classes.heroContent}>
<Container maxWidth="sm">
<Typography
component="h1"
variant="h2"
align="center"
color="textPrimary"
gutterBottom
>
Album layout
</Typography>
<Typography
variant="h5"
align="center"
color="textSecondary"
paragraph
>
Something short and leading about the collection below—its
contents, the creator, etc. Make it short and sweet, but not too
short so folks don&apos;t simply skip over it entirely.
</Typography>
<div className={classes.heroButtons}>
<Grid container spacing={2} justify="center">
<Grid item>
<Button variant="contained" color="primary">
Main call to action
</Button>
</Grid>
<Grid item>
<Button variant="outlined" color="primary">
Secondary action
</Button>
</Grid>
</Grid>
</div>
</Container>
</div>
<Container className={classes.cardGrid} maxWidth="md">
{/* End hero unit */}
<Grid container spacing={4}>
{cards.map(card => (
<Grid item key={card} xs={12} sm={6} md={4}>
<Card className={classes.card}>
<CardMedia
className={classes.cardMedia}
image={card.img}
title="Image title"
/>
<CardContent className={classes.cardContent}>
<Typography gutterBottom variant="h5" component="h2">
Heading
</Typography>
<Typography>{card.desc}</Typography>
</CardContent>
<CardActions>
<Button size="small" color="primary">
View
</Button>
<Button size="small" color="primary">
Edit
</Button>
</CardActions>
</Card>
</Grid>
))}
</Grid>
</Container>
</main>
{/* Footer */}
<footer className={classes.footer}>
<Typography variant="h6" align="center" gutterBottom>
Footer
</Typography>
<Typography
variant="subtitle1"
align="center"
color="textSecondary"
component="p"
>
Something here to give the footer a purpose!
</Typography>
<MadeWithLove />
</footer>
{/* End footer */}
</React.Fragment>
);
}

Resources