React Route to Page Using Unique ID - node.js

I have multiple rendered components on a page. When I click on one I want to navigate to a new page with all of the information specific to that component. What I need is:
OnClick -> Identify gameId variable
Using that gameID run a query against an API endpoint
Take the rendered data from the API and display it on a new page with route /nhl/:gameId
Example screenshot of /NHL page with different components.
/NHL Route
I have this existing Scores component:
function Scores(props) {
const navigate = useNavigate('/');
const handleClick = () => {
let path = '/' + {gameId};
navigate(path);
}
return (
<Card sx={{ Height: 50, padding: .25, margin: 3 }}>
<CardActionArea onClick={handleClick}>
<div className = "">
<CardContent sx={{ width: 200 }}>
<Stack direction="row" spacing={2}>
<Typography component="div" variant="h6">{props.gameStatus}</Typography>
<Typography>{props.gameDateandTime}</Typography>
</Stack>
<Stack direction="row" spacing={2}>
<Typography fontSize={14} sx={{ paddingTop: 1, paddingBottom: 1 }}>{props.awayTeam}</Typography>
<Typography fontSize={14} sx={{ paddingTop: 1, paddingBottom: 1 }}>{props.awayPoints}</Typography>
</Stack>
<Typography>#</Typography>
<Stack direction="row" spacing={2}>
<Typography fontSize={14} sx={{ paddingTop: 1, paddingBottom: 1 }}>{props.homeTeam}</Typography>
<Typography fontSize={14} sx={{ paddingTop: 1, paddingBottom: 1 }}>{props.homePoints}</Typography>
</Stack>
</CardContent>
</div>
</CardActionArea>
</Card>
)
}
export default Scores;
The Scores.js component above is rendered in the NHL route from the screenshot:
function NHL(){
var date = year + "-" + month + "-" + day;
const [scores, setScores] = useState([{ }]);
useEffect(() => {
let url = "http://localhost:3001/schednhl";
fetch(url).then(res => {
if(res.ok) {
return res.json()
}
}).then(jsonRes => setScores(jsonRes));
}, []);
return (
<div className='Home'>
<Banner />
<Typography variant="h3" align="center" sx={{ paddingTop: 5 }}>Live Games</Typography>
<hr className="lineRow"></hr>
<Stack direction="row" spacing={2}>
<div className="scroll-box">
<div className="scroll-box-wrapper">
<div className="scroll-box-container" role="list">
{scores.map((score, index) => {
if(score.gameDate === date && score.gameStatus === "closed" || score.gameStatus === "inprogress")
return (
<Scores
className="scroll-box-item"
role="listitem"
key={index}
id={index}
gameDate={score.gameDate}
gameStatus={score.gameStatus === "closed" ? "Final" : "Live" }
homeTeam={score.homeTeam}
homePoints={score.homePoints}
awayPoints={score.awayPoints}
awayTeam={score.awayTeam}
/>
);
})}
</div>
</div>
</div>
</Stack>
<h3 className="home-header" style={{paddingTop: 10 }}>Upcoming Games</h3>
<hr className="lineRow" style={{ }}></hr>
<Grid container spacing={3} direction="row" justifyContent="flex-start">
{scores.map((score, index) => {
if(score.gameDate === date && score.gameStatus === "scheduled" || score.gameStatus === "upcoming")
return (
<Scores
className="scroll-box-item"
role="listitem"
key={index}
id={index}
time={score.gameDateandTime}
gameStatus={score.gameStatus === "scheduled" ? "Upcoming" : ""}
homeTeam={score.homeTeam}
homePoints={score.homePoints}
awayPoints={score.awayPoints}
awayTeam={score.awayTeam}
/>
);
})}
</Grid>
</div>
);
}
export default NHL;
How can I access the gameId from the NHL function and use that in my Score component?

Related

Resizing book cover according to display size (express + react)

I'm working on a website where users can read book. In this, homepage showcase multiple books but I want this page to change the size of book cover depending upon display size and not crop them.
I'm also using mui library for creating ui elements.
Home.js
import { ImageList, ImageListItem, ImageListItemBar,
Typography, Link, Grid, Divider } from '#mui/material'
import { useContext } from 'react'
import { useNavigate } from 'react-router-dom'
import { PageLayout, Context } from '../Components/PageLayout'
function Feed({ catg, catgTitle, routeName = "" }) {
const navg = useNavigate();
const bookCatg = useContext(Context)[0][catg];
return (
<>
<Grid
container
direction="row"
justifyContent="space-between"
alignItems="center"
>
<Grid item>
<Typography variant="h6">{catgTitle}</Typography>
</Grid>
<Grid item>
<Link
href={`/book/${routeName}`}
variant="body1"
underline="none"
component="button"
>
More..
</Link>
</Grid>
</Grid>
<Divider />
<ImageList
sx={{ pt: '10px' }}
cols={4}
spacing={1}
rowHeight={250}
>
{bookCatg.map((book) => (
<ImageListItem key={book._id}>
<img
onClick={() => navg(`/book/${book._id}`)}
src={book.img}
sx={{ height: "50px" }}
alt='Not Found'
loading="lazy"
/>
<ImageListItemBar
onClick={() => navg(`/book/${book._id}`)}
sx={{ width: '10vw' }}
title={book.title}
position="below"
/>
</ImageListItem>
))}
</ImageList>
</>
)
}
export default function Home(){
var element = <>
<Feed catgTitle={'New Arrival'}
catg={'newArrival'} routeName={'newest'} />
<Feed catgTitle={'Popular Books'}
catg={'popRating'} routeName={'popular'} />
<Feed catgTitle={'Hot Rated'}
catg={'hotRating'} routeName={'hot'} />
<Feed catgTitle={'Rank'}
catg={'ranking'} routeName={'ranking'} />
</>;
return (
<PageLayout
url="/book"
gridElem={element}
failureMsg="Error"
/>
)
}
PageLayout.jsx
import { Grid, Typography } from '#mui/material'
import { useState, useEffect, createContext } from 'react'
import axios from 'axios'
import Navbar from './Navbar'
import AppFormNav from './AppFormNav'
import Loading from './Loading'
export const Context = createContext({});
export function PageLayout({ url, nav='normal', elem, gridElem, failureMsg }){
const NavType = {
'normal': <Navbar />,
'form': <AppFormNav />
};
const [info, setInfo] = useState({});
const fetchData = async() => {
axios.get(url)
.then((resp) => {
if(resp.status === 200)
setInfo({status: 200, data: resp.data.data});
else if(resp.status === 204)
setInfo({ status: 204, data: resp.message });
})
.catch((err) => {
setInfo({ status: 400, data: err.response.data.data })
// console.log("Bad Request", err.resp.status);
})
};
useEffect(() => {
fetchData();
}, []);
var gridElement = <Loading />, element, message;
if(info.status === 200){
gridElement = gridElem;
element = elem;
}
else if (info.status === 204){
gridElement=<></>;
message = failureMsg ? failureMsg : info.data;
}
return (
<Context.Provider value={info?.data}>
<Grid container sx={{ justifyContent: 'center' }}>
<Grid item> { NavType[nav] } </Grid>
<Grid item xs={12}> { element } </Grid>
<Grid item xs={10}>
<Typography sx={{ justifyContent: "center", alignItems: "center" }}> {message} </Typography>
</Grid>
<Grid item xs={ 10 }> { gridElement } </Grid>
</Grid>
</Context.Provider>
)
}
current look
As you can see the bookcover of different size take up space of other book cover.
Home.jsx
import { ImageList, ImageListItem, ImageListItemBar,
Typography, Link, Grid, Divider } from '#mui/material'
import { useContext } from 'react'
import { useNavigate } from 'react-router-dom'
import { PageLayout, Context } from '../Components/PageLayout'
function Feed({ catg, catgTitle, routeName = "" }) {
const navg = useNavigate();
const bookCatg = useContext(Context)[0][catg];
return (
<>
<Grid
container
direction="row"
justifyContent="space-between"
alignItems="center"
>
<Grid item>
<Typography variant="h6">{catgTitle}</Typography>
</Grid>
<Grid item>
<Link
href={`/book/${routeName}`}
variant="body1"
underline="none"
component="button"
>
More..
</Link>
</Grid>
</Grid>
<Divider />
<ImageList
sx={{ pt: '10px' }}
cols={4}
spacing={1}
// rowHeight={250}
>
{bookCatg.map((book) => (
<ImageListItem key={book._id}>
<img
onClick={() => navg(`/book/${book._id}`)}
src={book.img}
//changed start from here
style={{ aspectRatio: "0.8", resize: "auto", objectFit: "scale-down" }}
//change end here
alt='Not Found'
loading="lazy"
/>
<ImageListItemBar
onClick={() => navg(`/book/${book._id}`)}
sx={{ width: '10vw' }}
title={book.title}
position="below"
/>
</ImageListItem>
))}
</ImageList>
</>
)
}
export default function Home(){
var element = <>
<Feed catgTitle={'New Arrival'}
catg={'newArrival'} routeName={'newest'} />
<Feed catgTitle={'Popular Books'}
catg={'popRating'} routeName={'popular'} />
<Feed catgTitle={'Hot Rated'}
catg={'hotRating'} routeName={'hot'} />
<Feed catgTitle={'Rank'}
catg={'ranking'} routeName={'ranking'} />
</>;
return (
<PageLayout
url="/book"
gridElem={element}
failureMsg="Error"
/>
)
}
just added this style to img tag
style={{ aspectRatio: "0.8", resize: "auto", objectFit: "scale-down"
}}

How to use different image on mobile in ReactJs Slick

Is there any way to use mobile image different from the desktop mode in react slick slider? I can use display none for breakpoints but what I want to learn, Is there any different way to do it?
const Hero = () => {
const classes = useStyle();
const { push } = useRouter();
const [sliderState, setSliderState] = useState(heroSliderData);
const [my_swiper, set_my_swiper] = useState({});
return (
<section className={classes.section}>
<Grid style={{ width:"100%", padding: "0px" }}>
<Swiper
loop={true}
navigation={true}
onInit={(ev) => {
set_my_swiper(ev);
}}
>
{sliderState.map(({ id, mainheading, mainheading2, subheading, subheading2, buttontext, image }) => (
<SwiperSlide key={id}>
<Grid item className={classes.hero}>
<img className={classes.heroimg} src={image} style={{ position:"relative"}} />
<Grid item xs={12} style={{ position:"absolute", top:"30%", left:"0", right:"0", textAlign: "center" }}>
<Typography variant="h1" className={classes.h1}>
{mainheading}<br />
{mainheading2}
</Typography>
</Grid>
<Grid item xs={12} style={{ position:"absolute", top:"42%", left:"0", right:"0", textAlign: "center" }}>
<Typography variant="h2" className={classes.h2}>
{subheading}
<br/>
{subheading2}
</Typography>
</Grid>
<Grid item xs={12} style={{ position:"absolute", top:"52%", left:"0", right:"0", textAlign: "center" }}>
<Button
variant="contained"
onClick={() => push("/teklif-al")}
className={classes.teklifal}
>
{buttontext}
</Button>
</Grid>
</Grid>
</SwiperSlide>
))}
</Swiper>
</Grid>
</section>
);
};
This is my code that I am working on it
Have you tried to use an IF clause to show and hide images?
See docs of React Slick.
import React, { Component } from "react";
import Slider from "react-slick";
export default class MultipleItems extends Component {
render() {
const settings = {
dots: true,
infinite: true,
speed: 500,
slidesToShow: 3,
slidesToScroll: 3
};
return (
<div>
<h2> Multiple items </h2>
<Slider {...settings}>
<div>
<h3>1</h3>
</div>
<div>
<h3>2</h3>
</div>
<div>
<h3>3</h3>
</div>
<div>
<h3>4</h3>
</div>
<div>
<h3>5</h3>
</div>
<div>
<h3>6</h3>
</div>
<div>
<h3>7</h3>
</div>
<div>
<h3>8</h3>
</div>
<div>
<h3>9</h3>
</div>
</Slider>
</div>
);
}
}
And modify like this:
import React, { Component } from "react";
import Slider from "react-slick";
export default class MultipleItems extends Component {
const showOnMobile = document.innerWidth < 769;
render() {
const settings = {
dots: true,
infinite: true,
speed: 500,
slidesToShow: 3,
slidesToScroll: 3
};
return (
<div>
<h2> Multiple items </h2>
<Slider {...settings}>
{showOnMobile &&
<div>
<h3>1</h3>
</div>
}
<div>
<h3>2</h3>
</div>
<div>
<h3>3</h3>
</div>
<div>
<h3>4</h3>
</div>
<div>
<h3>5</h3>
</div>
<div>
<h3>6</h3>
</div>
<div>
<h3>7</h3>
</div>
<div>
<h3>8</h3>
</div>
<div>
<h3>9</h3>
</div>
</Slider>
</div>
);
}
}

React Bootstrap Card Result in Multiple Columns

Below is my code, my problem is, the results are displaying at the bottom one by one like this:
1
2
3
I want to display each output result as follows? as 3 column
1 2 3
4 5 so on......
I have used https://react-bootstrap.github.io/components/cards/ component to display the database output
{Mylist.length && Mylist.map((item, index) => {
return (
<Card key={index} style={{ width: '18rem' }}>
<Card.Body>
<Card.Subtitle className="mb-2 text-muted">{moment(item.date_time).format('LLL')}</Card.Subtitle>
<Card.Text>{item.content}</Card.Text>
<Button variant="danger" size="sm" data-id={item.id} onClick={() => remove(item.id)} >Delete</Button>{' '}
</Card.Body>
</Card>
)
})}
Try the following approach, see more at https://react-bootstrap.netlify.app/components/cards/#card-groups
<Row xs={1} md={2} className="g-3">
{Mylist.length && Mylist.map((item, index) => {
return (
<Col key={index}>
<Card style={{ width: '18rem' }}>
<Card.Body>
<Card.Subtitle className="mb-2 text-muted">{moment(item.date_time).format('LLL')}</Card.Subtitle>
<Card.Text>{item.content}</Card.Text>
<Button variant="danger" size="sm" data-id={item.id} onClick={() => remove(item.id)} >Delete</Button>{' '}
</Card.Body>
</Card>
</Col>
)
})}
</Row>

Redirect use if not logged in

I am trying to redirect the user if he/she has not logged in. I am using the below snipet to do that.
if(!this.props.isAuthenticated){
this.nextPath('/account/login')
}
But when I execute it, I am getting an error. (Error: Maximum update depth exceeded). If I takeoff the above snippet. I am not getting Error.
I have also attached the full code. Help me with debugging this problem.
import React, { Component, Suspense } from 'react'
import { Layout, Menu } from 'antd';
import {TagFilled, SettingFilled , FileAddOutlined, DeleteFilled, LogoutOutlined } from '#ant-design/icons';
import { renderRoutes } from 'react-router-config';
import { loadLabels, deleteLabel} from '../../Store/Action/label'
import { logout } from '../../Store/Action/auth'
import { connect } from 'react-redux';
import Dialog from '#material-ui/core/Dialog';
import DialogActions from '#material-ui/core/DialogActions';
import DialogContent from '#material-ui/core/DialogContent';
import DialogTitle from '#material-ui/core/DialogTitle';
import Button from '#material-ui/core/Button';
import AddLabel from './Components/AddLabel'
import SideBar from './Components/SideBar'
import Avatar from '#material-ui/core/Avatar';
import {Dropdown} from 'react-bootstrap'
import Card from '#material-ui/core/Card';
import CardContent from '#material-ui/core/CardContent';
import { Row, Col, ListGroup } from 'react-bootstrap';
import Typography from '#material-ui/core/Typography';
import Divider from '#material-ui/core/Divider';
import ListSubheader from '#material-ui/core/ListSubheader';
import List from '#material-ui/core/List';
import ListItem from '#material-ui/core/ListItem';
import ListItemIcon from '#material-ui/core/ListItemIcon';
import ListItemText from '#material-ui/core/ListItemText';
import { Redirect } from 'react-router-dom';
const { Header, Content, Footer, Sider } = Layout;
export class HomePage extends Component {
//Constructor
constructor(){
super()
this.state = {
collapsed: false,
addLabelVisible: false,
isHovered: {},
anchorEl: null,
setAnchorEl: null
};
this.addLabelToggle = this.addLabelToggle.bind(this)
this.handleMouseEnter = this.handleMouseEnter.bind(this);
this.handleMouseLeave = this.handleMouseLeave.bind(this);
this.handlelogOut = this.handlelogOut.bind(this);
this.fetchData = this.fetchData.bind(this);
}
//Collapse the Sidebar
onCollapse = collapsed => {
this.setState({ collapsed });
};
//Toogle Add Label Dialog
addLabelToggle(addLabelVisible) {
this.setState({ addLabelVisible });
}
//Fetch All labels from the API
componentDidMount(){
console.log('problem here 1')
this.props.loadLabels()
}
//API CAll
fetchData(){
this.props.loadLabels()
}
//Called Whenever new Label is Added
componentDidUpdate(prevProps) {
if(typeof(prevProps.labels) === 'undefined' ) {
this.fetchData()
}
else if(prevProps.labels === this.props.labels){
this.fetchData()
}else{
}
}
//Hover
handleMouseEnter = index => {
this.setState(prevState => {
return { isHovered: { ...prevState.isHovered, [index]: true } };
});
};
//Hover
handleMouseLeave = index => {
this.setState(prevState => {
return { isHovered: { ...prevState.isHovered, [index]: false } };
});
};
//Delete a Label
handleLabelDelete(id){
const data = {
id: id,
img: 'https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png'
}
this.props.deleteLabel(data)
}
handleClick = (event) => {
this.setState({
anchorEl: event.currentTarget
})
};
handleClose = () => {
this.setState({
anchorEl: null
})
};
handlelogOut = (e) =>{
console.log('logout')
this.props.logout()
}
nextPath(path) {
this.props.history.push(path);
}
render() {
const open = Boolean(this.anchorEl);
const id = open ? 'simple-popover' : undefined;
const { arr, isHovered } = this.state;
console.log(this.props.request)
if(!this.props.isAuthenticated){
this.nextPath('/account/login')
}
return (
<Layout style={{ minHeight: '100vh' }}>
{/* Navbar */}
<Header className="header" style={{ height: '60px', backgroundColor: '#1a243a' }}>
<div style={{ width: '120px', height: '31px', float: 'left', margin: '16px 28px 16px 0' }}>
<h2 style={{ color: 'white' }}>Nexdo</h2>
</div>
<div style={{ float: 'right' }}>
<Dropdown>
<Dropdown.Toggle style={{ backgroundColor: 'transparent', borderColor: 'transparent' }} id="dropdown-basic">
<Avatar>{this.props.user?this.props.user.first_name.slice(0,1):""}</Avatar>
</Dropdown.Toggle>
<Dropdown.Menu>
<Card style={{ background: '#ffffff', boxShadow: 'none', width: '280px' }}>
<CardContent>
<Row>
<Col xs={9}>
<Typography style={{ alignContent: 'right', justifyContent: 'right', display: 'flex' }} variant="h6" noWrap>
{this.props.user?this.props.user.first_name:""} {this.props.user?this.props.user.last_name:""}
</Typography>
<Typography style={{ color: '#333333', fontSize: '11px' , alignContent: 'right', justifyContent: 'right', display: 'flex' }} variant="h6" noWrap>
{this.props.user?this.props.user.email:""}
</Typography>
</Col>
<Col xs={3}>
<Avatar>{this.props.user?this.props.user.first_name.slice(0,1):""}</Avatar>
</Col>
</Row>
</CardContent>
<Divider />
<List
component="nav"
aria-labelledby="nested-list-subheader"
subheader={
<ListSubheader component="div" id="nested-list-subheader">
Actions
</ListSubheader>
}
>
<ListItem button>
<ListItemIcon>
<SettingFilled />
</ListItemIcon>
<ListItemText primary="Profile" />
</ListItem>
<a onClick={this.handlelogOut}>
<ListItem button>
<ListItemIcon>
<LogoutOutlined />
</ListItemIcon>
<ListItemText primary="Logout" />
</ListItem>
</a>
</List>
</Card>
</Dropdown.Menu>
</Dropdown>
</div>
</Header>
{/* SideBar and Content */}
<Layout className="site-layout">
<SideBar labelData = {this.props.labels} addLabelToggle = {this.addLabelToggle}/>
{/* Content which will be loaded dynamically */}
<Content style={{ margin: '0 16px' }}>
<main style={{ backgroundColor: "#fafafa", minHeight: '-webkit-fill-available' }} >
<Suspense fallback={<div>Loading...</div>}>
{renderRoutes(this.props.route.routes,)}
</Suspense>
</main>
</Content>
</Layout>
{/* Footer */}
<Footer style={{ textAlign: 'center' }}>Joan Louji ©2020 Created by Joan Louji</Footer>
{/* Add Label Dialog Box */}
<Dialog scroll="paper" open={this.state.addLabelVisible} onClose={()=>this.addLabelToggle(false)} aria-labelledby="scroll-dialog-title" aria-describedby="scroll-dialog-description">
<DialogTitle id="form-dialog-title"><b>Labels</b></DialogTitle>
<DialogContent>
<div style={{ height: "400px", width: "300px" }}>
{/* Display the Add Label Box */}
<AddLabel editClassName="form-control" value="Create a new Label" />
{this.props.labels?(this.props.labels.length==0?
<div style={{ margin: "0 auto", fontSize: '60px' ,display: 'flex' ,justifyContent: 'center', alignContent: 'center', alignItems: 'center', height: '100%', color: '#e0ebff'}}>
<div className="row">
<div className="col-12">
<FileAddOutlined style={{ margin: "0 auto", fontSize: '60px' ,display: 'flex' ,justifyContent: 'center', alignContent: 'center', alignItems: 'center', height: '100%', width: '100%' ,color: '#e0ebff'}}/>{"\n"}
</div>
<div className="col-12">
<h3 style={{ margin: "0 auto", fontSize: '20px' ,display: 'flex' ,justifyContent: 'center', alignContent: 'center', alignItems: 'center', height: '100%', width: '100%' ,color: '#e0ebff', marginTop: '20px'}}>Label Not Found</h3>
</div>
</div>
</div>
:
""
):"sd"}
{/* Render All the Labels in the Dialog Box */}
{this.props.labels?this.props.labels.map((data,index)=>{
return(
<div style={{ marginTop: '20px', }} >
<div key={data.name}>
<div className="row">
<div className="col-1" onMouseEnter={()=>this.handleMouseEnter(index)} onMouseLeave={()=>this.handleMouseLeave(index)}>
{this.state.isHovered[index]?
<DeleteFilled style={{ fontSize: 17, color: 'grey', cursor: 'pointer' }} onClick={(e)=>this.handleLabelDelete(data._id)}/>
:
<TagFilled style={{ fontSize: 17, color: 'grey' }}/>
}
</div>
<div className="col-9">
{data.name}
</div>
</div>
</div>
</div>
)
}):
<div>
<FileAddOutlined />
</div>
}
</div>
</DialogContent>
<DialogActions>
<Button onClick={(e)=>{
this.addLabelToggle(false)
}}>Done</Button>
</DialogActions>
</Dialog>
</Layout>
);
}
}
//mapStateToProps
const mapStateToProps = (state) => ({
isLoading: state.labels.isLoading,
user: state.auth.user,
labels: state.labels.labels,
});
export default connect(mapStateToProps, {loadLabels, deleteLabel, logout})(HomePage)
From the error, it is clear that there "IF" condition you have mentioned in the ComponentDidUpdate is calling setState repeatedly. That's why the react framework limits.
Please refer Component Did Update

How to make Material-UI GridListTitleBar and Image a Link in ReactJS

I am using Material UI GridList to display a list of Events in React. Everything is working fine except that I am not able to make Title or Image a Link. Does anyone know how to make Title and Image a Link?
Here is my Component.
<div className={classes.root}>
<GridListTile key="Subheader" style={{ height: "auto" }}>
<ListSubheader component="div">This is List of Events</ListSubheader>
</GridListTile>
<GridList
cellHeight={330}
cols={matches ? 1 : 3}
className={classes.gridList}
spacing={12}
>
{tileData.length > 0 &&
tileData.map((tile, index) => {
return (
<GridListTile
key={Math.floor(Math.random() * new Date().getTime())}
>
<img src={tile.eventImage} alt={tile.title} />
<GridListTileBar
title={tile.title}
subtitle={<span>by: {tile.description}</span>}
actionIcon={<IconButton title={tile.title} />}
/>
</GridListTile>
);
})}
</GridList>
</div>
);
Update
This is an update to the answer that was given below. The first image is now smaller than the rest of the images after update the code with the solution given below.
Here is the new code that I am trying:
<div className={classes.root}>
<GridListTile key="Subheader" style={{ height: "auto" }}>
<ListSubheader component="div">This is List of Events</ListSubheader>
</GridListTile>
<GridList
cellHeight={330}
cols={matches ? 1 : 3}
className={classes.gridList}
spacing={12}
>
{tileData.length > 0 &&
tileData.map((tile, index) => {
return (
<GridListTile
key={Math.floor(Math.random() * new Date().getTime())}
>
<a href={"events/" + tile._id + "/eventcomments"}>
<img
src={tile.eventImage}
alt={tile.title}
className="MuiGridListTile-imgFullHeight"
/>
<GridListTileBar title={tile.title} />
</a>
</GridListTile>
);
})}
</GridList>
</div>
Try wrapping the image with an anchor tag like this:
// ...
<GridListTile key={Math.floor(Math.random() * new Date().getTime())}>
<a href="https://www.google.com/">
<img src={tile.eventImage} alt={tile.title} className="MuiGridListTile-imgFullHeight" />
</a>
<GridListTileBar
title={tile.title}
subtitle={<span>by: {tile.description}</span>}
actionIcon={<IconButton title={tile.title} />}
/>
</GridListTile>
// ...
It is important, after wrapping the image inside an anchor tag to add the class MuiGridListTile-imgFullHeight to the image to keep the same styling of the grid. Normally this class is added automatically, but if you wrap it inside an anchor tag it isn't. So you need to add it manually.
Update
The image shows expected behavior, because your first image is not wide enough to cover the whole tile and you only added the class to scale the img to full height. There is also a class to scale to full width: MuiGridListTile-imgFullWidth, but you can't use both of these classes together for your use case as the styles conflict (see the style definition here: https://github.com/mui-org/material-ui/blob/master/packages/material-ui/src/GridListTile/GridListTile.js).
You can try to set the width to 100% in the image style prop:
<img
// ...
style={{ width: "100%" }}
className="MuiGridListTile-imgFullHeight"
/>
I eventually managed to get it to work without breaking or stretching my images, and here is what I did.
<div className={classes.root}>
<GridListTile key="Subheader" style={{ height: "auto" }}>
<ListSubheader component="div">This is List of Events</ListSubheader>
</GridListTile>
<GridList
cellHeight={330}
cols={matches ? 1 : 3}
className={classes.gridList}
spacing={12}
>
{tileData.length > 0 &&
tileData.map((tile, index) => {
return (
<GridListTile
component={Link}
to={"/events/" + tile._id + "/eventcomments"}
key={Math.floor(Math.random() * new Date().getTime())}
>
<img src={tile.eventImage} alt={tile.title} />
<GridListTileBar title={tile.title} />
</GridListTile>
);
})}
</GridList>
</div>
const Gallery = () => {
const classes = useStyles();
return (
<Fragment>
<div style={{background: "black"}}>
<Toolbar/>
<Grid container spacing={0}>
<Grid item xs={12}>
<Paper className={classes.paper}>GALERIA</Paper>
<div className={classes.root}>
<GridList cellHeight={280} className={classes.gridList} cols={1}>
{tileData.map((tile) => (
<GridListTile style={{ width: "100%" }} key={tile.img} cols={tile.cols || 1}>
<img src={tile.img} alt={tile.title} />
</GridListTile>
))}
</GridList>
</div>
</Grid>
</Grid>
</div>
</Fragment>
)
}
export default Gallery;
You can change the type of underlying component rendered by the GridListTime Material-UI component. Just add the component="a" to have it render as an anchor tag. Then you may specify an href prop to pass in your route. See below:
<GridList cellHeight={160} className={classes.gridList} cols={3}>
{tileData.map((tile) => (
<GridListTile key={tile.img} cols={tile.cols || 1} component="a" href="/">
<img src={tile.img} alt={tile.title} />
</GridListTile>
))}
</GridList>

Resources