问题描述
错误:超出最大更新深度。当组件重复调用componentwillUpdate或componentDidUpdate内部的setState时,可能会发生这种情况。 React限制了嵌套更新的数量,以防止无限循环。
当我的模态打开超过几秒钟时,出现上述错误。似乎是一个无限循环,但我找不到它。
const BookingsTable = ({data,setPage,parameters,setParameters,loading,setLoading}) => {
const [modalOpen,setModalOpen] = useState(false);
const [idLocation,setIdLocation]= useState('');
const [mounted,setMounted] = useState(false);
const [locationDetails,setLocationDetails] = useState('');
const session = new SessionService();
const { dataFromFetch,error } = useSWR([mounted ? `${session.domain}/external-booking/${idLocation}` : null,parameters ],url =>
session.fetch(url,{
method: 'POST',body: JSON.stringify({
parameterstocheck: parameters
})
}),{
onSuccess: (dataFromFetch) => {
setLocationDetails(dataFromFetch)
setModalOpen(true)
setLoading(false)
setMounted(false)
},onError: (err,key,config) => {
// console.log("error",err)
}
}
)
useEffect(() => {
setMounted(true)
setLoading(true)
console.log('passed in useEffect')
},[idLocation])
return (
<Fragment>
<CsstransitionGroup component="div" transitionName="TabsAnimation" transitionAppear={true}
transitionAppearTimeout={0} transitionEnter={false} transitionLeave={false}>
<Row>
<Col md="12">
<Card className="main-card mb-3">
<CardBody>
<ReactTable data={data.data}
columns={[
{
Header: "Réservation",columns: [
{
Header: "Numéro",id: 'booking_id',maxWidth: 80,accessor: (d) => d.booking.id,},{
Header: "Locataire",id: 'tenant_name',sortable: false,accessor: (d) => d.booking.user ? d.booking.user.last_name + ' ' + d.booking.user.first_name : ''
},{
Header: "Début",id: 'start_date',accessor: (d) => format(new Date(d.booking.start_date),"dd/MM/yyyy à hh'h'mm"),{
Header: "Fin",id: 'end_date',accessor: (d) => format(new Date(d.booking.end_date),}
],{
Header: "Véhicule",columns: [
{
Header: "Immat.",id: 'vehicle_registration_number',accessor: (d) => d.booking.vehicle.registration_number,{
Header: "Modèle",id: 'vehicle_model',accessor: (d) => d.booking.vehicle.brand + ' ' + d.booking.vehicle.model,sortable: false
},{
Header: "Cat.",id: 'vehicle_category',accessor: (d) => d.booking.vehicle.zc_category ? d.booking.vehicle.zc_category.name : '',],{
Header: "@R_698_4045@ions",columns: [
{
Header: "Créée le",id: 'created_at',accessor: (d) => format(new Date(d.booking.created_at),"dd/MM/yyyy"),{
Header: "Statut",id: "booking_status",accessor: (d) => d.booking.status,Cell: (row) => (
<span>
<span
style={{
color:
row.value < 30
? "#aaa"
: row.value >= 30 && row.value <= 60
? "#3ac47d"
: row.value >= 70 && row.value <= 100
? "#76C0DB"
: row.value == 120 || row.value == 130
? `#fd7e14`
: "#d92550",transition: "all .3s ease",}}>
●
</span>{" "}
{row.value == 10
? "créée"
: row.value >= 20 && row.value < 30
? `en attente de paiement`
: row.value == 30
? `confirmée`
: row.value > 30 && row.value <= 60
? `en cours`
: row.value > 60 && row.value <= 100
? `terminée`
: row.value == 110
? `refusée`
: row.value == 120 || row.value == 130
? `expirée`
: row.value > 130
? `annulée`
: '-'}
</span>
),}
]
}
]}
defaultPageSize={20}
manual
loading={loading}
loadingText="Chargement..."
nextText="Suivant"
prevIoUsText="Précédent"
noDataText="Aucune données correspondantes"
showPageSizeOptions={false}
pages={data.numberPage}
onFetchData={(state,instance) => {
setLoading(true);
const params = {...parameters,sort_by: state.sorted.length ? state.sorted[0].id + (state.sorted[0].desc ? '_desc' : '_asc') : 'id_desc'
}
console.log("onFetchData",state.page,state.filtered,state.sorted,instance);
console.log("parameters",params);
setPage(state.page);
setParameters(params);
}}
className="-striped -highlight"
getTdProps={(state,rowInfo,column,instance) => {
return {
style: {
fontSize: '12px'
},onClick: (e) => {
console.log('A Td Element was clicked!')
console.log('it produced this event:',e)
console.log('It was in this column:',column)
console.log('It was in this row:',rowInfo)
console.log('It was in this table instance:',instance)
// Router.push(`/bookings/${rowInfo.original.booking.id}`)
setLoading(true)
setIdLocation(rowInfo.original.booking.id)
}
}
}}
/>
</CardBody>
</Card>
</Col>
</Row>
</CsstransitionGroup>
{loading? null : <ModifyLocationModal locationDetails={locationDetails} isOpen={modalOpen}/>}
</Fragment>
);
}
export default BookingsTable
我的模态成分是:
export default function SimpleModal(props) {
const {isOpen,locationDetails} = props;
const materialClasses = useStyles();
const [open,setopen] = useState(false);
const handleOpen = () => {
setopen(true);
};
const handleClose = () => {
setopen(false);
};
useEffect(() => {
setopen(isOpen)
},[isOpen])
const body = (
<div className={materialClasses.paper}>
<HeaderOfModal handleClose={handleClose}/>
<LocationDetails locationDetails={locationDetails} handleChange={props.handleChange} close={handleClose}/>
</div>
);
return (
<div>
<div onClick={handleOpen}>
{props.button}
</div>
<Modal
open={open}
onClose={handleClose}
aria-labelledby="simple-modal-title"
aria-describedby="simple-modal-description"
>
{body}
</Modal>
</div>
);
}
似乎触发问题的我的模态主体是:
const LocationDetails = (props) => {
const { locationDetails } = props;
const date = new Date();
const session = new SessionService();
const company_id = localStorage.getItem('company_id')
const { formData,error } = useSWR([`${session.domain}/company/${company_id}}/external-booking-form-data`,url =>
session.fetch(url,{
method: 'GET',}),{
onSuccess: (formData) => {
setCategoryAndAgencies(formData)
setLoading(false)
},config) => {
console.log("error",err)
}
}
)
console.log(locationDetails)
const[ loading,setLoading] = useState(true);
const [categoryAndAgencies,setCategoryAndAgencies] = useState('');
const [parameters,setParameters] = useState('')
const [state,setState] = useState({
reference: locationDetails? locationDetails.data.external_booking.reference : '',source: locationDetails? locationDetails.data.external_booking.source : 'Site Web',statut: locationDetails? locationDetails.data.external_booking.status :'30',startingAgency: locationDetails? locationDetails.data.external_booking.start_agency :'5',endingAgency: locationDetails? locationDetails.data.external_booking.end_agency :'5',category: locationDetails? locationDetails.data.external_booking.vehicle_category.id :'23',vehicle: locationDetails? locationDetails.data.external_booking.vehicle.registration_number :'',totalPrice: locationDetails? locationDetails.data.external_booking.amount :'',paidPrice: locationDetails? locationDetails.data.external_booking.paid_amount :'',suppOptions: locationDetails? locationDetails.data.external_booking.options :'',driver: locationDetails && locationDetails.data.external_booking.drivers[0] ? locationDetails.data.external_booking.drivers[0].name : '',phone: locationDetails && locationDetails.data.external_booking.drivers[0] ? locationDetails.data.external_booking.drivers[0].phone_number :'',licence: locationDetails && locationDetails.data.external_booking.drivers[0] ? locationDetails.data.external_booking.drivers[0].driver_licence_number : '',countryDelivery: locationDetails && locationDetails.data.external_booking.drivers[0] ? locationDetails.data.external_booking.drivers[0].driver_licence_country : 'FR',})
const [ dates,setDates ] = useState({
startDate: locationDetails? locationDetails.data.external_booking.start_date : new Date(),endDate: locationDetails? locationDetails.data.external_booking.end_date : new Date(),obtainedDate: locationDetails && locationDetails.data.external_booking.drivers[0] ? locationDetails.data.external_booking.drivers[0].driver_licence_date : new Date(),birthDate: locationDetails && locationDetails.data.external_booking.drivers[0] ? locationDetails.data.external_booking.drivers[0].birthday : date.setFullYear( date.getFullYear() - 21 ),})
const handleChange = (e) => {
const { value } = event.target
setState({
...state,[event.target.name] : value
})
}
const handleChangeDate = (name,date) => {
setDates({
...dates,[name]: date
})
}
const handleModification = () => {
}
return (
<>
{loading ?
<Loader className={classes.Loader} color="#ffffff" active type="ball-triangle-path" />
: <div className={classes.LocationDetails}>
<h5>Détails de la location</h5>
<Form>
<div className={classes.FirstLine}>
<FormGroup className={classes.Reference}>
<Label className={classes.Label} for="reference">Référence</Label>
<Input
type="text"
name="reference"
id="reference"
placeholder="Référence de la location"
className={classes.Input}
onChange={handleChange}
value={locationDetails? locationDetails.data.external_booking.reference : state.reference}
/>
</FormGroup>
<FormGroup className={classes.source}>
<Label className={classes.Label} for="source">Source</Label>
<Input
type="select"
name="source"
id="source"
className={classes.Input}
onChange={handleChange}
value={locationDetails? locationDetails.data.external_booking.source : state.source}
>
<option>Site Web</option>
<option>Téléphone</option>
<option>Direct en agence</option>
<option>broker</option>
<option>Autre</option>
</Input>
</FormGroup>
<FormGroup className={classes.Statut}>
<Label className={classes.Label} for="statut">Statut</Label>
<Input
type="select"
name="statut"
id="statut"
className={classes.Input}
onChange={handleChange}
value={locationDetails? locationDetails.data.external_booking.status : state.statut}
>
<option value={30}>Confirmée</option>
<option value={60}>En cours</option>
<option value={100}>Terminée</option>
<option value={131}>Annulée par le pro</option>
<option value={132}>Annulée par le locataire</option>
<option value={20}>En attente de paiement</option>
</Input>
</FormGroup>
</div>
<div className={classes.SecondLine}>
<div className={classes.StartingDate}>
<label className={classes.Label}>Date de début </label>
<DatePicker
className={classes.Input}
value={state.startingDate}
name="startingDate"
onChange={(date) => handleChangeDate('startDate',date)}
showTimeSelect
selected={dates.startDate}
value={locationDetails? locationDetails.data.external_booking.start_date : dates.startDate}
timeFormat="HH:mm"
locale='fr'
timeIntervals={15}
dateFormat="d MMMM,yyyy HH:mm"
timeCaption="Time"
inputStyle={{ textAlign: 'center' }}
popperModifiers={{
flip: {
behavior: ["bottom"] // don't allow it to flip to be above
},preventOverflow: {
enabled: false // tell it not to try to stay within the view (this prevents the popper from covering the element you clicked)
},hide: {
enabled: false // turn off since needs preventOverflow to be enabled
}
}}
/>
</div>
<div className={classes.EndingDate}>
<label className={classes.Label}>Date de fin </label>
<DatePicker
className={classes.Input}
value={state.startingDate}
name="startingDate"
onChange={(date) => handleChangeDate('endDate',date)}
showTimeSelect
selected={dates.endDate}
value={locationDetails? locationDetails.data.external_booking.end_date : dates.endDate}
timeFormat="HH:mm"
locale='fr'
timeIntervals={15}
dateFormat="d MMMM,yyyy HH:mm "
timeCaption="Time"
popperModifiers={{
flip: {
behavior: ["bottom"] // don't allow it to flip to be above
},hide: {
enabled: false // turn off since needs preventOverflow to be enabled
}
}}
/>
</div>
</div>
<div className={classes.ThirdLine}>
<FormGroup className={classes.StartingAgency}>
<Label className={classes.Label} for="startingAgency">Agence de début</Label>
<Input
type="select"
name="startingAgency"
id="startingAgency"
placeholder=""
className={classes.Input}
onChange={handleChange}
value={locationDetails? locationDetails.data.external_booking.start_agency : state.startingAgency}
>
{categoryAndAgencies.data.form_data.agencies.map((element,index) => {
return <option key={index} value={element.id}>{element.name} - {element.code}</option>
})}
</Input>
</FormGroup>
<FormGroup className={classes.EndingAgency}>
<Label className={classes.Label} for="endingAgency">Agence de fin</Label>
<Input
type="select"
name="endingAgency"
id="endingAgency"
placeholder=""
className={classes.Input}
onChange={handleChange}
value={locationDetails? locationDetails.data.external_booking.end_agency : state.endingAgency}
>
{categoryAndAgencies.data.form_data.agencies.map((element,index) => {
return <option key={index} value={element.id}>{element.name} - {element.code}</option>
})}
</Input>
</FormGroup>
</div>
<div className={classes.FourthLine}>
<FormGroup className={classes.Category}>
<Label className={classes.Label} for="category">Catégorie</Label>
<Input
type="select"
name="category"
id="category"
className={classes.Input}
onChange={handleChange}
value={locationDetails? locationDetails.data.external_booking.vehicle_category.id :state.category}
>
{categoryAndAgencies.data.form_data.vehicle_categories.map((element,index) => {
return <option key={index} value={element.id}>{element.display_name}</option>
})}
</Input>
</FormGroup>
<FormGroup className={classes.Vehicle}>
<Label className={classes.Label} for="vehicle">Véhicule</Label>
<Input
type="text"
name="vehicle"
id="vehicle"
placeholder=""
className={classes.Input}
onChange={handleChange}
value={locationDetails? locationDetails.data.external_booking.vehicle.registration_number : state.vehicle}
/>
</FormGroup>
</div>
<div className={classes.FifthLine}>
<FormGroup className={classes.TotalPrice}>
<Label className={classes.Label} for="totalPrice">Prix total</Label>
<Input
type="text"
name="totalPrice"
id="totalPrice"
placeholder=""
className={classes.Input}
onChange={handleChange}
value={ locationDetails? locationDetails.data.external_booking.amount : state.totalPrice}
/>
</FormGroup>
<FormGroup className={classes.PaidPrice}>
<Label className={classes.Label} for="paidPrice">Somme payée</Label>
<Input
type="text"
name="paidPrice"
id="paidPrice"
placeholder=""
className={classes.Input}
onChange={handleChange}
value={locationDetails? locationDetails.data.external_booking.paid_amount : state.paidPrice}
/>
</FormGroup>
<FormGroup className={classes.SuppOptions}>
<Label className={classes.Label} for="suppOptions">Options supplémentaires</Label>
<Input
type="select"
name="suppOptions"
id="suppOptions"
className={classes.Input}
onChange={handleChange}
value={locationDetails? locationDetails.data.external_booking.options : state.suppOptions}
>
<option>Options</option>
<option>2</option>
<option>3</option>
<option>4</option>
<option>5</option>
</Input>
</FormGroup>
</div>
<h5>Conducteur principal</h5>
<div className={classes.SixthLine}>
<FormGroup className={classes.Driver}>
<Label className={classes.Label} for="driver">Conducteur</Label>
<Input
type="text"
name="driver"
id="driver"
placeholder=""
className={classes.Input}
onChange={handleChange}
value={locationDetails && locationDetails.data.external_booking.drivers[0] ? locationDetails.data.external_booking.drivers[0].name :state.driver}
/>
</FormGroup>
<FormGroup className={classes.Phone}>
<Label className={classes.Label} for="phone">Téléphone</Label>
<Input
type="text"
name="phone"
id="phone"
placeholder=""
className={classes.Input}
onChange={handleChange}
value={state.phone}
/>
</FormGroup>
</div>
<hr />
<div className={classes.BtnContainer}>
<div className={classes.Btn} onClick={handleModification}>Enregistrer</div>
</div>
</Form>
</div>}
</>
)
}
export default LocationDetails;
解决方法
问题是在react datepicker中设置一个没有新日期的日期。由于某种原因,它会加载无限循环。