React.js をチェックして、このライブラリが Isotope.js とどのように連携できるかを理解しようとしています。 Reactのドキュメントには、他のライブラリとうまく連携すると書かれていますが、DOMを独自に変更するライブラリで使用することは、Reactを使用する意味がないようです。
誰かが私に説明できますか?Isotope.jsをレイアウトとして使用する私のWebアプリでReactを利用するにはどうすればよいですか?
React内で直接DOMを操作できます。これにより、既存のJSライブラリを統合したり、Reactで適切に処理されないカスタムニーズに対応したりできます。
あなたはここで例を見つけることができます:
そして、これがどのように見えるかです:
ReactとIsotopeのようなライブラリの統合に関する問題は、同じdomサブツリーを更新しようとする2つの異なるライブラリが存在することです。AsReact work差分を使用すると、それだけでdomを変更していると想定されます。
したがって、アイデアはReactコンポーネントを作成することであり、これは1回だけレンダリングされ、それ自体は更新されません。これは次の方法で確認できます。
shouldComponentUpdate: function() {
return false;
}
これを使用すると、次のことができます。
componentDidMount
で、Reactによってマウントされたdomノードの同位体を初期化しますそしてそれがすべてです。これで、Reactは、DOMのこの部分を二度と更新することはなく、Isotopeは、Reactに干渉することなく、自由に操作できます。
さらに、私が理解している限り、Isotopeはアイテムの動的リストで使用することを意図していないため、更新されないReactコンポーネントを持つことは理にかなっています。
これが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();
}
}
});
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 の使用を検討してください。
ComponentDidMountで新しいIsotopeオブジェクトを作成し、componentDidUpdateでアイテムをリロードする必要があります。
私の mixin を使用してそれを理解してください:)
私は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関数でローカル状態を更新し、それに基づいてボタンをレンダリングするだけです。
フックとの現代的な反応に対する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