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

React集成Isotope.js过滤功能报错:isotope不是函数求助

解决React集成Isotope.js的isotope is not a function报错

嘿,我刚帮人解决过一模一样的问题!你遇到的TypeError: ...isotope is not a function报错,本质是jQuery和Isotope的集成方式不对,而且在React里硬套jQuery操作DOM也不是最佳实践,咱们一步步来搞定:

报错原因分析

  • 现在的Isotope版本已经原生支持JS调用,不需要依赖jQuery了,你用$(...).isotope()的方式调用时,jQuery并没有注册这个方法,所以报错
  • 另外你代码里的portfolioIsotope变量根本没定义,这也是个隐藏bug

具体修复步骤

1. 移除不必要的jQuery依赖

直接删掉代码里的import $ from 'jquery';,Isotope完全可以用原生JS初始化和操作。

2. 正确初始化Isotope并绑定过滤事件

修改componentDidMount方法,用原生JS创建Isotope实例,同时用原生事件绑定处理过滤按钮的点击,还要注意this的指向:

componentDidMount() {
  // 初始化Isotope实例,保存到组件属性里方便后续调用
  this.isotopeInstance = new Isotope(this.portGridRef.current, {
    itemSelector: '.portfolio-item', // 必须和PortfolioItem组件的根元素class对应
    layoutMode: 'fitRows' // 根据你的布局需求调整,比如masonry等
  });

  // 获取所有过滤按钮,绑定点击事件
  const filterButtons = document.querySelectorAll('#portfolio-flters li');
  filterButtons.forEach(button => {
    button.addEventListener('click', (e) => {
      // 移除所有按钮的激活状态
      filterButtons.forEach(btn => btn.classList.remove('filter-active'));
      // 给当前点击的按钮添加激活状态
      e.target.classList.add('filter-active');
      // 获取过滤规则并执行过滤
      const filterValue = e.target.getAttribute('data-filter');
      this.isotopeInstance.arrange({ filter: filterValue });
    });
  });
}

3. 确保PortfolioItem组件的类名正确

你的PortfolioItem组件根元素必须包含对应的过滤类,比如根据category属性生成filter-app、filter-card这类类名,示例如下:

// PortfolioItem.js的render部分
return (
  <div className={`portfolio-item filter-${this.props.category.toLowerCase()}`}>
    {/* 你的项目内容,比如图片、标题等 */}
    <img src={this.props.image} alt={this.props.title} />
    <h3>{this.props.title}</h3>
  </div>
);

这样Isotope才能正确识别需要过滤的元素。

4. 修正shouldComponentUpdate的问题

你现在设置shouldComponentUpdate() { return false; }会让组件永远不更新,如果后续PortfolioData有变化,页面完全不会同步。除非你确定数据永远不会变,否则建议删掉这个方法,或者改成基于props/state变化的判断逻辑。

5. 清理资源避免内存泄漏

在组件卸载时销毁Isotope实例,避免内存泄漏:

componentWillUnmount() {
  if (this.isotopeInstance) {
    this.isotopeInstance.destroy();
  }
}

修改后的完整代码

import React, { Fragment } from 'react';
import Header from './Components/Header';
import Footer from './Components/Footer';
import Breadcrumb from './Components/Breadcrumb';
import PortfolioItem from './Components/PortfolioItem';
import Isotope from 'isotope-layout';
import PortfolioData from './portoflio.json';

class Portfolio extends React.Component {
  constructor(props) {
    super(props);
    this.portGridRef = React.createRef();
    this.isotopeInstance = null; // 保存Isotope实例
  }

  componentDidMount() {
    // 初始化Isotope
    this.isotopeInstance = new Isotope(this.portGridRef.current, {
      itemSelector: '.portfolio-item',
      layoutMode: 'fitRows'
    });

    // 绑定过滤按钮点击事件
    const filterButtons = document.querySelectorAll('#portfolio-flters li');
    filterButtons.forEach(button => {
      button.addEventListener('click', (e) => {
        filterButtons.forEach(btn => btn.classList.remove('filter-active'));
        e.target.classList.add('filter-active');
        const filterValue = e.target.getAttribute('data-filter');
        this.isotopeInstance.arrange({ filter: filterValue });
      });
    });
  }

  componentWillUnmount() {
    // 卸载时清理Isotope实例
    if (this.isotopeInstance) {
      this.isotopeInstance.destroy();
    }
  }

  render() {
    return (
      <Fragment>
        <Header/>
        <main id="main">
          <Breadcrumb currentPage="Portfolio"/>
          <section id="portfolio" className="portfolio">
            <div className="container">
              <div className="section-title">
                <h2>Our Portfolio</h2>
              </div>
              <div className="row" >
                <div className="col-lg-12">
                  <ul id="portfolio-flters">
                    <li data-filter="*" className="filter-active">All</li>
                    <li data-filter=".filter-app">App</li>
                    <li data-filter=".filter-card">Card</li>
                    <li data-filter=".filter-web">Web</li>
                  </ul>
                </div>
              </div>
              <div className="row portfolio-container" ref={this.portGridRef}>
                { PortfolioData.map((currentItem, index) => {
                  return <PortfolioItem 
                    key={index} 
                    title={currentItem.title} 
                    category={currentItem.category} 
                    image={currentItem.image} 
                  />
                }) }
              </div>
            </div>
          </section>
        </main>
        <Footer/>
      </Fragment>
    );
  }
}

export default Portfolio;

这样修改后,不仅解决了报错问题,还更符合React的组件化思想,避免了不必要的jQuery依赖,同时也修复了未定义变量的潜在bug。

内容的提问来源于stack exchange,提问作者Agraj Yadav

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 19:37:31