У меня есть компонент с формой внутри. Поля формы зависят от состояния компонента, который обновляется в методах onChange. После нажатия кнопки отправки компонент отправляет поля формы родительскому компоненту, а затем обновляет хранилище. При вызове метода onChange возникает ошибка «Превышена максимальная глубина обновления. Это может произойти, когда компонент повторно вызывает setState внутри componentWillUpdate или componentDidUpdate. React ограничивает количество вложенных обновлений, чтобы предотвратить бесконечные циклы.»
Я не могу найти причина, по которой al oop возникает внутри компонента MemberForm.
Однако при отладке я понял, что при изменении состояния (не для функции onChange) также отображается родительский компонент AggiungiSocio. Однако состояние компонента «MemberForm» никоим образом не связано с компонентом «AggiungiSocio».
Что вызывает этот неожиданный рендеринг? Как мне избежать этого?
Странно то, что я также использую компонент "MemberForm" в компоненте "ModificaSocio", где я передаю поля формы в качестве свойств. В этом компоненте "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)
);
MemberForm
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);