Neo
Neo

Reputation: 119

passing function in React Js

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;

Upvotes: 0

Views: 58

Answers (2)

Arun Shankar
Arun Shankar

Reputation: 89

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)}/>

Upvotes: 0

Praveen Kumar Purushothaman
Praveen Kumar Purushothaman

Reputation: 167162

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;

Upvotes: 1

Related Questions