简体   繁体   English

带有 react-form-hook 验证值的 Material UI 自动完成未正确更改

[英]Material UI autocomplete with react-form-hook validation value is not changing properly

I am trying to implement multi-select Mui autocomplete.我正在尝试实现多选 Mui 自动完成功能。

Whenever user selects an option, I want Chip component to be displayed underneath.每当用户选择一个选项时,我希望芯片组件显示在下面。

I am using react-form-hook to check validation.我正在使用 react-form-hook 来检查验证。 categories field is an array, and I want it to have at least one item. categories字段是一个数组,我希望它至少有一个项目。

Problem is when I delete a chip, the value does not update properly.问题是当我删除一个芯片时,值没有正确更新。 I am using react state to keep track of selectedItems so I can display Chip component.我正在使用反应状态来跟踪 selectedItems,以便我可以显示芯片组件。

When I delete the chip, it is deleted from selectedItem state, but actual value from Controller does not change.当我删除芯片时,它会从 selectedItem 状态中删除,但 Controller 的实际值不会改变。

Please review my code, and give me some feedbacks.请检查我的代码,并给我一些反馈。 Thank you all!!谢谢你们!!

mui_autocomplete mui_autocomplete

import React, { useEffect, useState } from 'react';
import { Autocomplete, Chip, FormControl, FormLabel, Stack, TextField } from '@mui/material';
import { Controller } from 'react-hook-form';
import CloseIcon from '@mui/icons-material/Close';

export default function FormAutoComplete({ name, control, label, error, ...props }) {
  const [selectedItems, setSelectedItems] = useState([]);

  const selectedItemChip = selectedItems.map((item) => {
    return (
      <Chip
        key={item}
        label={item}
        deleteIcon={<CloseIcon />}
        onDelete={() => {
          setSelectedItems((prev) => prev.filter((entry) => entry !== item));
        }}
      />
    );
  });

  return (
    <FormControl fullWidth>
      <FormLabel>{label}</FormLabel>
      <Controller
        name={name}
        control={control}
        render={({ field: { onChange, value } }) => (
          <Autocomplete
            multiple
            filterSelectedOptions
            options={options}
            getOptionLabel={(option) => option}
            renderTags={() => {}}
            value={selectedItems}
            onChange={(e, newValue) => {
              const addedItem = newValue[newValue.length - 1];
              setSelectedItems((prev) => [...prev, addedItem]);
              onChange(selectedItems);
              return selectedItems;
            }}
            renderInput={(params) => (
              <TextField
                {...params}
                {...props}
                error={!!error}
                helperText={error && error.message}
              />
            )}
          />
        )}
      />
      <Stack direction="row" marginTop={2} gap={1} flexWrap="wrap">
        {selectedItemChip}
      </Stack>
    </FormControl>
  );
}

export const options = [
  'Building Materials',
  'Tools',
  'Decor & Furniture',
  'Bath',
  'Doors & Windows',
  'Cleaning',
  'Electrical',
  'Heating & Cooling',
  'Plumbing',
  'Hardware',
  'Kitchen',
  'Lawn & Garden',
  'Lighting & Fans',
];

Sandbox 沙盒

Once chip is deleted, react-hook-form is not updated with latest value.删除芯片后,react-hook-form 不会更新为最新值。 So, when form is submitted, old data is logged.因此,提交表单时,会记录旧数据。

  1. No need to track selectedItems in a state variable.无需在状态变量中跟踪selectedItems You can use useWatch hook to get latest value from react-hook-form您可以使用useWatch钩子从 react-hook-form 获取最新值
  2. use setValue to update value in formState使用setValue更新formState中的值

With these changes your FormAutoComplete component should look like this通过这些更改,您的FormAutoComplete组件应如下所示

export default function FormAutoComplete({
  name,
  control,
  label,
  error,
  setValue, // Pass this prop from parent component. Can be destructured from useForm hook
  ...props
}) {
  // const [selectedItems, setSelectedItems] = useState([]);
  const selectedItems = useWatch({control,name}) // import useWatch from react-hook-form
  const selectedItemChip = selectedItems.map((item) => {
    return (
      <Chip
        key={item}
        label={item}
        deleteIcon={<CloseIcon />}
        onDelete={() => {
          // setSelectedItems((prev) => [...prev.filter((entry) => entry !== item)]);
        setValue(name,selectedItems.filter((entry) => entry !== item))
        }}
      />
    );
  });

  return (
    <FormControl fullWidth>
      <FormLabel>{label}</FormLabel>
      <Controller
        name={name}
        control={control}
        render={({ field: { onChange, value } }) => (
          <Autocomplete
            multiple
            filterSelectedOptions
            options={options}
            getOptionLabel={(option) => option}
            renderTags={() => {}}
           // value={selectedItems}
            value={value}
            onChange={(e, newValue) => {
              // setSelectedItems(newValue);
              onChange(newValue);
            }}
            renderInput={(params) => (
              <TextField
                {...params}
                {...props}
                error={!!error}
                helperText={error && error.message}
              />
            )}
          />
        )}
      />
      <Stack direction="row" marginTop={2} gap={1} flexWrap="wrap">
        {selectedItemChip}
      </Stack>
    </FormControl>
  );
}

Documentation :文档:

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM