在react中使用onFocus和onBlur显示隐藏表单字段



我正在制作一个表单,最初只显示一个输入字段,当它被聚焦时,它显示其他输入和提交按钮。

我还想隐藏所有这些额外的字段,如果表单失去焦点,而他们是空的。这是我无法实现的部分。

这是我的代码:我使用一个受控表单和一个状态来处理焦点。

const FoldableForm = () => {
const [formState, setFormState] = useState(defaultFormState);
const [hasFocus, setFocus] = useState(false);

const handleOnBlur = () => {
if (!formState.message.trim() && !formState.other_input.trim()) {
setFocus(false);
}
};
return (
<form
onFocus={() => setFocus(true)}
onBlur={handleOnBlur}
>
<textarea 
name="message" 
onChange={(e) => setFormState({ ...formState, message: e.target.value })}
/>
{hasFocus && (
<>
<input 
type="text" name="other_input" 
onChange={(e) => setFormState({ ...formState, message: e.target.other_input })}
/>
<button type="button">Post comment</button>
</>
)}
</form>
);
}

目前,如果我在文本区域中键入一些内容,则永远不会调用setFocus(false),因此它按预期工作。否则,如果我将其保留为空并单击另一个输入字段,则调用handleOnBlur函数,它将焦点设置为false,因此表单是'最小化'。

这是预期的,因为模糊事件(来自文本区域)在焦点事件(来自新输入字段)之前触发。所以我尝试使用setTimeout来检查,在几分之一秒后焦点事件是否已经发生。

为此,我使用了第二个状态(shouldShow),它在handleOnBlue函数中的setTimeout中更新。

setTimeout(() => {
if(!hasFocus) {
setShouldShow(false); // this should cause the form to minimize
}
}, 100);

然而,根据react的生命周期,传递给setTimeout函数的hasFocus的值是在调用时,而不是在执行时。所以这里的setTimeout是没有用的。

我也试过使用引用,但是我不能使它工作。

在你的情况下,我认为shouldShow状态的使用是多余的,你也可以避免使用超时,这可能导致错误。您可以利用FocusEvent。当模糊从一个输入和焦点到另一个同时发生时,防止隐藏额外的字段。

handleOnBlur函数应该是这样的:

const handleOnBlur = (e) => {
if (e.relatedTarget && e.relatedTarget.name === "other_input") return;
if (!formState.message.trim() && !formState.other_input.trim()) {
setFocus(false);
}
};

您可以在这个代码沙箱中找到一个工作示例。

这种方法的问题是,如果你有多个字段出现,你需要检查其中是否有一个是集中的,如下所示:

["other_input", "another_input"].includes(e.relatedTarget.name)

这种行为是因为JavaScript中的闭包。hasFocus的值不是在setTimeout内部执行回调时变量的值。它是执行onBlur回调时的值。

一个解决方案是使用功能更新。

定义一个包含hasFocusshouldShow的状态:

const [state, setState] = useState({ hasFocus: false, shouldShow: false });

当您尝试使用功能更新访问以前的状态时,您将获得最近的值:

setTimeout(() => {
setState((state) => {
if (!state.hasFocus) {
return { ...state, shouldShow: false };
}
return state;
});
}, 100);

codesandbox

另一个解决方案是拆除一个将hasFocus状态设置为false的函数,在我看来这要好得多。

相关内容

  • 没有找到相关文章

最新更新