React自定义Hook onClick传参触发规则报错,求问题原因及修正方案
问题分析与解决
问题描述
我开发了一个简单的React应用,通过jsonplaceholder API获取数据并展示,每条数据对应一个删除按钮。原本在User.js组件内实现了deleteUser函数,现希望将该函数封装为通用自定义Hook,但在向该Hook传参时触发如下错误:
React Hooks must be called in a React function component or a custom React Hook function react-hooks/rules-of-hooks
相关代码如下:
userDelete.js
import { useFetch } from "./useFetch"; export const useDelete = (userName) => { const { data, setData} = useFetch(); const newData = data.filter((dataItem) => dataItem.name !== userName); console.log(newData); setData(newData) };
useFetch.js
import { useState, useEffect } from "react"; export const useFetch = () => { const [loading, setLoading] = useState(false); const [data, setData] = useState([]); const url = `https://jsonplaceholder.typicode.com/users`; const fetchData = async () => { try { setLoading(true); const response = await fetch(url); const data = await response.json(); console.log(data); setData(data); setLoading(false); return; } catch (error) { console.log("Error", error); } }; useEffect(() => { fetchData(); }, []); return { loading, data, setData }; };
User.js
import { useFetch } from "../Hooks/useFetch"; import { useDelete } from "../Hooks/useDelete"; const Users = () => { const { loading, data, setData } = useFetch(); const deleteCallback = useDelete(data); const deleteUser = (userName) => { const newData = data.filter((dataItem) => dataItem.name !== userName); console.log("newData", newData); setData(newData); }; return ( <> <h1>Custom Hook Example</h1> {loading && <h4>Fetching Data...</h4>} {data.map((data, index) => ( <div key={index} style={{ border: "2px solid red", width: "fit-content", margin: "0 auto" }} > <p>Name: {data.name}</p> <article>Email: {data.email}</article> {/* <button onClick={(e) => deleteUser(data.name, e)}>Delete</button> */} <button onClick={() => useDelete(data.name)}>Delete</button> </div> ))} {data.length === 0 && ( <> <p>No Items to Show</p> </> )} </> ); }; export default Users;
错误原因
- 违反Hook调用规则:在按钮的
onClick事件回调中直接调用useDelete(data.name),Hook只能在React函数组件或自定义Hook的顶层作用域调用,不能在事件处理、循环、条件判断等嵌套逻辑里执行。 - 自定义Hook逻辑冗余:
useDelete内部重复调用useFetch,会导致每次执行删除时都重新发起API请求,且和组件中useFetch维护的状态是独立的,完全不符合复用删除逻辑的需求。
修正方案
重构useDelete Hook
让它接收组件中的data和setData作为参数,返回一个可复用的删除函数,而不是直接执行删除操作:
// userDelete.js export const useDelete = (data, setData) => { const deleteUser = (userName) => { const newData = data.filter(item => item.name !== userName); setData(newData); }; return deleteUser; };
修改User.js组件
在组件顶层调用useDelete,获取删除函数后绑定到按钮点击事件:
// User.js import { useFetch } from "../Hooks/useFetch"; import { useDelete } from "../Hooks/useDelete"; const Users = () => { const { loading, data, setData } = useFetch(); // 在组件顶层调用自定义Hook,传入数据和更新函数 const deleteUser = useDelete(data, setData); return ( <> <h1>Custom Hook Example</h1> {loading && <h4>Fetching Data...</h4>} {data.map((item, index) => ( <div key={index} style={{ border: "2px solid red", width: "fit-content", margin: "0 auto" }} > <p>Name: {item.name}</p> <article>Email: {item.email}</article> {/* 调用返回的删除函数,传入用户名 */} <button onClick={() => deleteUser(item.name)}>Delete</button> </div> ))} {data.length === 0 && ( <> <p>No Items to Show</p> </> )} </> ); }; export default Users;
useFetch.js保持原有代码不变即可。
内容的提问来源于stack exchange,提问作者Sachin
相关产品推荐
相关产品推荐

