Home > Back-end >  Can't use props on imported React functional components
Can't use props on imported React functional components

Time:07-09

I'm trying to get a component (TestCard) to render the output of an API call I'm making with Axios. When I put the code of the TestCard component directly in the App() function of my App.js file, it renders as expected. But when I move this code out into its own function, it doesn't render the values. This is surprising to me, as I'm calling the same useState and useEffect functions to store the data from the API call in state.

I've listed the code below; what am I doing wrong here?

This is the code of the TestCard component:

function TestCard(props) {
    return (
      <Card sx={{ maxWidth: 345 }}>
      <CardActionArea>
        <CardMedia
          component="img"
          height="300"
          image={props.preview_image}
          alt={props.name} />
        <CardContent>
          <Typography gutterBottom variant="h5" component="div">
            {props.description}
          </Typography>
          <Typography variant="body2" color="text.secondary">
            {props.description}
          </Typography>
        </CardContent>
      </CardActionArea>
    </Card>
  );
}

export default TestCard

This is the code directly in my App() function (this renders correctly):

function App() {
  const [props, setProps] = useState({});
  useEffect(() => {
     axios.get(`http://localhost:9000/sessions/list`).then((row)=>setProps(row.data))
  })
  return (
    <div>
        <Card sx={{ maxWidth: 345 }}>
    <CardActionArea>
      <CardMedia
        component="img"
        height="300"
        image={props.preview_image}
        alt={props.name} />
      <CardContent>
        <Typography gutterBottom variant="h5" component="div">
          {props.description}
        </Typography>
        <Typography variant="body2" color="text.secondary">
          {props.description}
        </Typography>
      </CardContent>
    </CardActionArea>
  </Card>
    </div> 
  );
}

export default App

And this is the imported function in my App() function (does not render the data correctly):

function App() {
  const [props, setProps] = useState({});
  useEffect(() => {
     axios.get(`http://localhost:9000/sessions/list`).then((row)=>setProps(row.data))
  })
  return (
    <div>
      <TestCard name={props.name} description={props.description} preview_image={props.preview_image} />
    </div> 
  );
}

CodePudding user response:

I'm not sure if this might be the issue, but I'm thinking maybe it has something to do with te useEffect dependency array, since you have no dependency array, it's making the api call on every render, which in some cases could cause more render because you are changing the state. Try setting the useEffect like this

function App() {
  const [props, setProps] = useState({});
  useEffect(() => {
    axios
      .get(`http://localhost:9000/sessions/list`)
      .then((row) => setProps(row.data));
  }, []);
  return (
    <div>
      <TestCard
        name={props.name}
        description={props.description}
        preview_image={props.preview_image}
      />
    </div>
  );
}

CodePudding user response:

First, you need to add a dependency to useEffect, especially when making an API call. Without it, it will make the API call every time the component re-renders and that is an endless cycle.

useEffect(() => {
  axios
    .get(`http://localhost:9000/sessions/list`)
    .then((row)=>setProps(row.data))
  },[])

The issue with your code is that you are passing in three properties to TestCard but expecting one. Here is the working version:

function TestCard({name, description, preview_image}) {
    return (
      <Card sx={{ maxWidth: 345 }}>
        <CardActionArea>
          <CardMedia
            component="img"
            height="300"
            image={preview_image}
            alt={name} />
          <CardContent>
            <Typography gutterBottom variant="h5" component="div">
              {description}
            </Typography>
            <Typography variant="body2" color="text.secondary">
              {description}
            </Typography>
          </CardContent>
        </CardActionArea>
     </Card>
  );
}

export default TestCard
  • Related