【发布时间】:2020-11-16 22:59:37
【问题描述】:
我使用react-hook-form 在这个 Gatsby 项目的表单中进行验证,但我的下拉组件不是<select> 标记,而是使用 div 和无序列表制作的自定义组件。这完全是一个设计选择,因为我们需要它非常定制。这里是组件
// Dropdown.js
import React, { useState } from "react";
import "../../sass/components/forms/dropdown.sass"
export function Dropdown({ preambulo, name, options, placeholder, value}) {
const [isOpen, setIsOpen] = useState(false);
const [selectedOption, setSelectedOption] = useState(null);
const toggling = () => setIsOpen(!isOpen);
const onOptionClicked = value => () => {
setSelectedOption(value);
setIsOpen(false);
};
return (
<React.Fragment>
<span>{preambulo}</span>
<div
className={`
dropdownHeader
${isOpen === true ? 'open' : 'closed'}
`}
onClick={toggling}
>
{selectedOption || placeholder}
</div>
{isOpen && (
<div
className="dropdownListContainer">
<ul
className="dropdownList"
name={name}
id={name}
value={value}
>
{options.map((option, i) => (
<li
className={`dropdownListItem item-${i}`}
key={i}
onClick={onOptionClicked(option)}>
{option}
</li>
))}
<hr />
</ul>
</div>
)}
</React.Fragment>
);
}
稍微解释一下,props 是从 <Controller> 中的 react-hook-form 传递的,组件被渲染的地方。组件本身具有处理列表的状态,当用户单击标题时将打开该列表。很简单:const toggling = () => setIsOpen(!isOpen); 做到了。并且选项的值是从传递给父元素的 const 映射的,然后一旦选择了某些内容,它就会像 <select> 一样发生在标题中。
这是表单的代码(Edit2):
// contato.js
import React from "react";
import { useForm, Controller } from "react-hook-form";
//Form Components
import { Dropdown } from "../../components/forms/Dropdown"
import { Input, TextArea } from "../../components/forms/Input"
const ContatoFull = ({ className }) => {
const cargos = [
{//** values **/}
]
const estados = [
"Acre",
"Alagoas",
"Amazonas",
"Amapá",
"Bahia",
"Ceará",
"Distrito Federal",
"Espírito Santo",
"Goiás",
"Maranhão",
"Minas Gerais",
"Mato Grosso do Sul",
"Mato Grosso",
"Pará",
"Paraíba",
"Pernambuco",
"Piauí",
"Paraná",
"Rio de Janeiro",
"Rio Grande do Norte",
"Rondônia",
"Roraima",
"Rio Grande do Sul",
"Santa Catarina",
"Sergipe",
"São Paulo",
"Tocantins"
]
const methods = useForm();
const { handleSubmit, control, formState, errors } = methods;
const onSubmit = data => {
alert(JSON.stringify(data));
};
console.log(formState);
return (
<form
method="post"
className={`${className !== 0 ? className : ''}`}
onSubmit={handleSubmit(onSubmit)}>
<div
className={`dropdownContainer cargo`}>
<Controller
name="cargo"
control={control}
render={({ onClick, name, value }) =>
<Dropdown
onClick={e => onClick(e.target.value)}
value={value}
preambulo="Eu sou"
placeholder="Placeholder"
name={name}
options={cargos}
/>
}
/>
</div>
<div
className={`dropdownContainer estado`}>
<Controller
name="estado"
control={control}
render={({ onClick, name, value }) =>
<Dropdown
onClick={e => onClick(e.target.value)}
value={value}
name={name}
preambulo="Estou em/no"
placeholder="acre"
options={estados}
/>
}
/>
</div>
<div
className={`inputContainer empresa`}>
<Controller
name="empresa"
type="text "
control={control}
defaultValue=""
rules={{ required: true }}
render={({ onChange, value, name, type, label }) =>
<Input
onChange={e => onChange(e.target.value)}
value={value}
label="Nome da minha empresa"
type="text" />
}
/>
{errors.empresa && <span className="erro requerido">Campo obrigatório</span>}
</div>
{//** more input components //*^}
<button
type="submit"
className="simpleButton primary submit button">Enviar</button>
</form>
)
}
export default ContatoFull
现在,我们要处理两个问题:1)如何将值传递给表单,因为我们没有使用标准标签进行选择; 和 2) 即使切换适用于单击标题或从列表中选择一个选项,单击外部也不会关闭它,如下所示。
我不确定如何解决这些问题。我相信问题 #1 需要一个钩子来获取子组件选择的值,但不知道这个钩子是什么,也不知道如何将它与 react-hook-form 一起使用。 对于问题 #2,也许是一个捕获外部点击的函数,它会切换回打开的列表。问题是我已经设法针对标题而不是它的外部,或者“非标题”部分,如果那是一件事的话。
编辑:设法使用此库检测到外部点击:react-outside-click-handler。一个简单问题的绝佳解决方案。
编辑 2:阅读@dshung1997 的评论我意识到我没有在此处粘贴父组件的代码。只是纠正这个。谢谢!
【问题讨论】:
-
嗯。我认为将值传递给表单似乎很明显。如果没有,介意你多说几句吗?
-
当然。在组件下拉菜单中,该值由所选选项设置,但我不能或无法在提交时将相同的值传递给控制台。我的意思是,表单没有从子组件中获得任何更改。这可能很明显,但我不明白。我不是一个编码员。 :(
-
嗯。我认为您想将一个值传递给 Dropdown,当您选择一个项目时该值将被更新。正确的?如果是这样,您将需要两件事。值和更新它的函数。就像普通的
-
如果我误解了这一点,我很抱歉,但不是反过来吗?子组件
<Dropdown>在[selectedOption, setSelectedOption] = useState(null)中已经有这样的功能(或类似的东西)来设置“初始选项”,然后onOptionClick = value => () => {...}更改 selectedOption 的状态,因此它会正确显示在标题上,你知道,模拟<select>行为。我想知道这是否与您告诉我的相同,或者我是否错了。目标是在父组件上获取这个selectedOption值,以便表单在提交时发布它? -
在 Dropdown 中拥有本地状态主要取决于您的偏好。但是,是的,我明白你的意思。让我写一个答案
标签: javascript reactjs react-hook-form