Передача данных между реагирующими компонентами - PullRequest
5 голосов
/ 17 января 2020

Я пытаюсь сделать простой календарь. В моем календаре есть компонент «День», «Имена дней», «Месяц» и «Месяцы», и все, к чему я обращаюсь в основном календаре. При начальной загрузке будет отображаться календарь на текущий месяц.

Теперь, когда я выбираю месяц из компонента имени месяца, хочу передать компоненту месяца, а затем перейти к компоненту дня для отображения дат.

Я пытаюсь использовать функцию обратного вызова, но это не помогает мне

Весь компонент реакции здесь 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)
  }
}

Ответы [ 2 ]

3 голосов
/ 17 января 2020

Смотрите этот бит: <MonthNames changeMonthComponent={() => this.showDays(this.state.monthNo)} />

и этот бит: this.props.changeMonthComponent(showComponent.Days, monthNo)

Проблема в том, что внутренний компонент вызывает функцию changeMonthComponent, но аргументы отбрасываются родитель. Компонент MonthNames должен что-то делать с передачей аргументов обратно:

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

(Грубо говоря, я не копаюсь во всех аспектах вашего кода, поэтому я не точно знать, что вы хотите сделать с параметром days, который мое предложение игнорирует.)

0 голосов
/ 17 января 2020

Я решил свою проблему, с помощью ** см. Резче ** и спасибо поддержки и голосов.

Теперь вернемся к моей проблеме. Мой календарь изначально загружался правильно, но когда я меняю месяц и год в компоненте MonthName (то есть дочернем компоненте), переходите к DayPickerMonths (т.е. родительскому компоненту), а затем до компонента Calendar (т.е. родительского компонента), затем до компонента DatePickerDays (т.е. дочернего) компонент для календаря и брат для DayPickerMonths)

Визуально выглядит так enter image description here

Итак, начните с дочернего элемента (т. е. 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)
  }

Календарь (т. Е. Дедушка)

<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 (т. Е. Дочерний элемент для календаря и брат для 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

Но все же есть проблема, что , когда год является изменением в компоненте DayPickerDays, это не отражало в DayPickerMonths и обременительны для передачи данных, мы должны se Реагирует на контекст , чтобы сделать его глобальным и простым. Я скоро обновлю этот ответ, как только сделаю провайдера, так как мне нужно go на прием к врачу для проверки моих глаз

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...