Home > Mobile >  Can a component change the data of another component?
Can a component change the data of another component?

Time:08-15

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.

  • Related