javascript React.js 和 Isotope.js

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25135261/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-28 04:01:23  来源:igfitidea点击:

React.js and Isotope.js

javascriptjquery-isotopereactjs

提问by user1091733

I'm checking out React.jsand trying to figure out how this library can work together with Isotope.js. The documentation of React says that it plays nicely with other libraries, but using it with library that changes DOM on its own seems like no sense of using React.

我正在查看React.js并试图弄清楚这个库如何与Isotope.js一起工作。React 的文档说它可以很好地与其他库一起使用,但是将它与自行更改 DOM 的库一起使用似乎没有使用 React 的意义。

Can someone explain to me, how can I take advantage of React in my webapp that uses Isotope.js as layout ?

有人可以向我解释一下,如何在使用 Isotope.js 作为布局的 web 应用程序中利用 React?

采纳答案by Sebastien Lorber

You can manipulate the dom directly inside React. This permits to integrate existing JS libraries or for custom needs not handled well by React.

你可以直接在 React 中操作 dom。这允许集成现有的 JS 库或用于 React 无法很好处理的自定义需求。

You can find an exemple here:

你可以在这里找到一个例子:

https://github.com/stample/gulp-browserify-react-phonegap-starter/blob/master/src/js/home/homeComponents.jsx#L22

https://github.com/stample/gulp-browserify-react-phonegap-starter/blob/master/src/js/home/homeComponents.jsx#L22

And here's what it looks like:

这是它的样子:

image

图片



The problem with integration of React and a library like Isotope is that you will end up having 2 different libraries trying to update the same dom subtree. As React work with diffs, it kind of assumes that it is alone modyfing the dom.

React 和 Isotope 之类的库集成的问题在于,您最终将有 2 个不同的库试图更新同一个 dom 子树。当 React 使用 diff 时,它有点假设它是单独修改 dom 的。

So the idea could be to create a React component that will render only one time, and will never update itself. You can ensure this with:

所以这个想法可能是创建一个只渲染一次并且永远不会更新自己的 React 组件。您可以通过以下方式确保这一点:

shouldComponentUpdate: function() { 
    return false; 
}

With this you can:

有了这个,你可以:

  • Use React to generate your isotope item html elements (you can also create them without React)
  • On componentDidMount, initialize isotope on the dom node mounted by React
  • 使用 React 生成您的同位素项目 html 元素(您也可以在没有 React 的情况下创建它们)
  • on componentDidMount,在React挂载的dom节点上初始化isotope

And that's all. Now React will never update this part of the dom again, and Isotope is free to manipulate it like it wants to without interfering with React.

就这样。现在 React 将永远不会再更新 dom 的这一部分,并且 Isotope 可以随意操作它,而不会干扰 React。

In addition, as far as I understand, Isotope is not intented to be used with a dynamic list of items so it makes sense to have a React component that never updates.

此外,据我所知,Isotope 并不打算与动态的项目列表一起使用,因此拥有一个永不更新的 React 组件是有意义的。

回答by James Broad

Here's a working version with Masonry, you should find it easy enough to port to Isotope (or use Masonry :)) http://jsfiddle.net/emy7x0dc/1/.

这是 Masonry 的工作版本,您应该会发现很容易移植到 Isotope(或使用 Masonry :))http://jsfiddle.net/emy7x0dc/1/

Here's the crux of the code that makes it work (and allow React to do its job).

这是使其工作(并允许 React 完成其工作)的代码的关键。

var Grid = React.createClass({
    displayName: 'Grid',

    getInitialState: function(){
        return {
            masonry: null
        }
    },

    // Wrapper to layout child elements passed in
    render: function () {
        var children = this.props.children;
        return (
            <div className="grid">
                {children}
            </div>
        );
    },

    // When the DOM is rendered, let Masonry know what's changed
    componentDidUpdate: function() {
        if(this.state.masonry) {
            this.state.masonry.reloadItems();
            this.state.masonry.layout();
        }
    },

    // Set up Masonry
    componentDidMount: function() {
        var container = this.getDOMNode();
        if(!this.state.masonry) {
            this.setState({
                masonry: new Masonry( container )
            });
        } else {
            this.state.masonry.reloadItems();
        }
    }
});

回答by Hubert

Here's an updated version of the above code posted by James:

这是 James 发布的上述代码的更新版本:

If you're using webpack, remember to modify your webpack configfor working with Isotope.

如果您正在使用 webpack,请记住修改您的 webpack 配置以使用 Isotope。

import React, { PureComponent } from 'react';
import ReactDOM from 'react-dom';
import Isotope from 'isotope-layout';

// Container for isotope grid
class ItemGrid extends PureComponent {
    constructor(props) {
        super(props);
        this.state = { isotope: null };
    }

    render() {
        return(
            <div className="item-grid">
                {this.props.children}
            </div>
        )
    }

    // set up isotope
    componentDidMount() {
        const node = ReactDOM.findDOMNode(this);
        if (!this.state.isotope) {
            this.setState({
                isotope: new Isotope( node )
            });
        } else {
            this.state.isotope.reloadItems();
        }
    }

    // update isotope layout
    componentDidUpdate() {
        if (this.state.isotope) {
            this.state.isotope.reloadItems();
            this.state.isotope.layout();
        }
    }
}

export default ItemGrid;

Usage:

用法:

Just pass the items you want to keep inside isotope into the ItemGrid component as children:

只需将要保留在同位素中的项目作为子项传递到 ItemGrid 组件中即可:

<ItemGrid>
    {data.map(object => (
      <Item key={object._id} name={object.name} imageUrl={object.imageUrl} />
    ))}
</ItemGrid>

Alternatives

备择方案

If you can, consider using react-masonry-component.

如果可以,请考虑使用react-masonry-component

回答by Sean Lee

My solution with useState and useEffect hooks, also works with dynamically generated filter keys and items. The trick is to initialize Isotope after the component is mounted, and call its "arrange" method everytime the filter keyword changes. You can achieve the same with componentDidMount and componentDidUpdate in a class component.

我的 useState 和 useEffect 钩子解决方案也适用于动态生成的过滤器键和项目。诀窍是在组件安装后初始化 Isotope,并在每次过滤器关键字更改时调用其“排列”方法。您可以在类组件中使用 componentDidMount 和 componentDidUpdate 实现相同的效果。

Demo: https://codepen.io/ilovepku/pen/zYYKaYy

演示:https: //codepen.io/ilovepku/pen/zYYKaYy

const IsotopeReact = () => {
  // store the isotope object in one state
  const [isotope, setIsotope] = React.useState(null);
  // store the filter keyword in another state
  const [filterKey, setFilterKey] = React.useState("*");

  // initialize an Isotope object with configs
  React.useEffect(() => {
    setIsotope(
      new Isotope(".filter-container", {
        itemSelector: ".filter-item",
        layoutMode: "fitRows"
      })
    );
  }, []);

  // handling filter key change
  React.useEffect(
    () => {
      if (isotope) {
        filterKey === "*"
          ? isotope.arrange({ filter: `*` })
        : isotope.arrange({ filter: `.${filterKey}` });
      }
    },
    [isotope, filterKey]
  );

  return (
    <>
      <ul>
        <li onClick={() => setFilterKey("*")}>Show Both</li>
        <li onClick={() => setFilterKey("vege")}>Show Veges</li>
        <li onClick={() => setFilterKey("fruit")}>Show Fruits</li>
      </ul>
      <hr />
      <ul className="filter-container">
        <div className="filter-item vege">
          <span>Cucumber</span>
        </div>
        <div className="filter-item fruit">
          <span>Apple</span>
        </div>
        <div className="filter-item fruit">
          <span>Orange</span>
        </div>
        <div className="filter-item fruit vege">
          <span>Tomato</span>
        </div>
      </ul>
    </>
  );
};

回答by Karén

You need to create new Isotope object on componentDidMount and reload items on componentDidUpdate.

您需要在 componentDidMount 上创建新的 Isotope 对象并在 componentDidUpdate 上重新加载项目。

Use my mixinto figure it out :)

使用我的mixin来弄清楚:)

回答by Iskeraet

Updated Hubert's answer to modern react with Hooks.

更新了休伯特对 Hooks 的现代反应的回答。

import React, { useEffect, useRef, useState } from 'react';
import Isotope from 'isotope-layout'

function IsoContainer (props){
    const isoRef = useRef()
    const [state, setState] = useState({ isotope: null })

    useEffect(() => {
        if (!state.isotope) {
            setState({
                isotope: new Isotope( isoRef.current )
            })
        } else if (state.isotope) {
            state.isotope.reloadItems()
        } 
    })

    return (
        <div ref={isoRef}>
            {props.children}
        </div>
    )
}

export default IsoContainer

回答by Luke V

I got Isotope working in React by following Amith's quick tutorial at this link. The key was to address filtering within the onClick function:

通过在此链接中遵循 Amith 的快速教程,我让 Isotope 在 React 中工作。关键是解决 onClick 函数中的过滤问题:

class Parent extends Component {
  constructor(props) {
    super(props);
    this.onFilterChange = this.onFilterChange.bind(this);
  }

  // Click Function
  onFilterChange = (newFilter) => {
    if (this.iso === undefined) {
      this.iso = new Isotope('#filter-container', {
        itemSelector: '.filter-item',
        layoutMode: "fitRows"
      });
    }
    if(newFilter === '*') {
      this.iso.arrange({ filter: `*` });
    } else {
      this.iso.arrange({ filter: `.${newFilter}` });
    }
  }

  render() {
    return(
      // Filter Buttons
      <ul id="portfolio-flters">
        <li data-filter="*" onClick={() => {this.onFilterChange("*")}}>All</li>
        <li data-filter="filter-one" onClick={() => {this.onFilterChange("filter-one")}}>One</li>
        <li data-filter="filter-two" onClick={() => {this.onFilterChange("filter-two")}}>Two</li>
      </ul>

      // Isotope Grid & items
      <div id="filter-container">
        <div className='filter-item filter-one'>
          // Item Content
        </div>
        <div className='filter-item filter-two'>
          // Item Content
        </div>
      </div>
    )
  }
}

It now works exactly like it did on my static jQuery site. If you want the filter buttons to change appearance when active you can simply update local state in the onFilterChange function and render the buttons based on that.

它现在的工作方式与在我的静态 jQuery 站点上完全一样。如果您希望过滤器按钮在活动时更改外观,您可以简单地更新 onFilterChange 函数中的本地状态并基于此渲染按钮。