Обновление реквизита не вызывает метод componentWillReceiveProps - PullRequest
0 голосов
/ 07 августа 2020

В пользовательском интерфейсе у меня есть две кнопки, addRow и removeRow. AddRow добавляет новую строку с раскрывающимися списками, а removeRow удаляет их. По какой-то причине нажатие на строку удаления не удаляет строку из пользовательского интерфейса. Родительский класс - это функциональный компонент:

export const LimitUpdateSRCreate: React.FC<Props> = (props) => {
  const [defaultCategory, setDefaultCategory] = React.useState<string>(
    undefined
  );
  const [defaultResource, setDefaultResource] = React.useState<string>(
    undefined
  );
  const [limitFields, setLimitFields] = React.useState<ResourceLimitFields[]>(
    []
  );
 const [resourceInputRows, setResourceInputRows] = React.useState<
    ResourceInputRow[]
  >([]);

  return (
    <LimitRequestInputList
            serviceCategoryTestId="sr-service-select-id"
            resourceTestId="sr-resource-select-id"
            defaultCategory={defaultCategory}
            defaultResource={defaultResource}
            setGeneratedFields={setLimitFields}
            setResourceLimitRows={setResourceInputRows}
            rows={resourceInputRows}
            generatedFields={limitFields}
            incidentTypes={
              !!incidentTypes.response ? incidentTypes.response.data : []
            }
          />
  )
};

Компонент LimitRequestInputList - это компонент класса, который имеет кнопки addRow и removeRow:

export class LimitRequestInputList extends React.Component<Props, State> {
  constructor(props: Props) {
    super(props);
    this.state = {
      nextId : 0
    };
  }

  public componentDidMount(): void {
    this.createDefaultRow(this.props);
  }
  private createDefaultRow(otherProps: Props): void {
    if (otherProps && otherProps.incidentTypes && otherProps.incidentTypes.length && !otherProps.rows.length) {
      const firstId = 0;
      const defaultRow = [
        { id: firstId, 
          row: (
            <ResourceLimitIncreaseRow
              serviceCategoryTestId={otherProps.serviceCategoryTestId}
              resourceTestId={otherProps.resourceTestId}
              rowId={firstId}
              key={"" + firstId}
              isDefaultRow={true}
              defaultCategory={otherProps.defaultCategory}
              defaultResource={otherProps.defaultResource}
              setGeneratedFields={this.setGeneratedFields}
              formRef={otherProps.formRef}
              incidentTypes={otherProps.incidentTypes}
              removeRow={this.removeRow}
            />)
        }];
      this.addGeneratedFields(firstId);
      this.setState ({
        nextId : firstId + 1
      });
      this.props.setResourceLimitRows(defaultRow);
    }
  }

  public componentWillReceiveProps(nextProps: Props): void {
    this.createDefaultRow(nextProps);
    
  }
private addRow = (): void => {
    const newNextId = this.state.nextId + 1;
    const currentRows = this.props.rows;
    currentRows.push({ id: this.state.nextId, row: (
    <ResourceLimitIncreaseRow
      serviceCategoryTestId={this.props.serviceCategoryTestId}
      resourceTestId={this.props.resourceTestId}
      key={"" + this.state.nextId}
      rowId={this.state.nextId}
      isDefaultRow={false}
      setGeneratedFields={this.setGeneratedFields}
      formRef={this.props.formRef}
      incidentTypes={this.props.incidentTypes}
      removeRow={this.removeRow}
    />
    )});
    this.addGeneratedFields(this.state.nextId);
    this.setState({ nextId: newNextId });
    this.props.setResourceLimitRows(currentRows);
  }

  private removeRow = (rowId: number): void => {
    const rows = this.props.rows;
    const currentRow = rows ? rows.findIndex(row => row.id === rowId) : -1;
    if (currentRow !== -1) {
      rows.splice(currentRow, 1);
      this.props.setResourceLimitRows(rows);
    }
    this.removeGeneratedFields(rowId);
  }

  private addGeneratedFields = (rowId: number): void => {
    const newGeneratedFieldsRow: ResourceLimitFields = {
      id: rowId,
      serviceCategoryFieldName: ServiceCategoryFieldName + rowId,
      resourceFieldName: ResourceFieldName + rowId,
      generatedFields: []
    };
    const newGeneratedFields = this.props.generatedFields;
    newGeneratedFields.push(newGeneratedFieldsRow);
    this.props.setGeneratedFields(newGeneratedFields);
  }

  private removeGeneratedFields = (rowId: number): void => {
    const generatedFieldRows = this.props.generatedFields;
    const currentRow = generatedFieldRows ? generatedFieldRows.findIndex(row => row.id === rowId) : -1;
    if (currentRow !== -1) {
      generatedFieldRows.splice(currentRow, 1);
      this.props.setGeneratedFields(generatedFieldRows);
    }
  }

  private getResourceRows = (): JSX.Element[] => {
    const resourceRows : JSX.Element[] = this.props.rows.map(resourceRow => resourceRow.row);
    return resourceRows;
  }

  private setGeneratedFields = (resourceLimitFields: ResourceLimitFields) : void => {
    const generatedFieldRows = this.props.generatedFields;
    const currentRowIndex = generatedFieldRows ? 
    generatedFieldRows.findIndex(row => row.id === resourceLimitFields.id) : -1;
    if (currentRowIndex === -1) {
      generatedFieldRows.push(resourceLimitFields);
    } else {
      generatedFieldRows[currentRowIndex].generatedFields = resourceLimitFields.generatedFields;
    }
    this.props.setGeneratedFields(generatedFieldRows);
  }
}

Насколько я знаю, всякий раз, когда есть является изменением свойств, вызываются методы componentWillReceiveProps. В моем коде этого не происходит. Проблема в том, что родительский компонент является функциональным, а дочерний - компонентом класса. Думаю, это не должно быть так. Из-за этого нажатие кнопки удаления не удаляет строку из пользовательского интерфейса. В чем может быть причина того, что componentWillReceiveProps не вызывается? Я убедился, что значение props меняется каждый раз при нажатии кнопки.

1 Ответ

1 голос
/ 07 августа 2020

Вы изменяете свойство rows в методе удаления, лучше удалите его с помощью фильтра:

private removeRow = (rowId: number): void => {
    const rows = this.props.rows.filter(r => r.id !== rowId);

    this.props.setResourceLimitRows(rows);

    this.removeGeneratedFields(rowId);
 }

Когда вы делаете const rows = this.props.rows;, новая переменная rows по-прежнему указывает на this.props.rows и все изменения в нем отражаются на this.props.rows.

Другой способ - сделать неглубокую копию массива props через const rows = this.props.rows.concat() или const rows = this.props.rows.slice() перед изменением rows.

...