web-dev-qa-db-ja.com

React.jsとIsotope.js

React.js をチェックして、このライブラリが Isotope.js とどのように連携できるかを理解しようとしています。 Reactのドキュメントには、他のライブラリとうまく連携すると書かれていますが、DOMを独自に変更するライブラリで使用することは、Reactを使用する意味がないようです。

誰かが私に説明できますか?Isotope.jsをレイアウトとして使用する私のWebアプリでReactを利用するにはどうすればよいですか?

15
user1091733

React内で直接DOMを操作できます。これにより、既存のJSライブラリを統合したり、Reactで適切に処理されないカスタムニーズに対応したりできます。

あなたはここで例を見つけることができます:

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

そして、これがどのように見えるかです:

image


ReactとIsotopeのようなライブラリの統合に関する問題は、同じdomサブツリーを更新しようとする2つの異なるライブラリが存在することです。AsReact work差分を使用すると、それだけでdomを変更していると想定されます。

したがって、アイデアはReactコンポーネントを作成することであり、これは1回だけレンダリングされ、それ自体は更新されません。これは次の方法で確認できます。

shouldComponentUpdate: function() { 
    return false; 
}

これを使用すると、次のことができます。

  • Reactを使用して同位体アイテムのhtml要素を生成します(Reactなしで作成することもできます)
  • componentDidMountで、Reactによってマウントされたdomノードの同位体を初期化します

そしてそれがすべてです。これで、Reactは、DOMのこの部分を二度と更新することはなく、Isotopeは、Reactに干渉することなく、自由に操作できます。

さらに、私が理解している限り、Isotopeはアイテムの動的リストで使用することを意図していないため、更新されないReactコンポーネントを持つことは理にかなっています。

6

これがMasonryで動作するバージョンです。Isotopeに移植する(またはMasonryを使用する:)) http://jsfiddle.net/emy7x0dc/1/ に簡単に移植できるはずです。

これがそれを機能させるコードの核心です(そして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();
        }
    }
});
11
James Broad

Jamesによって投稿された上記のコードの更新バージョンは次のとおりです。

Webpackを使用している場合は、Isotopeを使用するために webpack構成を変更 を忘れないでください。

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

// Container for isotope grid
class ItemGrid extends Component {
    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;

使用法:

アイソトープ内に保持したいアイテムを子としてItemGridコンポーネントに渡すだけです。

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

代替案

可能であれば、 react-masonry-component の使用を検討してください。

5
Hubert

ComponentDidMountで新しいIsotopeオブジェクトを作成し、componentDidUpdateでアイテムをリロードする必要があります。

私の mixin を使用してそれを理解してください:)

3
Karén

私はIsotopeをReactでAmithのクイックチュートリアル このリンク に従って実行することで機能させました。重要なのは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>
    )
  }
}

これで、静的jQueryサイトとまったく同じように機能します。アクティブなときにフィルターボタンの外観を変更したい場合は、onFilterChange関数でローカル状態を更新し、それに基づいてボタンをレンダリングするだけです。

1
Luke V

フックとの現代的な反応に対するHubertの回答を更新しました。

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
1
Iskeraet