I have a component, GameGrid which makes an axios call to get the data that I pass as props to another component, GameCard. I currently have a Header component that is in the same file as GameGrid. The header has buttons which when clicked, changes the endpoint that the GameGrid is calling. I am trying to figure out a way to separate the two components, Header and GameGrid, but still have the buttons on the header determine which endpoint the GameGrid should call. Also, is the GameGrid the right place to have the data being called?
GameGrid.jsx
import React, { useEffect, useState } from "react";
import AppBar from '@mui/material/AppBar';
import Toolbar from '@mui/material/Toolbar';
import Box from '@mui/material/Box';
import IconButton from '@mui/material/IconButton';
import Grid from '@mui/material/Grid';
import axios from "axios";
import GameCard from "./GameCard";
export default function GameGrid() {
const [data, setData] = useState(); // Data Hook
const [route, setRoute] = useState('/')
useEffect(() => {
const getData = async () => {
try {
const { data } = await axios.get(`${process.env.REACT_APP_URL}${route}`);
console.log(data);
setData(data);
} catch (err) {
console.log(err);
}
};
getData();
}, [route]);
const createCards = (data) => {
return <GameCard
key = {data.id}
id = {data.id}
url = {data.game_url}
thumbnail = {data.thumbnail}
title = {data.title}
platform = {data.platform}
description = {data.short_description}
genre = {data.genre}
publisher = {data.publisher}
developer = {data.developer}
/>;
}
const Header = () => {
return (
<Box sx ={{ flexGrow: 1 }}>
<AppBar position="fixed">
<Toolbar>
<Grid sx={{ flexGrow: 1,
border: '1px solid white'}} container spacing={2}>
<Grid sx={{
}}>
<IconButton onClick={() => setRoute('/')}>
<img src='computer-mouse.png' alt='Logo' id='icon'/>
</IconButton>
<IconButton onClick={() => setRoute('/shooter')}>
<img src="shooter.png" alt="Shooter Games" />
</IconButton>
</Grid>
<Grid>
</Grid>
</Grid>
</Toolbar>
</AppBar>
</Box>
)
}
return (
<>
<Header/>
<div className="card-container">
{data?.map(createCards)}
</div>
</>
)
}
GameCard.jsx
import React 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, Chip } from "@mui/material";
import Stack from '@mui/material/Stack';
export default function GameCard(props) {
return (
<Card sx={{ width: 550, margin: 2}} key={props.id} id={props.id} >
<CardActionArea href={props.url}>
<CardMedia
component="img"
height="fit-content"
image={props?.thumbnail}
/>
<CardContent>
<Stack direction="row" justifyContent="space-between">
<Typography gutterBottom variant="h6" component="div">
{props.title}
</Typography>
<Chip label={props.platform} size="small"/>
</Stack>
<Typography gutterBottom variant="body1" id="description-text"
color="text.secondary"
sx={{
textOverflow: 'ellipsis',
overflow: 'hidden',
whiteSpace: 'nowrap'
}}>
{props.description}
</Typography>
<Stack direction="row" justifyContent="space-between">
<Chip label={props.genre} size="small" />
<Chip label={props.publisher} size="small" />
<Chip label={props.developer} size="small" />
</Stack>
</CardContent>
</CardActionArea>
</Card>
);
}
CodePudding user response:
To separate Header
, simply define it with all the props it requires. In this instance, that appears to be the setRoute
function though you can call it whatever you like.
For example
// Header.jsx
const Header = ({ onRouteClick }) => (
<Box sx={{ flexGrow: 1 }}>
{/* ... */}
<IconButton onClick={() => onRouteClick("/")}>
<img src="computer-mouse.png" alt="Logo" id="icon" />
</IconButton>
<IconButton onClick={() => onRouteClick("/shooter")}>
<img src="shooter.png" alt="Shooter Games" />
</IconButton>
{/* ... */}
</Box>
);
export default Header;
and in your GameGrid
component, import Header from "./Header"
and use...
<Header onRouteClick={setRoute} />
If you were using Typescript (highly recommended), the API for Header
would look something like this
interface HeaderProps {
onRouteClick: (route: string) => void;
}
const Header = ({ onRouteClick }: HeaderProps) => (
// ...
);
CodePudding user response:
There are multiple ways to acheive this. You can either use a data store like Redux or choose to handle the data passing between child components by yourself. This tutorial explains how you can pass data between child and parent components.