如何在 Reactjs 中从外部调用主组件内部的方法

How to call method inside main Component from outside in Reactjs

我需要使用来自 popover 内的 Button onClick 的参数调用 cancelMethod。但是我无法访问此方法。你能解释一下是否可以访问。如果是,我该怎么做?

const popover = (
  <Popover id="popover-basic">
    <Popover.Title as="h3">Cancel reservation</Popover.Title>
    <Popover.Content>
     for <strong>canceling</strong> course. Click here:
     <Button onClick={cancelMethod()} variant='danger'>Cancel</Button>
    </Popover.Content>
  </Popover>
);

const Event = ({event}) => (
  <OverlayTrigger trigger="click" placement="top" overlay={popover}>
    <Button 
     style={{background:"transparent", border:"none"}}
    >{event.title} <br/> Lecture Room:{event.room}<br/> Teacher: {event.instructor}</Button>
  </OverlayTrigger>
);


export default class NewCalendarView extends Component {

  cancelMethod(id){
    alert("Hello"+id);
  }

  componentDidMount() {
    API.getLectures().then((res)=>{
      console.log(res)
       const cal=res.map((lec)=>{
         let lecture= {
           instructor: lec.teacherName,
          room: lec.room,
          title: lec.subject,
          startDate : moment(lec.date+"T"+lec.hour).toDate(),
          endDate:  moment(lec.date+"T"+lec.hour+"-02:00").toDate()
          }   
          return lecture;
      })
          this.setState({events:cal,loading:null,serverErr:null})
    }).catch((err)=>{
        this.setState({serverErr:true,loading:null})
    })
}
  constructor(props) {
    super(props);

    this.state = {
       events: []
    }
  }

  render() {
    return (
      <div style={{
        flex: 1
      }}>
        {console.log(this.state.events)}

        <Calendar
          localizer={localizer}
          events={this.state.events}
          startAccessor='startDate'
          endAccessor='endDate'
          defaultView='week'
          views={['month', 'week', 'day']}
          culture='en'
          components={{
            event: Event
          }}

          />
      </div>
    );
  }
}

您可以在class中定义函数Popover和Event,并使用此关键字调用函数。

export default class NewCalendarView extends Component {
  cancelMethod(id){
    alert("Hello"+id);
  }

  componentDidMount() {
    API.getLectures().then((res)=>{
      console.log(res)
       const cal=res.map((lec)=>{
         let lecture= {
           instructor: lec.teacherName,
          room: lec.room,
          title: lec.subject,
          startDate : moment(lec.date+"T"+lec.hour).toDate(),
          endDate:  moment(lec.date+"T"+lec.hour+"-02:00").toDate()
          }   
          return lecture;
      })
          this.setState({events:cal,loading:null,serverErr:null})
    }).catch((err)=>{
        this.setState({serverErr:true,loading:null})
    })
}
  constructor(props) {
    super(props);

    this.state = {
       events: []
    }
  }

Popover = (
  <Popover id="popover-basic">
    <Popover.Title as="h3">Cancel reservation</Popover.Title>
    <Popover.Content>
     for <strong>canceling</strong> course. Click here:
     <Button onClick={cancelMethod()} variant='danger'>Cancel</Button>
    </Popover.Content>
  </Popover>
);

Event = ({event}) => (
  <OverlayTrigger trigger="click" placement="top" overlay={this.popover}>           // added the this keyword
    <Button 
     style={{background:"transparent", border:"none"}}
    >{event.title} <br/> Lecture Room:{event.room}<br/> Teacher: {event.instructor}</Button>
  </OverlayTrigger>
);

  render() {
    return (
      <div style={{
        flex: 1
      }}>
        {console.log(this.state.events)}

        <Calendar
          localizer={localizer}
          events={this.state.events}
          startAccessor='startDate'
          endAccessor='endDate'
          defaultView='week'
          views={['month', 'week', 'day']}
          min={new Date(2020, 1, 0, 7, 0, 0)} 
          max={new Date(2022, 1, 0, 21, 0, 0)}
          culture='en'
          components={{
            event: this.Event           // added the this keyword
          }}

          />
      </div>
    );
  }
}

一种方法是将它作为 prop 传递给 popover(我将其重命名为 PopoverInstance,因为 Popover 已经被采用)。不幸的是,这有一个副作用,那就是必须将道具向下钻两层(而不是直接向下一层)。另一种方法是引入管理状态和方法的外部状态(如 Context 或 Redux)。这肯定有助于螺旋钻井。

如果cancelMethod只用在这个弹窗中,你也可以考虑把它移到那里。

另外我不确定日历是如何工作的,所以当您查看我在下面设置的示例时请考虑到这一点。

const PropoverInstance = ({cancelMethod}) => (
  <Popover id="popover-basic">
    <Popover.Title as="h3">Cancel reservation</Popover.Title>
    <Popover.Content>
     for <strong>canceling</strong> course. Click here:
     <Button onClick={cancelMethod()} variant='danger'>Cancel</Button>
    </Popover.Content>
  </Popover>
);

const Event = ({event, cancelMethod}) => (
  <OverlayTrigger trigger="click" placement="top" overlay={<PopoverInstance cancelMethod={cancelMethod} />}>
    <Button 
     style={{background:"transparent", border:"none"}}
    >{event.title} <br/> Lecture Room:{event.room}<br/> Teacher: {event.instructor}</Button>
  </OverlayTrigger>
);


export default class NewCalendarView extends Component {

  cancelMethod(id){
    alert("Hello"+id);
  }

  componentDidMount() {
    API.getLectures().then((res)=>{
      console.log(res)
       const cal=res.map((lec)=>{
         let lecture= {
           instructor: lec.teacherName,
          room: lec.room,
          title: lec.subject,
          startDate : moment(lec.date+"T"+lec.hour).toDate(),
          endDate:  moment(lec.date+"T"+lec.hour+"-02:00").toDate()
          }   
          return lecture;
      })
          this.setState({events:cal,loading:null,serverErr:null})
    }).catch((err)=>{
        this.setState({serverErr:true,loading:null})
    })
}
  constructor(props) {
    super(props);

    this.state = {
       events: []
    }
  }

  render() {
    return (
      <div style={{
        flex: 1
      }}>
        {console.log(this.state.events)}

        <Calendar
          localizer={localizer}
          events={this.state.events}
          startAccessor='startDate'
          endAccessor='endDate'
          defaultView='week'
          views={['month', 'week', 'day']}
          culture='en'
          components={{
            event: <Event event={???} cancelMethod={cancelMethod} />
          }}

          />
      </div>
    );
  }
}