Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix performance issue with composeValidators #6092

Merged
merged 1 commit into from
Mar 29, 2021

Conversation

djhi
Copy link
Collaborator

@djhi djhi commented Mar 29, 2021

Fixes #6075

@djhi djhi added the RFR Ready For Review label Mar 29, 2021
@djhi djhi added this to the 3.14 milestone Mar 29, 2021
@fzaninotto fzaninotto merged commit 5b93fef into master Mar 29, 2021
@fzaninotto fzaninotto deleted the fix-compose-validators branch March 29, 2021 15:48
@IoanBucur
Copy link

Thank you. Next time I'll try to come up with a PR instead of just reporting 🙂.

@ghost
Copy link

ghost commented Mar 31, 2021

Hi sorry for bringing this up again but after I updated the package to 3.14.1 my form is still slow with even a single validator but works fine without andy validators.

import * as React from 'react';
import { useState } from 'react';
import {
  TextInput,
  NumberInput,
  required,
  DateInput,
  FormDataConsumer,
  SelectInput,
  ReferenceInput,
  AutocompleteInput,
  useGetOne,
  ImageInput,
  ImageField,
} from 'react-admin';
import { useFormState } from 'react-final-form';

import { Typography, Box } from '@material-ui/core';
import { makeStyles, Theme } from '@material-ui/core/styles';
import { Styles } from '@material-ui/styles/withStyles';
import axios from 'axios';
import CarLocationInput from './CarLocationInput';
import CarStatusInput from './CarStatusInput';
import { ApiModels } from '../types';
import { CarLocation, CarStatus } from './types';

export const styles: Styles<Theme, any> = {
  input: { display: 'inline-block', marginRight: 32, width: 200 },
};

const useStyles = makeStyles(styles);

export const CarsForm = (props: any) => {
  const classes = useStyles(props);
  const { values } = useFormState();
  const [initialStatus] = useState(values.status);
  const [currentVin, setCurrentVin] = useState('empty');
  const [vinDetails, setVinDetails] = useState({
    vehicleDetails: {
      ccmTech: '',
      constructionType: '',
      cylinder: '',
      cylinderCapacityCcm: '',
      cylinderCapacityLiter: '',
      fuelType: '',
      fuelTypeProcess: '',
      impulsionType: '',
      manuId: '',
      manuName: '',
      modId: '',
      modelName: '',
      motorType: '',
      year: '',
      powerHpFrom: '',
      powerHpTo: '',
      powerKwFrom: '',
      powerKwTo: '',
      typeName: '',
      typeNumber: '',
      valves: '',
      yearOfConstrFrom: '',
      rmiTypeId: '',
    },
  });

  const [submodelSelected, setSubmodelSelected] = useState('');
  const { data: selectedSubmodel } = useGetOne(ApiModels.submodels, submodelSelected);

  const requiredValidate = [required()];

  const SectionTitle = ({ label }: { label: string }) => (
    <Typography variant="h6" gutterBottom>
      {label}
    </Typography>
  );

  const Separator = () => <Box pt="1em" />;

  const getStatus = () => {
    let status: CarStatus[] = [];
    if (props.isEdit) {
      switch (initialStatus) {
        case CarStatus.Auctioned:
          status = [CarStatus.Auctioned, CarStatus.PreDisAssemblyCheck];
          break;
        case CarStatus.PreDisAssemblyCheck:
          status = [CarStatus.PreDisAssemblyCheck, CarStatus.WaitingForDisAssembly];
          break;
        case CarStatus.WaitingForDisAssembly:
          status = [CarStatus.WaitingForDisAssembly, CarStatus.InDisAssembly];
          break;
        case CarStatus.InDisAssembly:
          status = [CarStatus.InDisAssembly, CarStatus.DisAssembled];
          break;
        case CarStatus.DisAssembled:
          status = [CarStatus.DisAssembled, CarStatus.Scraped];
          break;
        case CarStatus.Scraped:
          status = [CarStatus.Scraped];
          break;
      }
    } else {
      status = [
        CarStatus.Auctioned,
        CarStatus.PreDisAssemblyCheck,
      ];
    }
    return status;
  };

  return (
    <FormDataConsumer {...props}>
      {({ formData, ...rest }) => (
        <>
          <>
            <SectionTitle label="Car Details" />
            <Box className={classes.input}>
              <TextInput
                fullWidth
                source="vin"
                // validate={requiredValidate}
                onBlur={(event: any) => {
                  formData.make = '';
                  formData.model = '';
                  formData.year = '';
                  formData.submodel = '';
                }}
              />
            </Box>
            {formData?.vin ? (
              <Box className={classes.input}>
                <ReferenceInput
                  reference={ApiModels.make}
                  fullWidth
                  source="make"
                  // validate={requiredValidate}
                >
                  <AutocompleteInput
                    optionText="name"
                    onSelect={(event: any) => {
                      formData.model = '';
                      formData.year = '';
                      formData.submodel = '';
                    }}
                    helperText={vinDetails.vehicleDetails.manuName}
                  />
                </ReferenceInput>
              </Box>
            ) : (
              <Box className={classes.input}>
                <SelectInput
                  fullWidth
                  disabled
                  source="make"
                  // validate={requiredValidate}
                  choices={[]}
                />
              </Box>
            )}
            {formData?.vin && formData?.make ? (
              <Box className={classes.input}>
                <ReferenceInput
                  reference={ApiModels.model}
                  fullWidth
                  source="model"
                  filter={{ parent: formData.make }}
                  // validate={requiredValidate}
                >
                  <AutocompleteInput
                    optionText="name"
                    onSelect={(event: any) => {
                      formData.year = '';
                      formData.submodel = '';
                    }}
                    helperText={vinDetails.vehicleDetails.modelName}
                  />
                </ReferenceInput>
              </Box>
            ) : (
              <Box className={classes.input}>
                <SelectInput
                  fullWidth
                  disabled
                  source="model"
                  // validate={requiredValidate}
                  choices={[]}
                />
              </Box>
            )}
            {formData?.vin && formData?.make && formData?.model ? (
              <Box className={classes.input}>
                <ReferenceInput
                  reference={ApiModels.year}
                  fullWidth
                  source="year"
                  filter={{ parent: formData.model }}
                  // validate={requiredValidate}
                >
                  <AutocompleteInput
                    optionText="name"
                    onSelect={(event: any) => {
                      formData.submodel = '';
                    }}
                    helperText={vinDetails.vehicleDetails.year}
                  />
                </ReferenceInput>
              </Box>
            ) : (
              <Box className={classes.input}>
                <SelectInput
                  fullWidth
                  disabled
                  source="year"
                  // validate={requiredValidate}
                  choices={[]}
                />
              </Box>
            )}
            {formData?.vin
                && formData?.make
                && formData?.model
                && formData?.year ? (
                  <Box className={classes.input}>
                    <ReferenceInput
                      reference={ApiModels.submodels}
                      fullWidth
                      filter={{ parent: formData.year }}
                      source="submodel"
                      onBlur={(event: any) => {
                        setSubmodelSelected(formData.submodel);
                      }}
                      // validate={requiredValidate}
                    >
                      <AutocompleteInput
                        optionText="name"
                        helperText={vinDetails.vehicleDetails.typeName}
                      />
                    </ReferenceInput>
                  </Box>
              ) : (
                <Box className={classes.input}>
                  <SelectInput
                    fullWidth
                    disabled
                    source="submodel"
                    // validate={requiredValidate}
                    choices={[]}
                  />
                </Box>
              )}
            <Box className={classes.input}>
              <TextInput
                fullWidth
                source="style"
                helperText={`${vinDetails.vehicleDetails.constructionType}`}
              />
            </Box>
            <Box className={classes.input}>
              <TextInput
                fullWidth
                source="color"
              />
            </Box>
            <Box className={classes.input}>
              <NumberInput
                min={0}
                fullWidth
                source="doors"
              />
            </Box>
            <Box className={classes.input}>
              <TextInput
                fullWidth
                helperText={vinDetails.vehicleDetails.fuelType}
                source="fuelType"
              />
            </Box>
            <Box className={classes.input}>
              <TextInput
                fullWidth
                source="engineNo"
              />
            </Box>
            <Box className={classes.input}>
              <TextInput
                fullWidth
                source="engineCode"
              />
            </Box>
            <Box className={classes.input}>
              <TextInput
                fullWidth
                helperText={`${selectedSubmodel?.variant ? selectedSubmodel?.variant : ''}`}
                source="engine"
              />
            </Box>
            <Box className={classes.input}>
              <TextInput
                fullWidth
                source="licensePlate"
              />
            </Box>
            <Box className={classes.input}>
              <NumberInput
                min={0}
                fullWidth
                source="odometer"
              />
            </Box>
            <Box className={classes.input}>
              <TextInput
                fullWidth
                helperText={vinDetails.vehicleDetails.impulsionType}
                source="drive"
              />
            </Box>
            <Box className={classes.input}>
              <NumberInput
                min={0}
                fullWidth
                helperText={`${vinDetails.vehicleDetails.cylinder} ${selectedSubmodel?.engine ? selectedSubmodel?.engine : ''}`}
                source="cylinder"
              />
            </Box>
            <Box className={classes.input}>
              <NumberInput
                min={0}
                fullWidth
                helperText={vinDetails.vehicleDetails.cylinderCapacityLiter}
                source="cylinder_capainput_liter"
              />
            </Box>
          </>
          <>
            <Separator />
            <SectionTitle label="Car Yard details" />
            <Box className={classes.input}>
              <CarStatusInput
                // validate={requiredValidate}
                status={getStatus()}
              />
            </Box>
            <Box className={classes.input}>
              <CarLocationInput
                // validate={requiredValidate}
                locations={
                      formData?.status === CarStatus.Auctioned
                        ? [CarLocation.AwaitingArrival]
                        : [CarLocation.InYard]
                }
              />
            </Box>
          </>
          <>
            <Separator />
            <SectionTitle label="Car Purchase Details" />
            <Box className={classes.input}>
              <DateInput
                fullWidth
                source="purchasedDate"
                // validate={requiredValidate}
              />
            </Box>
            <Box className={classes.input}>
              <ReferenceInput 
                perPage={10} 
                source="purchased_from" 
                // validate={requiredValidate} 
                reference={ApiModels.customers}
              >
                <AutocompleteInput optionText="firstName" />
              </ReferenceInput>
            </Box>
          </>
          <>
            <Separator />
            <SectionTitle label="Car Images" />
            <Box>
              <ImageInput 
                multiple 
                // validate={requiredValidate} 
                maxSize={5000000} 
                source="pictures" 
                label="Car images" 
                accept="image/*"
              >
                <ImageField source="src" title="title" />
              </ImageInput>
            </Box>
          </>
        </>
      )}
    </FormDataConsumer>
  );
};

@IoanBucur
Copy link

Yeap I confirm. The simple fact that the 'composeValidators' method is marked as 'async', makes it slow.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
RFR Ready For Review
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Slow form inputs in V3 compared to V2 (useInput, composeValidators)
3 participants