错误:我的模态组件超出了最大更新深度

问题描述

错误:超出最大更新深度。当组件重复调用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",}}>
                                  &#x25cf;
                                </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中设置一个没有新日期的日期。由于某种原因,它会加载无限循环。