You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React中函数内调用组件触发Invalid hook call错误求助

解决React组件Invalid hook call错误及状态管理问题

问题根源

  1. 错误调用组件:直接在filterProductList里调用Products(false, newFilteredProducts),违反React组件使用规则——组件只能在JSX中渲染,不能像普通函数一样直接调用,会导致Hook调用违规。
  2. 状态分散管理:两个组件独立渲染,没有共享状态的通道,无法实现筛选后更新产品列表的联动。
  3. Hook使用违规:Products组件里把useEffect嵌套在FetchData函数内部,React要求Hook必须在组件顶层调用。
  4. 组件参数接收错误:React组件的props是一个对象,直接用start, listOfFilteredProducts接收参数,无法正确获取传入值。
  5. 全局数组滥用:未定义的全局products数组直接push数据,不符合React状态更新逻辑。

修复方案:状态提升+统一根渲染

把产品数据、筛选逻辑的状态统一放到父组件中,让FilterMenu负责触发筛选操作,Products负责接收数据并渲染,通过父组件实现状态联动。

修改后的完整代码

import React, { useState, useEffect } from 'react';
import ReactDOM from 'react-dom/client';

// 请替换为实际的图片资源路径
import searchIcon from './assets/search-icon.png';
import cartImage from './assets/cart-icon.png';

function FilterMenu({ onFilter }) {
  return (
    <div className="filterMenu">
      <ul>
        <li><a>...</a></li>
        <li><a onClick={() => onFilter(null)}>ВСИЧКИ</a></li>
        <li><a onClick={() => onFilter('Гривни')}>ГРИВНИ</a></li>
        <li><a onClick={() => onFilter('ОГЪРЛИЦИ')}>ОГЪРЛИЦИ</a></li>
        <li><a onClick={() => onFilter('ПРЪСТЕНИ')}>ПРЪСТЕНИ</a></li>
        <li><a onClick={() => onFilter('ОБЕЦИ')}>ОБЕЦИ</a></li>
        <div className='filterSearchbar' id="filterSearchbar">
          <input type="text" className='filterText' id="filterText" />
          <img className="SearchIcon" src={searchIcon} />
        </div>
      </ul>
    </div>
  )
}

function Products({ productList }) {
  const items = productList.map((product, index) => (
    <div className="grid-item" key={product.id || index + 1}>
      <div className="picture">
        <img className="productPicture" src={'data:image/jpeg;base64,' + product.imageData} />
      </div>
      <div className="title"><a>{product.name} {product.weight}гр</a></div>
      <div className="price"><a>{product.price} лв.</a></div>
      <div className="cartImage">
        <img className="cart" src={cartImage} />
      </div>
    </div>
  ));

  return (
    <div className="grid-container">
      {items}
    </div>
  )
}

// 父组件统一管理状态
function App() {
  const [allProducts, setAllProducts] = useState([]);
  const [filteredProducts, setFilteredProducts] = useState([]);

  // 顶层调用useEffect获取API数据
  useEffect(() => {
    const fetchProducts = async () => {
      try {
        const response = await fetch("http://localhost:5104/Product");
        const data = await response.json();
        setAllProducts(data);
        setFilteredProducts(data); // 初始显示所有产品
      } catch (error) {
        console.error('获取产品数据失败:', error);
      }
    };
    fetchProducts();
  }, []);

  // 筛选函数,传给FilterMenu
  const handleFilter = (category) => {
    if (!category) {
      // 点击"ВСИЧКИ"时显示所有产品
      setFilteredProducts(allProducts);
      return;
    }
    const newFiltered = allProducts.filter(product => product.category.includes(category));
    setFilteredProducts(newFiltered);
  };

  return (
    <div>
      <FilterMenu onFilter={handleFilter} />
      <Products productList={filteredProducts} />
    </div>
  )
}

// 统一渲染根组件
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);

关键修改点说明

  1. 新增父组件App:集中管理所有产品数据allProducts和筛选后数据filteredProducts,负责API请求和筛选逻辑。
  2. FilterMenu改造:不再自行处理筛选状态,通过onFilter回调把筛选条件传给父组件,由父组件更新状态。
  3. Products改造:变为纯展示组件,仅接收父组件传递的productList并渲染,不再自行管理状态和API请求,避免Hook调用错误。
  4. 修正Hook使用:把API请求的useEffect直接放在App组件顶层,符合React Hook规则。
  5. 统一根渲染:不再分别渲染两个组件,将App作为根组件渲染,确保组件树完整性和状态联动。
  6. 替换for循环为map:用React推荐的map遍历数组生成元素,同时优先使用产品id作为key,无id则用index。

内容的提问来源于stack exchange,提问作者Руслан Василев

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 20:07:02