Компонент MaterialUI не выполняет автозаполнение при наличии данных - PullRequest
6 голосов
/ 23 апреля 2020

Я не могу заставить свой компонент показывать свои автозапросы. В консоли замечено, что мои данные доступны, и я отправил их этому компоненту, используя реквизиты предложений, используя функцию компонента автозаполнения пользовательского интерфейса здесь Я пытаюсь настроить свои параметры, и они меняются по мере того, как я введите, как он обрабатывается в родительском компоненте, но установка значений, кажется, не отражает и не вызывает мои предложения. Я очень смущен. мой код ниже.

import React, { FunctionComponent, FormEvent, ChangeEvent } from "react";
import { Grid, TextField, Typography } from "@material-ui/core";
import { CreateProjectModel, JobModel } from "~/Models/Projects";
import ErrorModel from "~/Models/ErrorModel";
import Autocomplete from "@material-ui/lab/Autocomplete";

type CreateProjectFormProps = {
    model: CreateProjectModel;
    errors: ErrorModel<CreateProjectModel>;
    onChange: (changes: Partial<CreateProjectModel>) => void;
    onSubmit?: () => Promise<void>;
    suggestions: JobModel[];
};

const CreateProjectForm: FunctionComponent<CreateProjectFormProps> = ({
    model,
    errors,
    onChange,
    onSubmit,
    suggestions,
}) => {
    const [open, setOpen] = React.useState(false);
    const [options, setOptions] = React.useState<JobModel[]>([]);
    const loading = open && options.length === 0;
    const [inputValue, setInputValue] = React.useState('');
    React.useEffect(() => {
        let active = true;

        if (!loading) {
            return undefined;
        }

        (async () => {
            if (active) {
                setOptions(suggestions);
            }
        })();

        return () => {
            active = false;
        };
    }, [loading]);

    React.useEffect(() => {
        if (!open) {
            setOptions([]);
        }
    }, [open]);

    const submit = async (event: FormEvent) => {
        event.preventDefault();
        event.stopPropagation();

        await onSubmit();
    };

    const change = (name: string) => (event: ChangeEvent<HTMLInputElement>) => {
        setInputValue(event.target.value);

        onChange({
            [name]: event.target.value,
        });
    };

    const getFieldProps = (id: string, label: string) => {
        return {
            id,
            label,
            helperText: errors[id],
            error: Boolean(errors[id]),
            value: model[id],
            onChange: change(id),
        };
    };

    return (
        <Autocomplete
            {...getFieldProps}
            open={open}
            onOpen={() => {
                setOpen(true);
            }}
            onClose={() => {
                setOpen(false);
            }}
            getOptionSelected={(option, value) => option.id === value.id}
            getOptionLabel={(option) => option.id}
            options={options}
            loading={loading}
            autoComplete
            includeInputInList            
            renderInput={(params) => (
                <TextField
                    {...getFieldProps("jobNumber", "Job number")}
                    required
                    fullWidth
                    autoFocus
                    margin="normal"
                />
            )}
            renderOption={(option) => {        
                return (
                  <Grid container alignItems="center">

                    <Grid item xs>
                      {options.map((part, index) => (
                        <span key={index}>
                          {part.id}
                        </span>
                      ))}
                      <Typography variant="body2" color="textSecondary">
                        {option.name}
                      </Typography>
                    </Grid>
                  </Grid>
                );
              }}            
        />
    );
};

export default CreateProjectForm;

Пример моих данных в предложениях выглядит следующим образом:

[{"id":"BR00001","name":"Aircrew - Standby at home base"},{"id":"BR00695","name":"National Waste"},{"id":"BR00777B","name":"Airly Monitor Site 2018"},{"id":"BR00852A","name":"Cracow Mine"},{"id":"BR00972","name":"Toowoomba Updated"},{"id":"BR01023A","name":"TMRGT Mackay Bee Creek"},{"id":"BR01081","name":"Newman Pilot Job (WA)"},{"id":"BR01147","name":"Lake Vermont Monthly 2019"},{"id":"BR01158","name":"Callide Mine Monthly Survey 2019"},{"id":"BR01182","name":"Lake Vermont Quarterly 2019 April"}]

Ответы [ 3 ]

5 голосов
/ 25 апреля 2020

Проблема в вашем коде - это useEffects, которые вы используете.

В приведенном ниже useEffect вы фактически устанавливаете параметры для пустого массива изначально. Это связано с тем, что автозаполнение не открыто, и эффект запускается и при первоначальном монтировании. Кроме того, поскольку вы настраиваете параметры для другого использования. Влияет, что ваш код должен работать только при загрузке обновлений состояния, а вы не открыли выпадающий список автозаполнения.

В тот момент, когда вы закрываете его даже один раз, состояние обновлен до пустого, и вы больше не будете видеть предложения.

React.useEffect(() => {
    if (!open) {
        setOptions([]);
    }
}, [open]);

Решение простое. Вам не нужно сохранять локальное состояние для опций, но используйте значения, поступающие из реквизита, которые suggestions

Вам нужно только сохранить состояние для открытого

const CreateProjectForm: FunctionComponent<CreateProjectFormProps> = ({
    model,
    errors,
    onChange,
    onSubmit,
    suggestions,
}) => {
    const [open, setOpen] = React.useState(false);
    const loading = open && suggestions.length === 0;
    const [inputValue, setInputValue] = React.useState('');

    const submit = async (event: FormEvent) => {
        event.preventDefault();
        event.stopPropagation();

        await onSubmit();
    };

    const change = (name: string) => (event: ChangeEvent<HTMLInputElement>) => {
        setInputValue(event.target.value);

        onChange({
            [name]: event.target.value,
        });
    };

    const getFieldProps = (id: string, label: string) => {
        return {
            id,
            label,
            helperText: errors[id],
            error: Boolean(errors[id]),
            value: model[id],
            onChange: change(id),
        };
    };

    return (
        <Autocomplete
            {...getFieldProps}
            open={open}
            onOpen={() => {
                setOpen(true);
            }}
            onClose={() => {
                setOpen(false);
            }}
            getOptionSelected={(option, value) => option.id === value.id}
            getOptionLabel={(option) => option.id}
            options={suggestions}
            loading={loading}
            autoComplete
            includeInputInList            
            renderInput={(params) => (
                <TextField
                    {...getFieldProps("jobNumber", "Job number")}
                    required
                    fullWidth
                    autoFocus
                    margin="normal"
                />
            )}
            renderOption={(option) => {        
                return (
                  <Grid container alignItems="center">

                    <Grid item xs>
                      {options.map((part, index) => (
                        <span key={index}>
                          {part.id}
                        </span>
                      ))}
                      <Typography variant="body2" color="textSecondary">
                        {option.name}
                      </Typography>
                    </Grid>
                  </Grid>
                );
              }}            
        />
    );
};

export default CreateProjectForm;
0 голосов
/ 01 мая 2020

Я заметил несколько проблем с вашим кодом, getFieldProps вызывается без параметров id или name, из-за которых страница не загружается. Что еще более важно, вы должны соблюдать следующие правила autocomplete docs при передаче и использовании реквизита для него. Например:

renderInput={(params) => <TextField {...params} label="Controllable" variant="outlined" />}

Я задал несколько вопросов, пожалуйста, дайте мне знать, когда вы сможете получить эти ответы, чтобы я мог решить все вопросы, которые могут возникнуть.

Q1. должен ли пользовательский ввод предоставить соответствующие совпадения из свойства name в ваших предложениях или только по id? например если я наберу "озеро", вы хотите показать BRO1182, Озеро Вермонт ежеквартально 2019 апреля в качестве совпадения?

Q2. как вы хотели устранить ошибку? Я вижу, у вас есть модель ошибки, но вы не знаете, как использовать sh, чтобы использовать ее для стилизации автозаполнения при возникновении ошибки

Q3. мы пропускаем кнопку отправки? Я вижу функцию onSubmit, но она не используется в нашем коде.

Q4. Есть ли конкретная причина, по которой вам нужны состояния открытия и загрузки?

ниже я попытался показать соответствующие совпадения из пользовательского ввода

import React, { FunctionComponent, FormEvent, ChangeEvent } from "react";
import { Grid, TextField, Typography } from "@material-ui/core";
import { CreateProjectModel, JobModel } from "~/Models/Projects";
import ErrorModel from "~/Models/ErrorModel";
import Autocomplete from "@material-ui/lab/Autocomplete";

type CreateProjectFormProps = {
  model: CreateProjectModel;
  errors: ErrorModel<CreateProjectModel>;
  onChange: (changes: Partial<CreateProjectModel>) => void;
  onSubmit?: () => Promise<void>;
  suggestions: JobModel[];
};

const CreateProjectForm: FunctionComponent<CreateProjectFormProps> = ({
  model,
  errors,
  // mock function for testing
  // consider a better name like selectChangeHandler
  onChange = val => console.log(val),
  // consider a better name like submitJobFormHandler
  onSubmit,
  suggestions: options = [
    { id: "BR00001", name: "Aircrew - Standby at home base" },
    { id: "BR00695", name: "National Waste" },
    { id: "BR00777B", name: "Airly Monitor Site 2018" },
    { id: "BR00852A", name: "Cracow Mine" },
    { id: "BR00972", name: "Toowoomba Updated" },
    { id: "BR01023A", name: "TMRGT Mackay Bee Creek" },
    { id: "BR01081", name: "Newman Pilot Job (WA)" },
    { id: "BR01147", name: "Lake Vermont Monthly 2019" },
    { id: "BR01158", name: "Callide Mine Monthly Survey 2019" },
    { id: "BR01182", name: "Lake Vermont Quarterly 2019 April" }
  ]
}) => {
  const [value, setValue] = React.useState<JobModel>({});
  const loading = open && options.length === 0;

  // this pc of code is not used, why?
  const submit = async (event: FormEvent) => {
    event.preventDefault();
    event.stopPropagation();

    await onSubmit();
  };

  const handleChange = (_: any, value: JobModel | null) => {
    setValue(value);

    onChange({
      [value.name]: value.id
    });
  };

  // consider passing in props instead
  const getFieldProps = (id: string, label: string) => {
    return {
      id,
      label,
      // not sure what this is
      helperText: errors[id],
      // not sure what this is
      error: Boolean(errors[id]),
      value: model[id],
      onChange: change(id)
    };
  };

  return (
    <Autocomplete
      id="placeholder-autocomplete-input-id"
      // for selection, use value see docs for more detail
      value={value}
      onChange={handleChange}
      getOptionSelected={(option, value) => option.id === value.id}
      getOptionLabel={option => option.id}
      options={options}
      loading={loading}
      autoComplete
      includeInputInList
      renderInput={params => (
        // spreading the params here will transfer native input attributes from autocomplete
        <TextField
          {...params}
          label="placeholder"
          required
          fullWidth
          autoFocus
          margin="normal"
        />
      )}
      renderOption={option => (
        <Grid container alignItems="center">
          <Grid item xs>
            <span key={option}>{option.id}</span>
            <Typography variant="body2" color="textSecondary">
              {option.name}
            </Typography>
          </Grid>
        </Grid>
      )}
    />
  );
};

export default CreateProjectForm;

и Вы можете увидеть код, запущенный в моей папке «коды», нажав кнопку ниже

Edit sharp-newton-87eng

0 голосов
/ 25 апреля 2020

Если я правильно понимаю ваш код и выдает ошибку, вы хотите -


    React.useEffect(() => {
      let active = true;

      if (!loading) {
        return undefined;
      }

      (async () => {
         if (active) {
             setOptions(suggestions);
          }
       })(); 

      return () => {
         active = false;
      };
   }, [loading]);

каждый раз запускаться и обновлять options, но дело в том, что [loading] зависимость установлена как


     const loading = open && suggestions.length === 0;

и не вызовет изменений.

Подумайте о том, чтобы сделать это так -


 const loading = useLoading({open, suggestions})


 const useLoading = ({open, suggestions}) => open && suggestions.length === 0;
...