在 React 组件之间传递数据

Passing Data between react components

我正在尝试制作简单的日历。在我的日历中,我有日期、日期名称、月份和月份名称组件以及我在主日历上访问它的所有内容。初始加载时,它将显示当前月份的日历。

现在,当我 select month from month-name component 想要传递给 month component 然后传递给 day component 以呈现日期时。

我尝试使用回调函数,但它没有帮助我

完整的 React 组件在这里 https://stackblitz.com/edit/react-ts-z2278r

Day component

import * as moment from 'moment'
import * as React from 'react'

import { showComponent } from '../../../../models'
import { MonthNames } from './'
import styles from './Calendar.module.scss'

interface IDatePickerMonthsProps {
  changeMonthComponent: (showComponent: showComponent, monthNo: number) => void
}

interface IDatePickerMonthsState {
  dateObject: moment.Moment,
  monthNo?: number
}

export class DatePickerMonths extends React.Component<IDatePickerMonthsProps, IDatePickerMonthsState> {

  constructor(props: IDatePickerMonthsProps) {
    super(props)
    this.state = {
      dateObject: moment()
    }
  }

  public render() {
    const monthPicker =
      <div className="datepicker-days">
        <table className={styles.table}>
          <thead>
            <tr>
              <th><span className="ms-Icon ms-Icon--ChevronLeft" title="Previous Month" onClick={this.onPrev}></span></th>
              <th className={styles["picker-switch"]} data-action="pickerSwitch" colSpan={5} title="Select Month">
                {this.year()}
              </th>
              <th><span className="ms-Icon ms-Icon--ChevronRight" title="Next Month" onClick={this.onNext}></span></th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td colSpan={7}>
                <MonthNames changeMonthComponent={() => this.showDays(this.state.monthNo)} />
              </td>
            </tr>
          </tbody>
        </table>
      </div>

    return (monthPicker)
  }

  private year = () => {
    return this.state.dateObject.format("Y");
  };

  private onPrev = () => {
    this.setState({
      dateObject: this.state.dateObject.subtract(1, "year")
    });
  };
  private onNext = () => {
    this.setState({
      dateObject: this.state.dateObject.add(1, "year")
    });
  };

  private showDays = (monthNo: number) => {
    console.log(monthNo)
    this.setState({ monthNo: monthNo })
    this.props.changeMonthComponent(showComponent.Days, monthNo)
  }
}

Month name component

import * as moment from 'moment'
import * as React from 'react'

import { showComponent } from '../../../../models'

interface IMonthNamesProps {
  changeMonthComponent: (showComponent: showComponent, monthNo: number) => void
}

export class MonthNames extends React.Component<IMonthNamesProps, {}> {
  private monthshort: string[] = moment.monthsShort();

  constructor(props: IMonthNamesProps) {
    super(props)
  }

  public render() {
    let monthshortname = this.monthshort.map((month, monthNo) => {
      return <span key={monthNo} onClick={() => this.showDays(monthNo)}>{month}</span>;
    });
    return monthshortname
  }

  private showDays = (monthNo: number) => {
    this.props.changeMonthComponent(showComponent.Days, monthNo)
  }
}

Month component

import * as moment from 'moment'
import * as React from 'react'

import { showComponent } from '../../../../models'
import { MonthNames } from './'
import styles from './Calendar.module.scss'

interface IDatePickerMonthsProps {
  changeMonthComponent: (showComponent: showComponent, monthNo: number) => void
}

interface IDatePickerMonthsState {
  dateObject: moment.Moment,
  monthNo?: number
}

export class DatePickerMonths extends React.Component<IDatePickerMonthsProps, IDatePickerMonthsState> {

  constructor(props: IDatePickerMonthsProps) {
    super(props)
    this.state = {
      dateObject: moment()
    }
  }

  public render() {
    const monthPicker =
      <div className="datepicker-days">
        <table className={styles.table}>
          <thead>
            <tr>
              <th><span className="ms-Icon ms-Icon--ChevronLeft" title="Previous Month" onClick={this.onPrev}></span></th>
              <th className={styles["picker-switch"]} data-action="pickerSwitch" colSpan={5} title="Select Month">
                {this.year()}
              </th>
              <th><span className="ms-Icon ms-Icon--ChevronRight" title="Next Month" onClick={this.onNext}></span></th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td colSpan={7}>
                <MonthNames changeMonthComponent={() => this.showDays(this.state.monthNo)} />
              </td>
            </tr>
          </tbody>
        </table>
      </div>

    return (monthPicker)
  }

  private year = () => {
    return this.state.dateObject.format("Y");
  };

  private onPrev = () => {
    this.setState({
      dateObject: this.state.dateObject.subtract(1, "year")
    });
  };
  private onNext = () => {
    this.setState({
      dateObject: this.state.dateObject.add(1, "year")
    });
  };

  private showDays = (monthNo: number) => {
    console.log(monthNo)
    this.setState({ monthNo: monthNo })
    this.props.changeMonthComponent(showComponent.Days, monthNo)
  }
}

看到这个位:<MonthNames changeMonthComponent={() => this.showDays(this.state.monthNo)} />

还有这个位:this.props.changeMonthComponent(showComponent.Days, monthNo)

问题是内部组件调用函数changeMonthComponent,但是参数被父级丢弃了。 MonthNames 组件需要对传回的参数做一些事情:

<MonthNames changeMonthComponent={(days, monthNo) => this.showDays(monthNo)} />

(大致 - 我没有深入研究您的代码的所有方面,所以我不知道您想对我的建议忽略的 days 参数做什么。)

在 **see sharper ** 的帮助下,我已经解决了我的问题,感谢支持和投票。

现在回到我的问题。我的日历最初加载正确,但是当我在 MonthName 组件(即 child 组件)中更改月份和年份时,传递到 DayPickerMonths(即 parent 组件),然后传递到日历组件(即 grand parent 组件)然后向下到 DatePickerDays 组件(即 child 组件到 Calendar & sibling to DayPickerMonths)

视觉上看起来像这样

所以从 child 开始(即 MonthName)

函数

private showDays = (monthNo: number) => {
    this.props.changeMonthComponent(monthNo)
  }

在渲染中调用

public render() {
    let monthshortname = this.monthshort.map((month, monthNo) => {
      return <span key={monthNo} onClick={() => this.showDays(monthNo)}>{month}</span>;
    });
    return monthshortname
  }

DayPickerMonths(即 Parent)

<MonthNames changeMonthComponent={(monthNo) => this.showDays(monthNo, this.state.dateObject.year())} />

private showDays = (monthNo: number, year: number) => {
    this.props.changeMonthComponent(showComponent.Days, monthNo, year)
  }

日历(即盛大Parent)

<DatePickerMonths
              changeMonthComponent={(childData, monthNo, year) => this.changeMonthComponent(childData, monthNo, year)} />

private changeMonthComponent = (childData: showComponent, monthNo: number, year: number) => {
    this.setState({ showComponent: childData, monthNo: monthNo, year: year })
  }

DayPickerDays(即 Child 到日历和同级到 DayPicker)

private showMonths = () => {
    this.props.changeComponent(showComponent.Months)
  }
public componentDidMount() {
    this.setState({ dateObject: this.state.dateObject.month(this.props.monthNo).year(this.props.year) })
  }

我已经在这里更新了我的 https://stackblitz.com/edit/react-ts-z2278r

But still it have issue that when year is change in DayPickerDays component it did not reflect in DayPickerMonths and cumbersome to pass data, we should use React context to make it global and simple. I will soon update this answer once I will make provider as I need to go for doctor appoinment for my eyes checkup