反应-从onChange更改状态时发生无限循环

时间:2020-03-28 18:12:49

标签: reactjs forms react-redux

我有一个内部带有表单的组件。表单的字段取决于在onChange方法中更新的组件的状态。单击提交按钮后,组件会将表单字段发送到父组件,然后更新商店。调用onChange方法时,错误“超出最大更新深度。当组件重复调用componentWillUpdate或componentDidUpdate内部的setState时,可能会发生此错误。React限制嵌套更新的数量以防止无限循环。”
我找不到“ MemberForm”组件内发生循环的原因。 但是,通过调试,我了解到在状态更改时(而不是onChange函数),还会呈现父组件“ AggiungiSocio”。但是,“ MemberForm”组件的状态与“ AggiungiSocio”组件无关。
是什么导致这种意外的渲染?如何避免呢?

奇怪的是,我还使用了“ ModificaSocio”组件中的“ MemberForm”组件,在其中我将表单字段作为属性传递。在此组件“ ModificaSocio”中,一切正常。

回顾
AddSocio -> MemberForm 不起作用
EditSocio -> MemberForm 有效

AggiungiSocio

import React, { Component, Fragment } from "react";
import {
  Row,
  Card,
  CardBody,
  CardTitle,
  CardSubtitle,
} from "reactstrap";
import IntlMessages from "../../../helpers/IntlMessages";
import { Colxx } from "../../../components/common/CustomBootstrap";
import MemberForm from "../../../containers/form/MemberForm";
import {injectIntl} from "react-intl";
import {connect} from "react-redux";
import {addMemberDetail} from "../../../redux/memberDetail/actions";
import {Socio} from "../../../models/socio";

class AggiungiSocio extends Component {
  constructor(props) {
    super(props);
  }

  aggiungiSocio = (socio) => {
    console.log(socio);
    this.props.addMemberDetail(socio);
  };

  render() {
    console.log("render aggiungi socio");
    const {
      loading
    } = this.props.memberDetail;
    return (
      <Fragment>
        <Row className="mb-4">
          <Colxx xxs="12">
            <Card>
              <CardBody>
                <CardTitle>
                  <IntlMessages id="pages.member.add-member"/>
                </CardTitle>
                <CardSubtitle>
                  <IntlMessages id="pages.member.add-member-description"/>
                </CardSubtitle>
                {loading ? (
                  <MemberForm onSubmit={this.aggiungiSocio}/>
                ) : (
                  <div className="loading"/>
                )
                }
              </CardBody>
            </Card>
          </Colxx>
        </Row>
      </Fragment>
    )
  }
}

const mapStateToProps = ({memberDetail}) => {
  return {
    memberDetail
  };
};
export default injectIntl(
  connect(
    mapStateToProps,
    {
      addMemberDetail
    }
  )(AggiungiSocio)
);

ModificaSocio

import React, { Component, Fragment } from "react";
import {
  Row,
  Card,
  CardBody,
  CardTitle
} from "reactstrap";
import IntlMessages from "../../../helpers/IntlMessages";
import { Colxx } from "../../../components/common/CustomBootstrap";
import "react-datepicker/dist/react-datepicker.css";
import MemberForm from "../../../containers/form/MemberForm";
import {injectIntl} from "react-intl";
import {connect} from "react-redux";
import {getMemberDetail, editMemberDetail} from "../../../redux/memberDetail/actions";

class ModificaSocio extends Component {
  constructor(props) {
    super(props);
    this.state = {
    };
  }
  modificaSocio = (socio) => {
    this.props.editMemberDetail(socio);
  }
  render() {
    const {
      member,
      loading
    } = this.props.memberDetail;
    return (
      <Fragment>
        <Row className="mb-4">
          <Colxx xxs="12">
            <Card>
              <CardBody>
                <CardTitle>
                  <IntlMessages id="pages.member.edit-member"/>
                </CardTitle>
                {loading ? (
                  <MemberForm member={member} onSubmit={this.modificaSocio}/>
                ): (
                  <div className="loading" />
                )
                }
              </CardBody>
            </Card>
          </Colxx>
        </Row>
      </Fragment>
    )
  }
}

const mapStateToProps = ({memberDetail}) => {
  return {
    memberDetail
  };
};
export default injectIntl(
  connect(
    mapStateToProps,
    {
      editMemberDetail,
      getMemberDetail
    }
  )(ModificaSocio)
);

会员表格

import React, { Component } from "react";
import {
  Input,
  FormGroup,
  Label,
  Button,
  Form
} from "reactstrap";
import IntlMessages from "../../helpers/IntlMessages";
import DatePicker from "react-datepicker";
import "react-tagsinput/react-tagsinput.css";
import "react-datepicker/dist/react-datepicker.css";
import "rc-switch/assets/index.css";
import "rc-slider/assets/index.css";
import "react-rater/lib/react-rater.css";
import { Colxx } from "../../components/common/CustomBootstrap";
import Select from "react-select";
import CustomSelectInput from "../../components/common/CustomSelectInput";
import moment from "moment";
import {Socio} from "../../models/socio";

class MemberForm extends Component {
  constructor(props) {
    super(props);
    moment.locale("it");
    this.state = {
      member: (typeof this.props.member === 'undefined') ? Socio : this.props.member,
      selectQualifica: [{
        label: (typeof this.props.member === 'undefined') ? '' : this.props.member.qualifica,
        value: (typeof this.props.member === 'undefined') ? '' : this.props.member.qualifica
      }],
      selectTitolo: [{
        label: (typeof this.props.member === 'undefined') ? '' : this.props.member.titolo,
        value: (typeof this.props.member === 'undefined') ? '' : this.props.member.titolo
      }],
      dataDiNascita: moment((typeof this.props.member === 'undefined') ? null : this.props.member.dataDiNascita, "DD/MM/YYYY"),
      dataRichiestaIscrizione: moment((typeof this.props.member === 'undefined') ? null : this.props.member.dataRichiestaIscrizione, "DD/MM/YYYY"),
      dataAccettazione: moment((typeof this.props.member === 'undefined') ? null : this.props.member.dataAccettazione, "DD/MM/YYYY")
    }
  }

  handleChangeQualifica = qualifica => {
    this.setState({
      member: {
        ...this.state.member,
        qualifica: qualifica.value
      },
      selectQualifica: [{
        label: qualifica.value,
        value: qualifica.value
      }]
    });
  }
  handleChangeTitolo = titolo => {
    this.setState({
      member: {
        ...this.state.member,
        titolo: titolo.value
      },
      selectTitolo: [{
        label: titolo.value,
        value: titolo.value
      }]
    });
  }
  handlerChange = event => {
    const name = event.target.name;
    const value = event.target.value;
    if (value!=this.state.member[name]) {
      console.log("il valore è cambiato, aggiorno stato");
      console.log(value, this.state.member[name]);
      this.setState({
        member: {
          ...this.state.member,
          [name]: value
        }
      });
    } else {
      console.log("il valore è lo stesso!, non aggiorno stato");
      console.log(value, this.state.member[name]);
    }
  }
  handleChangeDataNascita = date => {
    this.setState({
      member: {
        ...this.state.member,
        dataDiNascita: date.format("DD/MM/YYYY")
      },
      dataDiNascita: date
    });
  };
  handleChangeDataRichiestaIscrizione = date => {
    this.setState({
      member: {
        ...this.state.member,
        dataRichiestaIscrizione: date.format("DD/MM/YYYY")
      },
      dataRichiestaIscrizione: date
    });
  };
  handleChangeDataAccettazione = date => {
    this.setState({
      member: {
        ...this.state.member,
        dataAccettazione: date.format("DD/MM/YYYY")
      },
      dataAccettazione: date
    });
  };
  handleSubmit = () => {
    this.props.onSubmit(this.state.member);
  }

  render () {
    console.log("render memberform");
    const {
      member,
      selectQualifica,
      selectTitolo,
      dataDiNascita,
      dataRichiestaIscrizione,
      dataAccettazione
    } = this.state;
    return (
      (member &&
        <Form>
          <FormGroup row>
            <Colxx sm={2}>
              <FormGroup>
                <Label for="memberTitle">
                  <IntlMessages id="member.idSocio"/>
                </Label>
                <Input
                  disabled
                  readOnly
                  type="text"
                  name="memberId"
                  id="memberId"
                  defaultValue={member.numeroSocio}
                />
              </FormGroup>
            </Colxx>
            <Colxx sm={2}>
              <FormGroup>
                <Label for="memberTitle">
                  <IntlMessages id="member.title"/>
                </Label>
                <Select
                  components={{Input: CustomSelectInput}}
                  className="react-select"
                  classNamePrefix="react-select"
                  name="form-field-name"
                  id="memberTitle"
                  options={[
                    {label: "Sig", value: "Sig", key: 0},
                    {label: "Sig.ra", value: "Sig.ra", key: 1}
                  ]}
                  value={selectTitolo}
                  onChange={this.handleChangeTitolo.bind(this)}
                />
              </FormGroup>
            </Colxx>
            <Colxx sm={3}>
              <Label for="memberName">
                <IntlMessages id="member.name"/>
              </Label>
              <Input
                type="text"
                name="nome"
                id="memberName"
                value={member.nome}
                onChange={this.handlerChange.bind(this)}
              />
            </Colxx>
            <Colxx sm={3}>
              <Label for="memberSurname">
                <IntlMessages id="member.surname"/>
              </Label>
              <Input
                type="text"
                name="cognome"
                id="memberSurname"
                value={member.cognome}
                onChange={this.handlerChange.bind(this)}
              />
            </Colxx>
            <Colxx sm={2}>
              <Label for="memberSurname">
                <IntlMessages id="member.birthday"/>
              </Label>
              <DatePicker
                dateFormat="DD/MM/YYYY"
                selected={dataDiNascita}
                onChange={this.handleChangeDataNascita.bind(this)}
                id="memberBirthday"/>
            </Colxx>
          </FormGroup>

          <FormGroup row>
            <Colxx sm={3}>
              <FormGroup>
                <Label for="birth-comune">
                  <IntlMessages id="member.birth-comune"/>
                </Label>
                <Input
                  type="text"
                  name="comuneDiNascita"
                  id="birth-comune"
                  onChange={this.handlerChange.bind(this)}
                  value={member.comuneDiNascita}
                />
              </FormGroup>
            </Colxx>
            <Colxx sm={2}>
              <FormGroup>
                <Label for="birth-provincia">
                  <IntlMessages id="member.birth-provincia"/>
                </Label>
                <Input
                  type="text"
                  name="provinciaDiNascita"
                  id="birth-provincia"
                  onChange={this.handlerChange.bind(this)}
                  value={member.provinciaDiNascita}
                />
              </FormGroup>
            </Colxx>
            <Colxx sm={4}>
              <FormGroup>
                <Label for="residential-address">
                  <IntlMessages id="member.residential-address"/>
                </Label>
                <Input
                  type="text"
                  name="indirizzoDiResidenza"
                  id="residential-address"
                  onChange={this.handlerChange.bind(this)}
                  value={member.indirizzoDiResidenza}
                />
              </FormGroup>
            </Colxx>
            <Colxx sm={3}>
              <FormGroup>
                <Label for="codice-fiscale">
                  <IntlMessages id="member.codice-fiscale"/>
                </Label>
                <Input
                  type="text"
                  name="codiceFiscale"
                  id="codice-fiscale"
                  onChange={this.handlerChange.bind(this)}
                  value={member.codiceFiscale}
                />
              </FormGroup>
            </Colxx>
          </FormGroup>

          <FormGroup row>
            <Colxx sm={3}>
              <FormGroup>
                <Label for="data-richiesta-iscrizione">
                  <IntlMessages id="member.data-richiesta-iscrizione"/>
                </Label>
                <DatePicker
                  dateFormat="DD/MM/YYYY"
                  selected={dataRichiestaIscrizione}
                  onChange={this.handleChangeDataRichiestaIscrizione.bind(this)}
                  id="data-richiesta-iscrizione"/>
              </FormGroup>
            </Colxx>
            <Colxx sm={3}>
              <FormGroup>
                <Label for="data-accettazione">
                  <IntlMessages id="member.data-accettazione"/>
                </Label>
                <DatePicker
                  dateFormat="DD/MM/YYYY"
                  selected={dataAccettazione}
                  onChange={this.handleChangeDataAccettazione.bind(this)}
                  id="data-accettazione"/>
              </FormGroup>
            </Colxx>
            <Colxx sm={3}>
              <FormGroup>
                <Label for="payment">
                  <IntlMessages id="member.payment"/>
                </Label>
                <Input
                  type="text"
                  name="quotaVersata"
                  id="payment"
                  onChange={this.handlerChange.bind(this)}
                  value={member.quotaVersata}
                />
              </FormGroup>
            </Colxx>
            <Colxx sm={3}>
              <FormGroup>
                <Label for="qualification">
                  <IntlMessages id="member.qualification"/>
                </Label>
                <Select
                  components={{Input: CustomSelectInput}}
                  className="react-select"
                  classNamePrefix="react-select"
                  name="form-field-name"
                  id="qualification"
                  options={[
                    {label: "Socio", value: "Socio", key: 0},
                    {label: "Socio Fondatore", value: "Socio Fondatore", key: 1},
                    {label: "Consigliere", value: "Consigliere", key: 2}
                  ]}
                  value={selectQualifica}
                  onChange={this.handleChangeQualifica}
                />
              </FormGroup>
            </Colxx>
          </FormGroup>

          <Button color="primary" onClick={this.handleSubmit.bind(this)}>
            <IntlMessages id="pages.member.save"/>
          </Button>
        </Form>
      )
    )
  }
}
export default React.memo(MemberForm);

1 个答案:

答案 0 :(得分:0)

您不能将参数传递给函数之外的函数。

正确:

< ... onChange={function} />

不正确:

< ... onChange={function(params)} />

要使用参数,您需要将函数嵌套在匿名函数中:

< ... onChange={() => function(params)} />

如果您要编写此代码:

< ... onChange={() => this.handlerChange.bind(this)} />