提问人:KaMZaTa 提问时间:3/17/2022 最后编辑:KaMZaTa 更新时间:10/22/2023 访问量:11246
React Hook Form 和页面重新加载的持久化数据
React Hook Form and persistent data on page reload
问:
我正在使用 React Hook Form v7,我正在尝试使我的数据表单在页面重新加载时持久化。我阅读了 RHF 的官方文档,其中建议使用小状态机,我试图实现它,但没有成功。有没有更好的方法?然而。。。
我在使用它时遇到的第一个问题是,我的数据是一个复杂的对象,所以它应该不那么容易。updateAction
第二个问题是我不知道何时以及如何触发updateAction来保存数据。我应该在输入模糊时触发它吗?关于输入更改?
这是我的测试代码:
答:
状态本身不会在页面重新加载时保留任何数据。
您需要将状态数据添加到本地存储。
然后将其加载回 on 状态(使用空依赖数组的 useEffect)。componentDidMount
const Form = () => {
const [formData, setFormData] = useState({})
useEffect(() => {
if(localStorage) {
const formDataFromLocalStorage = localStorage.getItem('formData');
if(formDataFromLocalStorage) {
const formDataCopy = JSON.parse(formDataFromLocalStorage)
setFormData({...formDataCopy})
}
}
}, []);
useEffect(() => {
localStorage && localStorage.setItem("formData", JSON.stringify(formData))
}, [formData]);
const handleInputsChange = (e) => {
setFormData({
...formData,
[e.target.name]: e.target.value
})
}
return (
<div>
<input
type="text"
name="firstName"
placeholder='first name'
onChange={e => handleInputsChange(e)}
value={formData?.firstName}
/>
<input
type="text"
name="lastName"
placeholder='last name'
onChange={e => handleInputsChange(e)}
value={formData?.lastName}
/>
</div>
)
}
评论
little-state-machine
methods.watch()
如果坚持localStorage对你有用,这是我实现它的方式。
定义用于持久化数据的自定义钩子
export const usePersistForm = ({
value,
localStorageKey,
}) => {
useEffect(() => {
localStorage.setItem(localStorageKey, JSON.stringify(value));
}, [value, localStorageKey]);
return;
};
只需在表单组件中使用它即可
const FORM_DATA_KEY = "app_form_local_data";
export const AppForm = ({
initialValues,
handleFormSubmit,
}) => {
// useCallback may not be needed, you can use a function
// This was to improve performance since i was using modals
const getSavedData = useCallback(() => {
let data = localStorage.getItem(FORM_DATA_KEY);
if (data) {
// Parse it to a javaScript object
try {
data = JSON.parse(data);
} catch (err) {
console.log(err);
}
return data;
}
return initialValues;
}, [initialValues]);
const {
handleSubmit,
register,
getValues,
formState: { errors },
} = useForm({ defaultValues: getSavedData() });
const onSubmit: SubmitHandler = (data) => {
// Clear from localStorage on submit
// if this doesn’t work for you, you can use setTimeout
// Better still you can clear on successful submission
localStorage.removeItem(FORM_DATA_KEY);
handleFormSubmit(data);
};
// getValues periodically retrieves the form data
usePersistForm({ value: getValues(), localStorageKey: FORM_DATA_KEY });
return (
<form onSubmit={handleSubmit(onSubmit)}>
...
</form>
)
}
评论
Uncaught TypeError: Cannot destructure property 'zip' of 'watch(...)' as it is undefined.
我已经遇到了这个问题,并通过创建一个名为 .但是由于您使用的是 React 钩子表单,因此它使代码有点复杂且不太干净!useLocalStorage
我建议你简单地使用轻量级软件包 react-hook-form-persist。
你唯一需要做的就是一个接一个地添加钩子。做!useFormPersist
useForm
import { useForm } from "react-hook-form";
import useFormPersist from "react-hook-form-persist";
const yourComponent = () => {
const {
register,
control,
watch,
setValue,
handleSubmit,
reset
} = useForm({
defaultValues: initialValues
});
useFormPersist("form-name", { watch, setValue });
return (
<TextField
title='title'
type="text"
label='label'
{...register("input-field-name")}
/>
...
);
}
评论
为 react-hook-form-persist 干杯。
继承@Hamidreza索尔塔尼的答案。但是遇到了一些问题,当设置时,页面重新加载不会持久化存储,而是取而代之。所以,我为表单写了一个包装器。defaultValues
defaultValues
export const usePersistForm = <
TFieldValues extends FieldValues = FieldValues,
TContext = any,
TTransformedValues extends FieldValues | undefined = undefined
>(
name: string,
props?: UseFormProps<TFieldValues, TContext>
): UseFormReturn<TFieldValues, TContext, TTransformedValues> => {
const hasStorage = window.sessionStorage.getItem(name)
const form = useFormPrimitive<TFieldValues, TContext, TTransformedValues>({
...(hasStorage ? omit(props, ["defaultValues"]) : props),
})
useFormPersist(name, form)
return form
}
react-use 有一个钩子,在这个用例中派上用场。useLocalStorage
import { useLocalStorage } from 'react-use';
var Demo = () => {
let [value, setValue, remove] = useLocalStorage('article', '',);
let {
register,
handleSubmit,
} = useForm({
defaultValues: {
article: value ?? '',
},
});
let onsubmit: SubmitHandler<ArticleInputType> = (data) => {
//...
remove();
};
return (
<form onSubmit={handleSubmit(onsubmit)}>
<input
{...register('article', {
required: 'This filed is required',
onChange: (e) => {
setValue(e.target.value);
},
})}
/>
</form>
);
};
评论