这可能不是正确的问题。但是我遇到了自定义表单验证挂钩的问题,当通过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
值?任何帮助将不胜感激。
在调试代码时,您必须一步一步地进行:
所以现在,您的选项是,仅在initialState更改时使用setState(因为如果您每次都使用初始值时都这样做),但是因为您的stateFactory总是返回一个新对象,所以我不推荐(你必须深入比较)
要么
提供重新初始化状态的必要方法,这样您就不必处理可能烦人的差异系统。
此外,您首先在输入中获得“名字”的原因是因为您使用value={profileFormInitialState.firstName}
设置它的值,当您的表单应该是为您处理的那个。