Search code examples
javascriptreactjsreact-propsconditional-rendering

Props is undefined when passed to a child component (react hooks)


I am building a simple agenda component and ran into a problem. The idea is that when a person clicks on the day and then sees trainings from this specific day. My logic is the following

  1. On button click I set state to day id
  2. On existing active item Ternary operator renders the component
  3. I am passing function invocation as props, which returns up-to-date object.

I tried putting function invocation to handleClick function, which did not help. For me it seems that the problem can occur with function not returning the value in time for component to pass it, but I don't know how to bypass this problem. Here is the codesandbox with everything - please help

https://codesandbox.io/s/cranky-johnson-s2dj3?file=/src/scheduledTrainingCard.js

Here is the code to parent component, as the problem is here

import React, { useState } from "react";
import { Transition, Grid, Button, Container } from "semantic-ui-react";
import ScheduledTrainingCard from "./scheduledTrainingCard";

function ScheduleComponent(props) {
  const days = [
    {
      id: "1",
      dayTrainings: [
        {
          time: "20:15:00",
          training: "zumba",
          trainer: "joe"
        },
        {
          time: "16:00:00",
          training: "stretching",
          trainer: "lily"
        }
      ],
      date:
        "Thu Dec 28 1995 00:00:00 GMT+0100 (Central European Standard Time)",
      createdAt: "2021-07-14T19:30:59.177Z"
    },
    {
      id: "2",
      dayTrainings: [
        {
          time: "23:15:00",
          training: "boxing",
          trainer: "phoebe"
        },
        {
          time: "15:00:00",
          training: "dancing",
          trainer: "kate"
        }
      ],
      date: "Thu Sep 23 2021 20:57:38 GMT+0200 (Central European Summer Time)",
      createdAt: "2021-09-23T19:01:53.801Z"
    },
    {
      id: "3",
      dayTrainings: [
        {
          time: "23:15:00",
          training: "ballet",
          trainer: "nataly"
        },
        {
          time: "12:00:00",
          training: "crossfit",
          trainer: "sheldon"
        }
      ],
      date: "Fri Jul 23 2021 21:02:37 GMT+0200 (Central European Summer Time)",
      createdAt: "2021-09-23T19:03:31.161Z"
    }
  ];

  const [activeItem, setActiveItem] = useState("");

  const handleItemClick = (e) => {
    setActiveItem(e.target.name);
  };

  function showSelectedDay(arr, dayId) {
    arr.forEach((element, index) => {
      if (dayId === element.id) {
        console.log("selected day is " + element.date);
        let trainings = element.dayTrainings;
        trainings.map((training) => {
          return training;
        });
      } else {
        console.log("not selected, day id is " + element.id);
      }
    });
  }

  const ScheduleComponent = (
      <Container style={{ textAlign: "left" }}>
        <h1 style={{ textAlign: "center" }}>Training Schedule</h1>
        <p>
          Lorem ipsum dolor sit amet consectetur adipisicing elit. Incidunt
          dolor unde repudiandae culpa ullam, asperiores officiis ratione
          repellat quaerat nihil vel corporis distinctio vero doloribus dolore
          optio commodi voluptatum inventore.
        </p>

        <Container>
          <Grid style={{ margin: "2rem auto", textAlign: "center" }} relaxed>
            <Button onClick={(e) => handleItemClick(e)} name={"1"}>
              Monday
            </Button>
            <Button onClick={(e) => handleItemClick(e)} name={"2"}>
              Tuesday
            </Button>
            <Button onClick={(e) => handleItemClick(e)} name={"3"}>
              Wednesday
            </Button>
          </Grid>
        </Container>
        <Container>
          {activeItem && (
            <ScheduledTrainingCard
              dayTraining={showSelectedDay(days, activeItem)}
            ></ScheduledTrainingCard>
          )}
        </Container>
      </Container>
   
  );
  return ScheduleComponent;
}

export default ScheduleComponent;


Solution

  • The problem is that you are using return inside map. Look how I did it:

    1- We don't need the function showSelectedDay so I remove it.

    2- We don't need the state const [activeItem, setActiveItem] = useState("");.

    3- Add new state const [dayTrainings, setDayTrainings] = useState([]);

    4- Update handleItemClick to:

      const [dayTrainings, setDayTrainings] = useState([]);
      const handleItemClick = (e) => {
        days.forEach((element, index) => {
          if (e.target.name === element.id) {
            console.log("selected day is " + element.date);
            setDayTrainings(element.dayTrainings);
          } else {
            console.log("not selected, day id is " + element.id);
          }
        });
      };
    

    5- In the render return:

          {dayTrainings.length > 0 && (
            <ScheduledTrainingCard
              dayTraining={dayTrainings}
            ></ScheduledTrainingCard>
          )
    

    Example of ScheduledTrainingCard:

    export default function scheduledTrainingCard(props) {
      console.log(props.dayTraining);
      return (<>
          {
            props.dayTraining.map((item, index) => 
            <p key={index}>
              {item['time']}<br/>
              {item['training']}<br/>
              {item['trainer']}<br/>
              <br/><br/>
            </p>)
          }
        </>);
    }
    

    Example of output: output