0

I need to pass bookLeacture function from AvailableCourses into LectureItem (inside Button onClick). But I think I can define only variable inside LectureItem but could not define as a function. Can you explain how can I call and define it?

const LectureItem = props => {
  let l = props.lecture;
  // let bookLeacture=props.bookLeacture
  return (
    <>
      <Container>
        <Row>
          <Col>
            <Alert variant="primary">
              <Row>
                {l.booked === false && (
                  <Col>
                    <Button
                      onClick={this.bookLeacture(l.lectureId)}
                      variant="success"
                      block
                    >
                      Book Now
                    </Button>
                  </Col>
                )}
              </Row>
            </Alert>
          </Col>
        </Row>
      </Container>
    </>
  );
};

class AvailableCourses extends React.Component {
  bookLeacture = id => {
    API.bookLeacture(id)
      .then(res => {
        console.log(res);
        this.setState({ lectures: res, loading: null, serverErr: null });
      })
      .catch(err => {
        this.setState({ serverErr: true, loading: null });
      });
  };

  constructor(props) {
    super(props);
    this.state = { lectures: [] };
  }
  render() {
    return (
      <>
        <Container fluid>
          <Row className="justify-content-md-center below-nav">
            <h3>Available Courses: </h3>
          </Row>
          {this.state.lectures.map(e => {
            return <LectureItem lecture={e} bookLeacture={this.bookLeacture} />;
          })}
        </Container>
      </>
    );
  }
}
export default AvailableCourses;
2
  • You're already returning a normal component, why are you wrapping it in the Fragment shortcode? That shortcode is for if you would otherwise return incompatible content. Commented Nov 11, 2020 at 21:06
  • I have an answer to a similar question here, How to set one component's state from another component in React. In this question, we were passing setState() between two functions, though any function could be used. Commented Nov 11, 2020 at 21:10

2 Answers 2

1

You've got a Functional Component there, which doesn't have classful arguments. This means, this is not valid here. So all you need to do is, change the following:

onClick={this.bookLeacture(l.lectureId)}

to this, plus the above is not a right way too, it gets executed immediately:

onClick={() => bookLeacture(l.lectureId)}

Also, you don't need fragments <></> for returning the Container.


Ultimately I'd do something like this:

const LectureItem = ({ lecture, bookLeacture }) => {
  return (
    <Container>
      <Row>
        <Col>
          <Alert variant="primary">
            <Row>
              {lecture.booked === false && (
                <Col>
                  <Button
                    onClick={() => bookLeacture(lecture.lectureId)}
                    variant="success"
                    block
                  >
                    Book Now
                  </Button>
                </Col>
              )}
            </Row>
          </Alert>
        </Col>
      </Row>
    </Container>
  );
};

class AvailableCourses extends React.Component {
  state = { lectures: [] };
  bookLeacture = id => {
    API.bookLeacture(id)
      .then(res => {
        console.log(res);
        this.setState({ lectures: res, loading: null, serverErr: null });
      })
      .catch(err => {
        this.setState({ serverErr: true, loading: null });
      });
  };
  render() {
    return (
      <Container fluid>
        <Row className="justify-content-md-center below-nav">
          <h3>Available Courses:</h3>
        </Row>
        {this.state.lectures.map(e => {
          return <LectureItem lecture={e} bookLeacture={this.bookLeacture} />;
        })}
      </Container>
    );
  }
}
export default AvailableCourses;

I would do some more things additionally:

  1. Make the alert look neater using MyAlert component.
  2. Add a key prop so that it works fine.
  3. Remove unnecessary fragments <></>.
  4. Remove the old constructor concept and add state.

Full optimised source:

const MyAlert = ({ children }) => (
  <Container>
    <Row>
      <Col>
        <Alert variant="primary">
          <Row>{children}</Row>
        </Alert>
      </Col>
    </Row>
  </Container>
);

const LectureItem = ({ lecture, bookLeacture }) => {
  return (
    <MyAlert>
      {lecture.booked === false && (
        <Col>
          <Button
            onClick={() => bookLeacture(lecture.lectureId)}
            variant="success"
            block
          >
            Book Now
          </Button>
        </Col>
      )}
    </MyAlert>
  );
};

class AvailableCourses extends React.Component {
  state = { lectures: [] };
  bookLeacture = id => {
    API.bookLeacture(id)
      .then(res => {
        console.log(res);
        this.setState({ lectures: res, loading: null, serverErr: null });
      })
      .catch(err => {
        this.setState({ serverErr: true, loading: null });
      });
  };
  render() {
    return (
      <Container fluid>
        <Row className="justify-content-md-center below-nav">
          <h3>Available Courses:</h3>
        </Row>
        {this.state.lectures.map((e, key) => {
          return (
            <LectureItem
              lecture={e}
              bookLeacture={this.bookLeacture}
              key={key}
            />
          );
        })}
      </Container>
    );
  }
}
export default AvailableCourses;
0

You are on track already.

You would have to do something like this on the button.

But I think you want "id" of the item passed as well, so do something like this.

<button onClick={()=>props.bookLeacture(props.lecture.id)}/>

3
  • But it is not a class component and this isn't valid right? Commented Nov 11, 2020 at 21:09
  • yes this is not class component, all this code in just 1 file
    – Neo
    Commented Nov 11, 2020 at 21:10
  • Yeah!, I didn't see that. Your solution works in that case. Commented Nov 11, 2020 at 21:10

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.