
一、3个高频场景实战:从重复代码到Hook封装
场景1:数据请求逻辑复用(useFetch)
问题:多个组件重复编写“加载中/错误处理/数据缓存”的API请求逻辑。
重复代码示例:
javascript
// 组件A:获取用户数据
function UserProfile() {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
fetch('/api/user')
.then(res => res.json())
.then(data => { setUser(data); setLoading(false); })
.catch(err => { setError(err); setLoading(false); });
}, []);
// ...渲染UI
}
// 组件B:获取商品列表(重复相同逻辑)
function ProductList() {
const [products, setProducts] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
fetch('/api/products')
.then(res => res.json())
.then(data => { setProducts(data); setLoading(false); })
.catch(err => { setError(err); setLoading(false); });
}, []);
// ...渲染UI
}
自定义Hook封装(useFetch):
javascript
// hooks/useFetch.js
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
const res = await fetch(url);
const result = await res.json();
setData(result);
} catch (err) {
setError(err);
} finally {
setLoading(false);
}
};
fetchData();
}, [url]);
return { data, loading, error }; // 返回状态供组件使用
}
组件使用Hook后:
javascript
// 组件A:获取用户数据(一行调用)
function UserProfile() {
const { data: user, loading, error } = useFetch('/api/user');
// ...渲染UI
}
// 组件B:获取商品列表(一行调用)
function ProductList() {
const { data: products, loading, error } = useFetch('/api/products');
// ...渲染UI
}
---
场景2:表单处理逻辑复用(useForm)
问题:多个表单组件重复处理“输入值绑定、表单提交、重置”逻辑。
自定义Hook封装(useForm):
javascript
// hooks/useForm.js
function useForm(initialValues) {
const [values, setValues] = useState(initialValues);
// 处理输入变化
const handleChange = (e) => {
const { name, value } = e.target;
setValues({ ...values, [name]: value });
};
// 重置表单
const resetForm = () => setValues(initialValues);
return { values, handleChange, resetForm };
}
组件使用:
javascript
function LoginForm() {
const { values, handleChange, resetForm } = useForm({
username: '',
password: ''
});
const handleSubmit = (e) => {
e.preventDefault();
console.log('提交数据:', values);
};
return (
<form onSubmit={handleSubmit}>
<input
name="username"
value={values.username}
onChange={handleChange}
placeholder="用户名"
/>
<input
name="password"
type="password"
value={values.password}
onChange={handleChange}
placeholder="密码"
/>
<button type="submit">登录</button>
<button type="button" onClick={resetForm}>重置</button>
</form>
);
}
---
场景3:窗口大小监听复用(useWindowSize)
问题:多个组件需要监听窗口大小变化(如响应式布局),重复编写useEffect+事件监听。
自定义Hook封装(useWindowSize):
javascript
// hooks/useWindowSize.js
function useWindowSize() {
const [size, setSize] = useState({
width: window.innerWidth,
height: window.innerHeight
});
useEffect(() => {
const handleResize = () => {
setSize({
width: window.innerWidth,
height: window.innerHeight
});
};
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize); // 清理
}, []);
return size;
}
组件使用:
javascript
function ResponsiveComponent() {
const { width, height } = useWindowSize();
return (
<div>
窗口大小:{width}x{height}
{width < 768 ? <MobileUI /> : <DesktopUI />}
</div>
);
}
---
二、自定义Hook核心原则
- 命名规范:必须以use开头(如useFetch),确保React能识别Hook规则。
- 单一职责:一个Hook只封装一个逻辑(如useFetch只处理数据请求,不掺杂表单逻辑)。
- 依赖清晰:Hook内部使用useEffect等时,需正确声明依赖数组(如[url]),避免无限循环。
---
三、对比传统复用方案(HOC/Render Props)

)
)
)
)
)
)
)
)
)
)
)
)
)
上架最便宜Cybertruck 最贵Cyberbeast亦降价(2398.4万美元))
)
)