React报错Invalid hook call,使用useState实现搜索筛选功能如何解决?
错误原因
- 你当前使用的是类组件(代码包含
this.setState、this.state等类组件专属语法),但React Hook 仅支持在函数组件顶层或者自定义Hook内部调用,禁止在类组件的实例方法、普通JS函数、条件/循环分支中调用。你将useState('')写在类组件的getSearchData实例方法中,完全不符合Hook使用规则,直接触发Invalid hook call报错。 - 额外逻辑问题:你将
searchTerm状态定义在getSearchData方法内部,但在render的input onChange事件中直接调用setSearchTerm,该变量不在onChange的作用域范围内,即使Hook可用也会触发变量未定义错误。
解决方案
这里提供两种适配方案,可根据你的开发需求选择:
方案1:保持类组件写法,移除Hook,用类组件state管理搜索词
- 在类组件的state初始化逻辑中新增
searchTerm字段:
constructor(props) { super(props); this.state = { productList: [], searchTerm: '' // 新增搜索词状态 // 其他原有state字段 } }
- 修改渲染区域的input onChange事件,用类组件的setState更新搜索词:
<input className="search-input" placeholder="Search..." type="text" onChange={event => this.setState({searchTerm: event.target.value})} />
- 改造
getSearchData方法,删除Hook调用,直接从类组件state取搜索词:
getSearchData(){ const searchTerm = this.state.searchTerm; return this.state.productList.filter((item)=>{ return item.name.toLowerCase().includes(searchTerm.toLocaleLowerCase()) }).map((item, index) => { return ( <li key={index}> <a onClick={(e) => this._navigateShop(route.product_details + "/" + item.id)}>{item.name}</a> </li> ) }) }
方案2:整体改为函数组件写法,符合Hook使用规则
如果你倾向于使用Hook开发,可以将整个组件重构为函数组件,示例代码如下:
import { useState, useEffect } from 'react'; // 其他依赖引入 function 你的组件名(props) { const [productList, setProductList] = useState([]); const [searchTerm, setSearchTerm] = useState(''); // 产品数据加载逻辑 const loadSearchData = async () => { const response = await getActiveProduct(null); if(response.code == API_SUCCESS){ setProductList(response.data.product); } } // 组件挂载时加载数据 useEffect(() => { loadSearchData(); }, []); // 导航方法改造(不需要this绑定) const _navigateShop = (path) => { // 原有导航逻辑 } // 搜索结果渲染逻辑 const searchResult = productList.filter((item)=>{ return item.name.toLowerCase().includes(searchTerm.toLocaleLowerCase()) }).map((item, index) => { return ( <li key={index}> <a onClick={(e) => _navigateShop(route.product_details + "/" + item.id)}>{item.name}</a> </li> ) }) // 组件渲染 return ( <div className="search-field collapse" id="searchToggle" > <input className="search-input" placeholder="Search..." type="text" onChange={event => setSearchTerm(event.target.value)} /> <a type="button" data-toggle="collapse" data-target="#searchToggle" aria-controls="searchToggle" aria-expanded="false"> <i className="icon_close search-close"></i> </a> <div className="search-dropdown"> {searchResult} </div> </div> // 其他原有组件内容 ) } export default 你的组件名;
内容的提问来源于stack exchange,提问作者Ace_kous471
相关产品推荐
相关产品推荐

