为了提高我的React技能,我一直在尝试构建一个可重用的表单状态挂钩和表单验证器。我的自定义钩子FormState使用空字符串初始化一个对象,该对象的值将用作我的钩子的初始状态。我编写了一个函数clearInputs,我希望将输入重置为初始状态,但是无法更新。
我一直在四处寻找答案,甚至提到了这个Stack Overflow帖子:Reset to Initial State with React Hooks。仍然没有骰子。
// MY FORMSTATE HOOK
import { useState } from 'react';
const FormState = props => {
let initialState = { ...props };
const [ inputs, setInputs ] = useState(initialState);
const [ errors, setErrors ] = useState(initialState);
const handleInput = e =>
setInputs({
...inputs,
[e.target.name]: e.target.value
});
const handleError = errs => setErrors({ ...errors, ...errs });
const resetForm = () => {
setInputs({ ...initialState });
setErrors({ ...initialState });
};
const clearInputs = () => {
console.log('SUPPOSED TO CLEAR', initialState)
console.log('MY INPUTS', inputs)
setInputs({ ...initialState });
console.log('AFTER THE SETTING', inputs)
};
return [ inputs, handleInput, errors, handleError, resetForm, clearInputs ];
};
export default FormState;
// REGISTER FORM
import React, { useEffect } from 'react';
import { connect } from 'react-redux';
import FormState from './formState';
import Field from './field';
import { registerUser } from '../../actions/users';
import './forms.css';
const RegisterForm = props => {
const isLoggedIn = localStorage.getItem('user');
useEffect(
() => {
if (isLoggedIn) {
const parsedUser = JSON.parse(isLoggedIn);
props.history.push(`/profile/${parsedUser.pk}`);
}
},
[ isLoggedIn ]
);
const initialInputs = {
username: '',
password1: '',
password2: '',
first_name: '',
last_name: ''
};
const [ inputs, handleInput, errors, handleErrors, resetForm, clearInputs ] = FormState(initialInputs);
const handleSubmit = e => {
e.preventDefault();
const validForm = validate(inputs, handleErrors);
if (validForm) {
props.registerUser(inputs);
resetForm();
}
else {
clearInputs();
}
};
return (
<div className='form-wrap'>
<h1>Register Here</h1>
<form className='form' onSubmit={handleSubmit}>
<Field
label='Username'
fieldname='username'
value={inputs.username}
placeholder='Enter Your Username'
fielderror={errors.username}
handleInput={handleInput}
classNames='form-section'
/>
<Field
label='Password'
fieldname='password1'
value={inputs.password1}
placeholder='Enter Your Password'
fielderror={errors.password1}
handleInput={handleInput}
classNames='form-section'
/>
<Field
label='Confirm Password'
fieldname='password2'
value={inputs.password2}
placeholder='Confirm Your Password'
fielderror={errors.password2}
handleInput={handleInput}
classNames='form-section'
/>
<Field
label='First Name'
fieldname='first_name'
value={inputs.first_name}
placeholder='Enter Your First Name'
fielderror={errors.first_name}
handleInput={handleInput}
classNames='form-section'
/>
<Field
label='Last Name'
fieldname='last_name'
value={inputs.last_name}
placeholder='Enter Your Last Name'
fielderror={errors.last_name}
handleInput={handleInput}
classNames='form-section'
/>
<button type='submit' className='submit-button'>
Submit
</button>
</form>
</div>
);
};
const validate = (inputs, handleErrors) => {
let errs = {};
const { username, password1, password2, first_name, last_name } = inputs;
if (!username) {
errs.username = 'Username is missing';
}
if (!password1) {
errs.password1 = 'Password is missing';
}
if (!password2) {
errs.password2 = 'Confirm password is missing';
}
if (!first_name) {
errs.first_name = 'First name is required';
}
if (!last_name) {
errs.last_name = 'Last name is required';
}
if (username.length < 6) {
errs.username = 'Username is too short';
}
if (password1.length < 8) {
errs.password1 = 'Password is too short';
}
if (password1 !== password2) {
errs.password1 = 'Passwords must match';
errs.password2 = 'Passwords must match';
}
if (Object.keys(errs).length) {
handleErrors(errs);
return false;
}
else {
return true;
}
};
const mapStateToProps = state => {
return {
loggedInUser: state.users.loggedInUser,
registerPending: state.users.registerPending,
registerError: state.users.registerError
};
};
const mapDispatchToProps = dispatch => {
return {
registerUser: newUser => {
dispatch(registerUser(newUser));
}
};
};
export default connect(mapStateToProps, mapDispatchToProps)(RegisterForm);
触发clearInputs时,应将输入重置为初始状态。相反,什么也没有发生。任何帮助都非常感谢。
编辑: 让我进一步澄清。我表单中的每个字段都从输入(用户名,密码1等)传递一个值。调用clearInputs时,它会清除钩子中的输入,但不会清除Field中的值。
答案 0 :(得分:0)
您的clearInputs
函数按预期运行。 setInputs
返回的useState
函数是异步的,导致您的“ AFTER THE SETTING”控制台日志在更新后显示inputs
的值。
您的自定义钩子的基本用法在这里可以正常使用。.https://codesandbox.io/s/jznpk7w85w
顺便说一句,您应该在自定义挂钩名称前加上use
。https://reactjs.org/docs/hooks-custom.html#extracting-a-custom-hook
答案 1 :(得分:0)
关于为什么登录不正确,必须理解这一点:每次调用钩子时(基本上在每个表单渲染器上),都会创建一个新的clearInputs函数,该函数具有自己的inputs
版本。因此,在clearInputs函数本身中,inputs
无法更改,因为它们来自作用域中较高的位置useState。
如果您想注意到两次钩子调用之间的变化,则可以在返回[inputs,...]之前登录inputs
。
同样,在您的钩子中,您没有调用setInputs
,而是定义了一个clearInputs
函数,该函数将触发状态更改,将重新呈现您的组件,该函数将一次使用您的钩子再次,您的钩子将读取inputs
的新值,并创建一个新的clearInputs
函数。