I'm checking out React.js and 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.
Can someone explain to me, how can I take advantage of React in my webapp that uses Isotope.js as layout ?
As React work with diffs, it kind of assumes that it is alone modyfing the dom. 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 is just JavaScript, there is a very small API to learn, just a few functions and how to use them. After that, your JavaScript skills are what make you a better React developer. There are no barriers to entry. A JavaScript developer can become a productive React developer in a few hours.
It is called JSX, and it is a syntax extension to JavaScript. We recommend using it with React to describe what the UI should look like. JSX may remind you of a template language, but it comes with the full power of JavaScript. JSX produces React “elements”.
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/.
Here's the crux of the code that makes it work (and allow React to do its job).
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();
}
}
});
My solution with useRef, useState and useEffect hooks. It 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 every time the filter keyword changes.
Demo: https://codepen.io/ilovepku/pen/zYYKaYy
const IsotopeReact = () => {
// init one ref to store the future isotope object
const isotope = React.useRef()
// store the filter keyword in a state
const [filterKey, setFilterKey] = React.useState('*')
// initialize an Isotope object with configs
React.useEffect(() => {
isotope.current = new Isotope('.filter-container', {
itemSelector: '.filter-item',
layoutMode: 'fitRows',
})
// cleanup
return () => isotope.current.destroy()
}, [])
// handling filter key change
React.useEffect(() => {
filterKey === '*'
? isotope.current.arrange({filter: `*`})
: isotope.current.arrange({filter: `.${filterKey}`})
}, [filterKey])
const handleFilterKeyChange = key => () => setFilterKey(key)
return (
<>
<ul>
<li onClick={handleFilterKeyChange('*')}>Show Both</li>
<li onClick={handleFilterKeyChange('vege')}>Show Veges</li>
<li onClick={handleFilterKeyChange('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>
</>
)
}
UPDATE (17/11/21):
TypeScript Demo: https://codesandbox.io/s/react-isotope-typescript-i9x5v
Don't forget to also add @types/isotope-layout
as a dev dependency.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With