在 react-hook-form 的 useFieldArray 上异步调用 reset 时,reset 无法正常工作
When reset is called asynchronously on react-hook-form's useFieldArray, reset doesn't work correctly
我正在使用 react-hook-form 和 react-navigation。在我的用例中,我使用 useFieldArray
来控制不断增长的输入数组,并且我想在用户按下 HeaderBackButton
时 reset
表单。但是当我将 reset
传递给 HeaderBackButton
的 onPress
道具并按下按钮时,只要字段数组有任何变化,就会出现 Cannot read properties of undefined (reading 'id')
的 react-hook-form 错误。
在下面的代码框中,您可以附加一个项目,然后单击 Reset
并重置表单。但是在附加项目后单击 Back
会产生错误。这个问题只出现在react-hook-form < 7.22.0
import React from "react";
import { useForm, useFieldArray, Controller } from "react-hook-form";
import ReactDOM from "react-dom";
import { HeaderBackButton } from '@react-navigation/stack';
import "./styles.css";
let renderCount = 0;
function App() {
const { control, handleSubmit, reset } = useForm({
defaultValues: {
loadState: "unloaded",
names: []
}
});
const { fields, append } = useFieldArray({
control,
name: "names"
});
renderCount++;
return (
<form>
<h1>Field Array </h1>
<p>1. Append using the append button. </p>
<p>2a. reset button works as expected</p>
<p>2b. Back button, which is a HeaderBackButton errors out when there is any change to the field array</p>
<span className="counter">Render Count: {renderCount}</span>
<HeaderBackButton tintColor={'#FFFFFF'}
labelVisible={true}
onPress={()=>{reset()}}
/>
<button type='button' onClick={()=>reset()}>reset</button>
<button type='button' onClick={()=>append('')}>append</button>
<ul>
{fields.map((item, index) => (
<Controller
key={item.id}
render={({ field }) => <input {...field} />}
name={`names[${index}]`}
control={control}
defaultValue={item.lastName}
/>
))}
</ul>
</form>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
已验证 react-hook-form 7.22.0 修复了这个问题。
但 7.22.0 中的修复仅使字段数组中的所有元素 undefined
。它没有清除字段数组,这仍然导致我的具体情况出现问题。
作者已确定问题的症结在于异步调用 reset
。库的更新 sandbox demonstrates that 7.22.2 完全解决了这个问题。
此代码在 react-hook-form 7.22.2 中按预期工作
import React from "react";
import { useForm, useFieldArray, Controller } from "react-hook-form";
import ReactDOM from "react-dom";
import { HeaderBackButton } from "@react-navigation/stack";
import "./styles.css";
let renderCount = 0;
function App() {
const { getValues, control, reset } = useForm({
defaultValues: {
loadState: "unloaded",
names: []
}
});
const { fields, append } = useFieldArray({
control,
name: "names"
});
renderCount++;
console.log(getValues());
return (
<form>
<h1>Field Array </h1>
<p>1. Append using the append button. </p>
<p>2a. reset button works as expected</p>
<p>
2b. Back button, which is a HeaderBackButton does clear out the
field array now
</p>
<span className="counter">Render Count: {renderCount}</span>
<HeaderBackButton
tintColor={"#FFFFFF"}
labelVisible={true}
onPress={() => reset({ names: [] })}
/>
<button type="button" onClick={() => reset({ names: [] })}>
reset
</button>
<button type="button" onClick={() => append({ name: "abc" })}>
append
</button>
<ul>
{fields.map((item, index) => (
<Controller
key={item.id}
render={({ field }) => <input value={field.value} />}
name={`names.${index}.name`}
control={control}
/>
))}
</ul>
</form>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
我正在使用 react-hook-form 和 react-navigation。在我的用例中,我使用 useFieldArray
来控制不断增长的输入数组,并且我想在用户按下 HeaderBackButton
时 reset
表单。但是当我将 reset
传递给 HeaderBackButton
的 onPress
道具并按下按钮时,只要字段数组有任何变化,就会出现 Cannot read properties of undefined (reading 'id')
的 react-hook-form 错误。
在下面的代码框中,您可以附加一个项目,然后单击 Reset
并重置表单。但是在附加项目后单击 Back
会产生错误。这个问题只出现在react-hook-form < 7.22.0
import React from "react";
import { useForm, useFieldArray, Controller } from "react-hook-form";
import ReactDOM from "react-dom";
import { HeaderBackButton } from '@react-navigation/stack';
import "./styles.css";
let renderCount = 0;
function App() {
const { control, handleSubmit, reset } = useForm({
defaultValues: {
loadState: "unloaded",
names: []
}
});
const { fields, append } = useFieldArray({
control,
name: "names"
});
renderCount++;
return (
<form>
<h1>Field Array </h1>
<p>1. Append using the append button. </p>
<p>2a. reset button works as expected</p>
<p>2b. Back button, which is a HeaderBackButton errors out when there is any change to the field array</p>
<span className="counter">Render Count: {renderCount}</span>
<HeaderBackButton tintColor={'#FFFFFF'}
labelVisible={true}
onPress={()=>{reset()}}
/>
<button type='button' onClick={()=>reset()}>reset</button>
<button type='button' onClick={()=>append('')}>append</button>
<ul>
{fields.map((item, index) => (
<Controller
key={item.id}
render={({ field }) => <input {...field} />}
name={`names[${index}]`}
control={control}
defaultValue={item.lastName}
/>
))}
</ul>
</form>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
已验证 react-hook-form 7.22.0 修复了这个问题。
但 7.22.0 中的修复仅使字段数组中的所有元素 undefined
。它没有清除字段数组,这仍然导致我的具体情况出现问题。
作者已确定问题的症结在于异步调用 reset
。库的更新 sandbox demonstrates that 7.22.2 完全解决了这个问题。
此代码在 react-hook-form 7.22.2 中按预期工作
import React from "react";
import { useForm, useFieldArray, Controller } from "react-hook-form";
import ReactDOM from "react-dom";
import { HeaderBackButton } from "@react-navigation/stack";
import "./styles.css";
let renderCount = 0;
function App() {
const { getValues, control, reset } = useForm({
defaultValues: {
loadState: "unloaded",
names: []
}
});
const { fields, append } = useFieldArray({
control,
name: "names"
});
renderCount++;
console.log(getValues());
return (
<form>
<h1>Field Array </h1>
<p>1. Append using the append button. </p>
<p>2a. reset button works as expected</p>
<p>
2b. Back button, which is a HeaderBackButton does clear out the
field array now
</p>
<span className="counter">Render Count: {renderCount}</span>
<HeaderBackButton
tintColor={"#FFFFFF"}
labelVisible={true}
onPress={() => reset({ names: [] })}
/>
<button type="button" onClick={() => reset({ names: [] })}>
reset
</button>
<button type="button" onClick={() => append({ name: "abc" })}>
append
</button>
<ul>
{fields.map((item, index) => (
<Controller
key={item.id}
render={({ field }) => <input value={field.value} />}
name={`names.${index}.name`}
control={control}
/>
))}
</ul>
</form>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);