React hook form setValue returns undefined with multi select (react-select)
React hook form setValue returns undefined with multi select (react-select)
我正在尝试使用 React 和来自 react-select 的 select 元素构建一个表单,并使用 react-hook-form 完成验证。
更改后值似乎成功更改,但是当我提交表单时 select 值未定义。
我有输入字段,它们工作正常,但对于我的 select 和多 select 元素,它失败了。
React 的新手很困惑,试图找到这个问题的答案但找不到。删除了一些代码以保留有趣的部分,希望我做对了。
import React, { useState } from "react";
import Collapsible from "../collapsible/Collapsible"
import Select, { components } from 'react-select';
import axios from "axios";
import { useInput } from "../../hooks"
import { useForm } from 'react-hook-form';
import { selectStyles } from "./styles"
import allBots from "../../data/bots";
import platforms from "../../data/platforms";
import connectionTypes from "../../data/connection_types";
import generatePayload from "./generate_payload";
const Connect = () => {
const { setValue, register, handleSubmit, errors } = useForm();
const [values, setValues] = useState({
selectedOption: []
});
const CustomOption = props => {
return (
<components.Option {...props}>
<div style={{ display: "inline-block", "min-width": "40px" }}>{props.data.suffix}</div>
<div style={{ display: "inline-block" }}>{props.data.value}</div>
</components.Option>
);
};
const handleBotChange = selectedBot => {
setValue("bots", selectedBot);
setValues(selectedBot);
};
const handleMultiChange = selectedOption => {
console.log(selectedOption);
setValue("platform", selectedOption);
setValues(selectedOption);
};
const onSubmit = (data) => {
console.log(data);
// outputs { "bots": undefined, "platform": undefined, username: "theinput" }
}
return (
<Collapsible className="collapsible" header="Connect">
<div className="collapsibleContent">
<form onSubmit={handleSubmit(onSubmit)}>
<Select
className="reactSelect"
name="platform"
placeholder="Platform"
value={values.platform}
onChange={handleMultiChange}
options={platforms}
ref={e => register({ name: "platform", required: true })}
/>
<Select
isMulti
name="bots"
options={bots}
onChange={handleBotChange}
closeMenuOnSelect={false}
blurInputOnSelect={false}
className="basic-multi-select formItem"
classNamePrefix="select"
components={{Option: CustomOption}}
styles={selectStyles}
placeholder="Bots"
ref={e => register({ name: "bots", required: true })}
/>
<input
name="username"
ref={register({
validate: value => value !== "illegal_value" || "Illegal value"
})}
/>
{errors.username && errors.username.message}
<button type="submit">Submit</button>
</form>
</div>
</Collapsible>
);
}
export default Connect;
更新:
我决定使用 react-hook-form 的“控制器”功能将其与 react-select 集成。这就是我的代码部分的结束方式。我还使用 SocketIO 事件来动态填充下拉列表中的选项。这个解决方案并不完美,但它确实不错。
import React, { useState, useEffect } from "react";
import Collapsible from "../collapsible/Collapsible"
import Select, { components } from 'react-select';
import { useForm, Controller } from 'react-hook-form';
import { selectStyles } from "./styles"
import connectionTypes from "../../data/connection_types";
import { OptionWithSuffix } from "../form_components/components";
import socket from "../socket";
const Connect = () => {
const { errors, control, watch, getValues, handleSubmit, register, setValue, reset } = useForm();
const watchFields = watch(["connectionType"]);
const [bots, setBots] = useState([]);
const connectionType = getValues("connectionType") || {};
useEffect(() => {
socket.on("bots", data => {
setBots(data.map(obj => ({...obj, suffix: obj.count, value: obj.name, label: obj.name})));
});
return () => {
socket.off("bots");
};
}, []);
const onSubmit = (data) => {
console.log(data);
}
return(
<Collapsible className="collapsible" header="Connect">
<div>
<form onSubmit={handleSubmit(data => onSubmit(data))}>
<Controller
control={control}
as={<Select className="formItem" options={platforms} />}
rules={{ required: true }}
placeholder="Select platform"
name="platform"
styles={selectStyles}
register={register}
setValue={setValue}
/>
<Controller
control={control}
as={<Select className="formItem" options={connectionTypes}/>}
rules={{ required: true}}
placeholder="Select connection type"
name="connectionType"
styles={selectStyles}
register={register}
setValue={setValue}
/>
{errors.connectionType && "Connection type is required"}
{connectionType.value === "specific" &&
<Controller
control={control}
as={
<Select
isMulti
className="formItem"
options={bots}
closeMenuOnBlur={false}
closeMenuOnSelect={false}
components={{Option: OptionWithSuffix}}
styles={selectStyles}
/>
}
rules={{ required: true }}
placeholder="Select bots"
name="bots"
rules={{ required: true }}
register={register}
setValue={setValue}
/>
}
{errors.platform && connectionType.value === "specific" && "Bots are required"}
<input className="formItem" type="submit" placeholder="Connect"/>
</form>
</div>
</Collapsible>
);
}
export default Connect;
我不能完全测试你的代码,因为它有一些导入。
据我所知,您需要在更改事件中获取 selected 选项值。
const handleBotChange = selectedBot => {
setValue("bots", selectedBot.value);
};
const handleMultiChange = selectedOption => {
setValue("platform", selectedOption.value);
};
另外,我不太了解react-select控件,但它可能是内部控制的,所以你不需要values state hook
看看 react-hook-form
的文档,它们展示了如何注册第三方 ui 组件的正确方法,甚至有一个使用 react-select
[=12= 的示例]
下面是我如何使用 v6.14.1
.
中的 react-hook-forms 让我的 MUI-Select 获取多个值
<Controller
name="categories"
type="select"
control={control}
defaultValue={categoryOptions[0]}
render={({ onChange, onBlur, value }) => (
<RHFSelect
onChange={onChange}
onBlur={onBlur}
value={[...value]} // this is what you need to do
multiple={true}
options={categoryOptions}
/>
)}
/>
RHFSelect
在我的代码中是可重复使用的 Select
。要select只有一个值,你可能会喜欢这样-
value={value}
对于v7.9.0
,可以这样做
<Controller
name="colors"
type="select"
control={control}
defaultValue={[]}
render={({ field }) => (
<Select
{...field}
multiple
>
/* Select ops */
</Select>
)}
/>
我正在尝试使用 React 和来自 react-select 的 select 元素构建一个表单,并使用 react-hook-form 完成验证。
更改后值似乎成功更改,但是当我提交表单时 select 值未定义。
我有输入字段,它们工作正常,但对于我的 select 和多 select 元素,它失败了。
React 的新手很困惑,试图找到这个问题的答案但找不到。删除了一些代码以保留有趣的部分,希望我做对了。
import React, { useState } from "react";
import Collapsible from "../collapsible/Collapsible"
import Select, { components } from 'react-select';
import axios from "axios";
import { useInput } from "../../hooks"
import { useForm } from 'react-hook-form';
import { selectStyles } from "./styles"
import allBots from "../../data/bots";
import platforms from "../../data/platforms";
import connectionTypes from "../../data/connection_types";
import generatePayload from "./generate_payload";
const Connect = () => {
const { setValue, register, handleSubmit, errors } = useForm();
const [values, setValues] = useState({
selectedOption: []
});
const CustomOption = props => {
return (
<components.Option {...props}>
<div style={{ display: "inline-block", "min-width": "40px" }}>{props.data.suffix}</div>
<div style={{ display: "inline-block" }}>{props.data.value}</div>
</components.Option>
);
};
const handleBotChange = selectedBot => {
setValue("bots", selectedBot);
setValues(selectedBot);
};
const handleMultiChange = selectedOption => {
console.log(selectedOption);
setValue("platform", selectedOption);
setValues(selectedOption);
};
const onSubmit = (data) => {
console.log(data);
// outputs { "bots": undefined, "platform": undefined, username: "theinput" }
}
return (
<Collapsible className="collapsible" header="Connect">
<div className="collapsibleContent">
<form onSubmit={handleSubmit(onSubmit)}>
<Select
className="reactSelect"
name="platform"
placeholder="Platform"
value={values.platform}
onChange={handleMultiChange}
options={platforms}
ref={e => register({ name: "platform", required: true })}
/>
<Select
isMulti
name="bots"
options={bots}
onChange={handleBotChange}
closeMenuOnSelect={false}
blurInputOnSelect={false}
className="basic-multi-select formItem"
classNamePrefix="select"
components={{Option: CustomOption}}
styles={selectStyles}
placeholder="Bots"
ref={e => register({ name: "bots", required: true })}
/>
<input
name="username"
ref={register({
validate: value => value !== "illegal_value" || "Illegal value"
})}
/>
{errors.username && errors.username.message}
<button type="submit">Submit</button>
</form>
</div>
</Collapsible>
);
}
export default Connect;
更新: 我决定使用 react-hook-form 的“控制器”功能将其与 react-select 集成。这就是我的代码部分的结束方式。我还使用 SocketIO 事件来动态填充下拉列表中的选项。这个解决方案并不完美,但它确实不错。
import React, { useState, useEffect } from "react";
import Collapsible from "../collapsible/Collapsible"
import Select, { components } from 'react-select';
import { useForm, Controller } from 'react-hook-form';
import { selectStyles } from "./styles"
import connectionTypes from "../../data/connection_types";
import { OptionWithSuffix } from "../form_components/components";
import socket from "../socket";
const Connect = () => {
const { errors, control, watch, getValues, handleSubmit, register, setValue, reset } = useForm();
const watchFields = watch(["connectionType"]);
const [bots, setBots] = useState([]);
const connectionType = getValues("connectionType") || {};
useEffect(() => {
socket.on("bots", data => {
setBots(data.map(obj => ({...obj, suffix: obj.count, value: obj.name, label: obj.name})));
});
return () => {
socket.off("bots");
};
}, []);
const onSubmit = (data) => {
console.log(data);
}
return(
<Collapsible className="collapsible" header="Connect">
<div>
<form onSubmit={handleSubmit(data => onSubmit(data))}>
<Controller
control={control}
as={<Select className="formItem" options={platforms} />}
rules={{ required: true }}
placeholder="Select platform"
name="platform"
styles={selectStyles}
register={register}
setValue={setValue}
/>
<Controller
control={control}
as={<Select className="formItem" options={connectionTypes}/>}
rules={{ required: true}}
placeholder="Select connection type"
name="connectionType"
styles={selectStyles}
register={register}
setValue={setValue}
/>
{errors.connectionType && "Connection type is required"}
{connectionType.value === "specific" &&
<Controller
control={control}
as={
<Select
isMulti
className="formItem"
options={bots}
closeMenuOnBlur={false}
closeMenuOnSelect={false}
components={{Option: OptionWithSuffix}}
styles={selectStyles}
/>
}
rules={{ required: true }}
placeholder="Select bots"
name="bots"
rules={{ required: true }}
register={register}
setValue={setValue}
/>
}
{errors.platform && connectionType.value === "specific" && "Bots are required"}
<input className="formItem" type="submit" placeholder="Connect"/>
</form>
</div>
</Collapsible>
);
}
export default Connect;
我不能完全测试你的代码,因为它有一些导入。
据我所知,您需要在更改事件中获取 selected 选项值。
const handleBotChange = selectedBot => {
setValue("bots", selectedBot.value);
};
const handleMultiChange = selectedOption => {
setValue("platform", selectedOption.value);
};
另外,我不太了解react-select控件,但它可能是内部控制的,所以你不需要values state hook
看看 react-hook-form
的文档,它们展示了如何注册第三方 ui 组件的正确方法,甚至有一个使用 react-select
[=12= 的示例]
下面是我如何使用 v6.14.1
.
<Controller
name="categories"
type="select"
control={control}
defaultValue={categoryOptions[0]}
render={({ onChange, onBlur, value }) => (
<RHFSelect
onChange={onChange}
onBlur={onBlur}
value={[...value]} // this is what you need to do
multiple={true}
options={categoryOptions}
/>
)}
/>
RHFSelect
在我的代码中是可重复使用的 Select
。要select只有一个值,你可能会喜欢这样-
value={value}
对于v7.9.0
,可以这样做
<Controller
name="colors"
type="select"
control={control}
defaultValue={[]}
render={({ field }) => (
<Select
{...field}
multiple
>
/* Select ops */
</Select>
)}
/>