这可能不是正确的问题。但是我遇到了一个自定义表单验证挂钩的问题,当通过http请求更新输入值时,该挂钩不会读取输入值。
如果您想尝试一下,这里是CodeSandbox。
这是自定义钩子useValidatedForm
const [
profileFormData,
profileFormValidation,
validateProfileForm,
getProfileFormData
] = useValidatedForm(
profileFormInitialState,
profileFormValidationDefinitions
);
我有profileFormInitialState
const [profileFormInitialState, setProfileFormInitialState] = useState({
firstName: ""
});
我在http请求(此刻为虚拟http请求)中更新了此状态
useEffect(() => {
const fn = "first name";
setProfileFormInitialState({
firstName: fn
});
setContent({ title: "My Personal Details" });
setLoading({ status: false });
}, []);
这是我的表单,已呈现到DOM。通过profileFormInitialState
状态设置输入值。
const form = (
<>
<FormControl
key={"profileForm"}
submit={profileFormSubmit}
form={profileFormData}
validation={profileFormValidation}
>
<InputControl
autoComplete="off"
type="text"
name="firstName"
placeholder={profileFormInitialState.firstName}
value={profileFormInitialState.firstName}
onInput={e =>
setProfileFormInitialState({ firstName: e.target.value })
}
onChange={e => e.preventDefault()}
label="First Name*"
columns="2"
position="left"
>
<ErrorMsg map="required" msg="First Name is required" />
</InputControl>
<InputButton
modifier={"Button--profile"}
disabled={!profileFormValidation.valid}
buttonText="Update Profile"
type="submit"
/>
</FormControl>
</>
);
下面是我的useValidatedForm
自定义钩子
import { useState } from "react";
import ValidaJS from "valida-js";
function stateFactory(fields) {
return Object.keys(fields).reduce((acc, key) => {
acc[key] = {
value: fields[key],
meta: {
touched: false,
dirty: false
}
};
return acc;
}, {});
}
function emptyErrorFactory(fields) {
return Object.keys(fields).reduce((acc, key) => {
acc[key] = [];
return acc;
}, {});
}
function rulesByNameFactory(descriptors, validators) {
const descriptorBy = descriptors.reduce((acc, descriptor) => {
acc[descriptor.type] = acc[descriptor.type];
acc[descriptor.name] = acc[descriptor.name]
? acc[descriptor.name].concat([descriptor])
: [descriptor];
return acc;
}, {});
return Object.keys(descriptorBy).reduce(
(acc, key) => {
acc[key] = ValidaJS.rulesCreator(validators, descriptorBy[key]);
return acc;
},
{ default: ValidaJS.rulesCreator(validators, descriptors) }
);
}
function getDataFromState(state) {
return Object.keys(state).reduce((acc, key) => {
acc[key] = state[key].value;
return acc;
}, {});
}
function extendsValidations(key, validation, newErrors = []) {
const newValidation = {
errors: {
...validation.errors,
[key]: newErrors
}
};
newValidation["valid"] = Object.keys(newValidation.errors).every(errorKey => {
return newValidation.errors[errorKey].length === 0;
});
return newValidation;
}
function onChangeHandlerByKey(
state,
key,
setState,
setValidation,
validation,
rulesBy
) {
return event => {
const newState = {
...state,
[key]: {
...state[key],
value:
event.currentTarget.type == "checkbox"
? event.currentTarget.checked
: event.currentTarget.value,
meta: {
...state[key].meta,
dirty: true
}
}
};
const newErrors = ValidaJS.validate(
rulesBy[key],
getDataFromState(newState)
).errors[key];
setState(newState);
setValidation(extendsValidations(key, validation, newErrors));
};
}
function onClickHandlerByKey(state, key, setState) {
return _ => {
setState({
...state,
[key]: {
...state[key],
meta: {
...state[key].meta,
touched: true
}
}
});
};
}
function formDataFactory(state, setState, setValidation, validation, rulesBy) {
return Object.keys(state).reduce((acc, key) => {
acc[key] = {
meta: state[key].meta,
input: {
value: state[key].value,
onClick: onClickHandlerByKey(
state,
key,
setState,
setValidation,
validation,
rulesBy
),
onChange: onChangeHandlerByKey(
state,
key,
setState,
setValidation,
validation,
rulesBy
)
}
};
return acc;
}, {});
}
const useValidatedForm = (
fields = {},
descriptors = [],
validators = ValidaJS.validators
) => {
const initialErrorsObj = emptyErrorFactory(fields);
const initialState = stateFactory(fields);
console.log("initial state = " + initialState.firstName.value);
const [state, setState] = useState(initialState);
console.log("state = " + state.firstName.value);
const [validation, setValidation] = useState({
valid: true,
errors: initialErrorsObj
});
const rulesBy = rulesByNameFactory(descriptors, validators);
const form = formDataFactory(
state,
setState,
setValidation,
validation,
rulesBy
);
const getData = () => getDataFromState(state);
const setData = data => setState(stateFactory(data));
const validate = () => {
const newValidations = ValidaJS.validate(
rulesBy.default,
getDataFromState(state)
);
setValidation({
...newValidations,
errors: { ...initialErrorsObj, ...newValidations.errors }
});
return newValidations.valid;
};
return [form, validation, validate, getData, setData];
};
export default useValidatedForm;
在useValidatedForm
函数中,我遇到的问题是,当我提交表单并调用此函数时,initialState
是正确的,它返回first name
,被使用作为state
的初始值,但state
将作为一个空字符串返回,直到我输入输入然后正确更新为止。因此,我不确定如何使此验证有效,因为它依赖于state
值并使用state
更新setState
值吗?任何帮助将不胜感激。
答案 0 :(得分:0)
调试代码时,您必须逐步进行操作:
从有问题的地方开始-> validateProfileForm->它从哪里来?
您的钩子返回的验证->验证从哪里获取数据?
上限状态变量->它从哪里来?
useState行147是useState从哪里获取它的值?
initialState->具有initialState正确的值吗?
是->为什么useState不使用initialState?
哦,等等,useState仅在第一次调用时才使用initialParameters,因此我无法使用该参数来重新初始化值。因为您之后设置了initialState,所以除非您使用setState
现在,您的选项是,仅在initialState更改时才使用setState(因为如果每次都被初始值所卡住,则使用setState),但是因为stateFactory始终返回一个新对象,所以我不建议使用(您必须进行深入比较)
OR
提供一种强制性的方法来重新初始化状态,这样您就不必处理可能令人讨厌的差异系统。
首先,您甚至在输入中获得“名字”的原因是,当表单应由您自己处理时,您用value={profileFormInitialState.firstName}
设置了它的值。