我创建了一些可在任何地方重用代码的逻辑。我有一个用于处理输入元素的 input.jsx 组件和用于管理所有内容的 use-form.js 自定义钩子,我有一个用于创建表单逻辑的基本表单组件。在基本表单组件中,我多次调用自定义钩子。这很乏味而且相当重复*所以我想在 input.jsx 组件中创建两个可重用的调用自定义钩子
input.component.jsx
const Input = (props) => {
return (
<div className={`form-control ${props.error && 'invalid'}`}>
<label htmlFor={props.id}>{props.label}</label>
<input
type={props.type}
id={props.id}
value={props.value}
onChange={props.changeHandler}
onBlur={props.blurHandler}
/>
{props.error && <p className="error-text">{props.label} must be entered!</p>}
</div>
);
};
使用-input.js
import { useReducer } from 'react';
const inputReducer = (state, action) => {
switch (action.type) {
case 'INPUT':
return { value: action.value, isTouched: state.isTouched };
case 'BLUR':
return { isTouched: true, value: state.value };
case 'RESET':
return { value: '', isTouched: false };
}
return state;
};
export const useInput = (validateValue) => {
const [state, dispatch] = useReducer(inputReducer, {
value: '',
isTouched: false,
});
const valueIsValid = validateValue(state.value);
const error = !valueIsValid && state.isTouched;
const valueChangeHandler = (e) => {
dispatch({ type: 'INPUT', value: e.target.value });
};
const inputBlurHandler = () => {
dispatch({ type: 'BLUR' });
};
const reset = () => {
dispatch({ type: 'RESET' });
};
return {
value: state.value,
isValid: valueIsValid,
error,
valueChangeHandler,
inputBlurHandler,
reset,
};
};
basic-form.component.jsx
import { useInput } from '../hooks/use-input';
import Input from './input.component';
const BasicForm = () => {
const {
value: name,
isValid: nameIsValid,
error: nameHasError,
valueChangeHandler: nameChangeHandler,
inputBlurHandler: nameBlurHandler,
reset: nameReset,
} = useInput((value) => value.trim() !== '');
const {
value: surname,
isValid: surnameIsValid,
error: surnameHasError,
valueChangeHandler: surnameChangeHandler,
inputBlurHandler: surnameBlurHandler,
reset: surnameReset,
} = useInput((value) => value.trim() !== '');
const {
value: email,
isValid: emailIsValid,
error: emailHasError,
valueChangeHandler: emailChangeHandler,
inputBlurHandler: emailBlurHandler,
reset: emailReset,
} = useInput((value) => /^\S+@\S+\.\S+$/.test(value));
let formIsValid = false;
if (nameIsValid && surnameIsValid && emailIsValid) {
formIsValid = true;
}
const formSubmitHandler = (e) => {
e.preventDefault();
nameReset();
surnameReset();
emailReset();
};
return (
<form onSubmit={formSubmitHandler}>
<div className="control-group">
<Input
id="name"
label="First Name"
type="text"
error={nameHasError}
value={name}
changeHandler={nameChangeHandler}
blurHandler={nameBlurHandler}
/>
<Input
id="surname"
label="Last Name"
type="text"
error={surnameHasError}
value={surname}
changeHandler={surnameChangeHandler}
blurHandler={surnameBlurHandler}
/>
<Input
id="email"
label="Email"
type="email"
error={emailHasError}
value={email}
changeHandler={emailChangeHandler}
blurHandler={emailBlurHandler}
/>
</div>
<div className="form-actions">
<button disabled={!formIsValid}>Submit</button>
</div>
</form>
);
};
export default BasicForm;
问题是我们必须从 input.jsx 返回两个值到 basic-form.jsx。第一个值显示属性 isValid
与否。其次,一个函数,用于重置每个单独的输入元素。此外,我们必须接收一个函数来验证从父组件到子组件的逻辑。我们如何解决这个问题?我认为我们应该使用 useRef
、useImperativeHandle
和 forwardRef
但如何使用?
请投票让更多人看到。