如何在使用反应钩子形式反应 select 一段时间后设置默认值

How to set defaultValue after some delay on react select with react hook form

我正在使用 react-select 下拉菜单和 react-hook-form 库。我正在调用 api 来获取 react-select 的默认值。最初下拉列表无法预填充默认值。所以我找到了一个解决方法,当我从 api.

获取数据时重新渲染整个 JSX
<form onSubmit={handleSubmit(saveData)}>
{!countryValue && (
      <Controller
        name="country"
        control={control}
        render={({ onChange, value, ref }) => (
          <Select
            options={country}
            value={country.find((c) => c.value === value)}
            onChange={(val) => onChange(val.value)}
          />
        )}
        rules={{ required: true }}
      />
    )}
    {countryValue && (
      <Controller
        name="country"
        control={control}
        render={({ onChange, value, ref }) => (
          <Select
            options={country}
            value={country.find((c) => c.value === value)}
            onChange={(val) => onChange(val.value)}
            defaultValue={country.find((c) => c.value === countryValue)}
          />
        )}
        rules={{ required: true }}
      />
    )}
{errors.country && <div>Field is rquired</div>}
    <button type="submit">Save</button>
  </form>

我在 countryValue 上设置了一个条件,即当组件获取 countryValue 的值时,它会呈现整个下拉列表。

但是当我使用相同的 defaultValue 钩子表单提交表单时,出现国家字段未定义的错误。

我为此创建了一个沙箱。 https://codesandbox.io/s/react-select-with-react-hook-form-sc2xz

如何解决这个问题。他们有什么解决方法吗?

一个很好的问题,但看起来你做的有点乱, 您将国家/地区对象传递给 Select 组件,然后在 valueonChange 道具 中再次过滤它(为什么,我想不通? ),

首先你需要为你的Select组件定义一个defaultValue,但是你不能在同一个地方同时使用(defaultValue value),做使用控制器为您设置默认值,您已经在 countryValue 状态中定义:

import "./styles.css";
import Select from "react-select";
import { useForm, Controller } from "react-hook-form";
import { useEffect, useState } from "react";

let country = [
  { label: "Bangladesh", value: "Bangladesh" },
  { label: "India", value: "India" },
  { label: "China", value: "China" },
  { label: "Finland", value: "Finland" }
];

export default function App() {
  const [countryValue, setCountryValue] = useState({
    label: "India",
    value: "India"
  });
  const { handleSubmit, control, errors } = useForm();

  useEffect(() => {
    setTimeout(() => {
      setCountryValue("India");
    }, 2000);
  }, []);

  useEffect(() => {
    console.log("errors", errors);
  }, [errors]);

  const saveData = (form_data) => {
    console.log("form_data", form_data);
  };

  return (
    <div className="App">
      <form onSubmit={handleSubmit(saveData)}>
        <Controller
          name="country"
          control={control}
          defaultValue={countryValue}
          render={({ onChange, value, ref }) => (
            <Select
              options={country}
              value={value}
              onChange={(val) => onChange(val)}
            />
          )}
          rules={{ required: true }}
        />

        {errors.country && <div>Field is rquired</div>}
        <button type="submit">Save</button>
      </form>
    </div>
  );
}

我认为与其重新创建一个新的组件来给它一个默认值,不如直接在现有组件上设置值。

为此,您可以使用从 useForm() 返回的对象中获得的 setValue

这是代码的一部分:

  const { handleSubmit, control, errors, setValue } = useForm();

  useEffect(() => {
    setTimeout(() => {
      setValue("country", "India");
    }, 2000);
  }, [setValue]);

here is the codesandbox.

就我而言,我是这样处理的

const [categories, setCategories] = useState([]);
const [defaultCategory, setDefaultCategory] = useState(null);
    
useEffect(() => {
    if(formAction === 'UPDATE') {
        setDefaultCategory(categories.find(element => element.value === data.category_id));
    }
}, [categories]);

<Controller
        control={control}
        name="category_id"
        render={({
            field: { onChange, onBlur, value, name, ref },
        }) =>  {
            return(
                <Select
                    value={defaultCategory}
                    onBlur={onBlur}
                    options={categories}
                    placeholder="Select a category"
                    defaultOptions={true}
                    onChange={(val) => {
                        setDefaultCategory(val);
                        onChange(val);
                    }}
                    isSearchable={false}
                    className="
                        shadow-sm
                        focus:ring-indigo-500
                        focus:border-indigo-500
                        block
                        max-w-full
                        text-md
                        border-gray-300
                        rounded-md
                    "
                />
            );
        }}
    />                                                             />