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
相关产品推荐
相关产品推荐

