//自定义的hook
import { useState, useCallback } from 'react';
// 自定义Hook:表单验证
const useName = (initialValue = '') => {
// 状态管理:字段值和错误信息
const [value, setValue] = useState(initialValue);
const [error, setError] = useState('');
const [touched, setTouched] = useState(false);
// 验证函数:检查用户名是否为空
const validateField = useCallback((fieldValue) => {
if (!fieldValue || fieldValue.trim() === '') {
return '用户名是必填项';
}
return ''; // 空字符串表示验证通过
}, []);
// 处理输入变化
const handleChange = useCallback((e) => {
const newValue = e.target.value;
setValue(newValue);
// 如果字段已经被触摸过,实时验证
if (touched) {
const validationError = validateField(newValue);
setError(validationError);
}
}, [touched, validateField]);
// 处理失去焦点事件
const handleBlur = useCallback(() => {
setTouched(true);
const validationError = validateField(value);
setError(validationError);
}, [value, validateField]);
// 手动验证函数(可用于提交前验证)
const validate = useCallback(() => {
setTouched(true);
const validationError = validateField(value);
setError(validationError);
return validationError === ''; // 返回布尔值表示是否有效
}, [value, validateField]);
// 重置字段
const reset = useCallback(() => {
setValue(initialValue);
setError('');
setTouched(false);
}, [initialValue]);
// 返回给组件使用的API
return {
// 状态
value,
error,
touched,
isValid: error === '', // 便捷的有效性检查
// 方法
handleChange,
handleBlur,
validate,
reset,
setValue,
// 便捷的对象展开(用于直接绑定到input)
fieldProps: {
value,
onChange: handleChange,
onBlur: handleBlur,
}
};
};
export default useName;
//使用自定义的hook
import React from 'react';
import useName from './useName';
const NameForm = () => {
// 使用自定义Hook
const username = useName('');
const handleSubmit = (e) => {
e.preventDefault();
// 提交前进行最终验证
const isValid = username.validate();
if (isValid) {
// 验证通过,处理提交逻辑
console.log('用户名有效:', username.value);
alert(`用户名 "${username.value}" 验证通过!`);
} else {
console.log('表单有错误,请检查');
}
};
return (
<div style={{ maxWidth: '400px', margin: '50px auto', padding: '20px' }}>
<h2>用户名验证示例</h2>
<form onSubmit={handleSubmit}>
<div style={{ marginBottom: '20px' }}>
<label htmlFor="username" style={{ display: 'block', marginBottom: '5px' }}>
用户名:
</label>
<input
type="text"
id="username"
// 使用fieldProps便捷绑定
{...username.fieldProps}
style={{
width: '100%',
padding: '8px',
border: username.error && username.touched ? '2px solid red' : '1px solid #ccc',
borderRadius: '4px'
}}
placeholder="请输入用户名"
/>
{/* 错误提示 */}
{username.error && username.touched && (
<span style={{ color: 'red', fontSize: '14px', marginTop: '5px', display: 'block' }}>
⚠️ {username.error}
</span>
)}
</div>
<button
type="submit"
style={{
width: '100%',
padding: '10px',
backgroundColor: username.isValid ? '#007bff' : '#ccc',
color: 'white',
border: 'none',
borderRadius: '4px',
cursor: username.isValid ? 'pointer' : 'not-allowed'
}}
disabled={!username.isValid}
>
提交
</button>
</form>
{/* 调试信息 */}
<div style={{
marginTop: '30px',
padding: '15px',
backgroundColor: '#f5f5f5',
borderRadius: '4px',
fontSize: '14px'
}}>
<h4>调试信息:</h4>
<p>当前值: <strong>"{username.value}"</strong></p>
<p>是否触摸过: <strong>{username.touched ? '是' : '否'}</strong></p>
<p>是否有效: <strong>{username.isValid ? '是' : '否'}</strong></p>
{username.error && <p>错误信息: <strong style={{color: 'red'}}>{username.error}</strong></p>}
</div>
{/* 重置按钮 */}
<button
onClick={username.reset}
style={{
marginTop: '10px',
padding: '8px 16px',
backgroundColor: '#6c757d',
color: 'white',
border: 'none',
borderRadius: '4px',
cursor: 'pointer'
}}
>
重置表单
</button>
</div>
);
};
export default NameForm;
console