Open dylannirvana opened 5 years ago
Hello! Thanks for reporting this issue.
Alas, I do not React expertise so I don't have an answer here. Maybe someone else can chime in?
I wouldn't complicate things and stick to the original packery package that gets frequent updates. If you want to set it up in React you can do something like this:
(raw paste of code in progress... everything helps right?)
import React, { Component } from 'react';
import Packery from 'packery';
import Draggabilly from 'draggabilly';
import ProductCard from './cards/ProductCard';
const COMPONENT_NAME = 'StyleGuide';
/** Class representing the styleguide. */
export default class StyleGuide extends Component {
constructor(props) {
super(props);
this.packeryContainer = React.createRef();
this.initializePackery = this.initializePackery.bind(this);
this.handleDragItemPositioned = this.handleDragItemPositioned.bind(this);
this.runPackery = this.runPackery.bind(this);
}
/**
* Create packery instance and bind draggabilly to each `.js-col`.
* @function componentDidMount
*/
componentDidMount() {
this.initializePackery();
this.packery.on('dragItemPositioned', this.handleDragItemPositioned);
}
/**
* Remove event listeners and destroy packery instance.
* @function componentWillUnmount
*/
componentWillUnmount() {
// TODO: test this
this.packery.unbindDraggabillyevents();
this.packery.packery('destroy');
}
/**
* Creates a packery instance and creates a
* draggabilly instance for each packery item element.
* @function initializePackery
*/
initializePackery() {
this.packery = new Packery(this.packeryContainer.current, {
columnWidth: '.js-col',
itemSelector: '.js-col',
percentPosition: true,
});
this.packery.getItemElements().forEach((itemElem) => {
const draggie = new Draggabilly(itemElem, {
containment: '.js-row',
handle: '.js-drag-handle',
});
this.packery.bindDraggabillyEvents(draggie);
});
}
/**
* Pass this function to cards to execute when image is loaded
* so that packery runs again and properly positions everything.
* @function runPackery
*/
runPackery() {
this.packery.shiftLayout();
}
/**
* Renders all HTML elements with their default styling
* and all reuseable components.
* @function render
*/
render() {
return (
<main className={`${COMPONENT_NAME}`}>
<div className={`${COMPONENT_NAME}__content`}>
<h1>
Cards
</h1>
<p>
Cards ordered in a grid with packery as they will be displayed on the pages.
The images serve as a grab handle for dragging.
</p>
<section className="row row--with-padding js-row" ref={this.packeryContainer}>
<div className="col-12 col-sm-md-8 col-lg-xl-6 col--with-padding js-col js-holder-1">
<ProductCard executeOnResize={this.runPackery} />
</div>
<div className="col-12 col-sm-md-8 col-lg-xl-6 col--with-padding js-col js-holder-2">
<ProductCard executeOnResize={this.runPackery} />
</div>
<div className="col-12 col-sm-md-8 col-lg-xl-6 col--with-padding js-col js-holder-3">
<ProductCard executeOnResize={this.runPackery} />
</div>
<div className="col-12 col-sm-md-8 col-lg-xl-6 col--with-padding js-col js-holder-4">
<ProductCard executeOnResize={this.runPackery} />
</div>
<div className="col-12 col-sm-md-8 col-lg-xl-6 col--with-padding js-col js-holder-5">
<ProductCard executeOnResize={this.runPackery} />
</div>
<div className="col-12 col-sm-md-8 col-lg-xl-6 col--with-padding js-col js-holder-6">
<ProductCard executeOnResize={this.runPackery} />
</div>
<div className="col-12 col-sm-md-8 col-lg-xl-6 col--with-padding js-col js-holder-7">
<ProductCard executeOnResize={this.runPackery} />
</div>
<div className="col-12 col-sm-md-8 col-lg-xl-6 col--with-padding js-col js-holder-8">
<ProductCard executeOnResize={this.runPackery} />
</div>
<div className="col-12 col-sm-md-8 col-lg-xl-6 col--with-padding js-col js-holder-9">
<ProductCard executeOnResize={this.runPackery} />
</div>
<div className="col-12 col-sm-md-8 col-lg-xl-6 col--with-padding js-col js-holder-10">
<ProductCard executeOnResize={this.runPackery} />
</div>
<div className="col-12 col-sm-md-8 col-lg-xl-6 col--with-padding js-col js-holder-11">
<ProductCard executeOnResize={this.runPackery} />
</div>
<div className="col-12 col-sm-md-8 col-lg-xl-6 col--with-padding js-col js-holder-12">
<ProductCard executeOnResize={this.runPackery} />
</div>
</div>
</main>
);
}
}
ProductCard:
import React, { Component } from 'react';
import LikeButton from '../LikeButton';
// import addToCartIcon from '../../assets/images/shared/add-to-cart-icon.svg';
const COMPONENT_NAME = 'ProductCard';
/** Class representing a product card. */
export default class ProductCard extends Component {
/**
* Construct the `ProductCard`.
* `executeOnResize` may be passed as prop for ProductCard's displayed
* in a packery grid. Execute this function each time the card resizes.
* @function contructor
*/
constructor(props) {
super(props);
this.state = {
isImageLoading: true,
};
this.handleImageLoad = this.handleImageLoad.bind(this);
/** TODO: Below is temporary! */
this.imageSrc = `https://picsum.photos/500/${400 + Math.random() * 1000}/?random`;
}
/**
* Check whether component has resized and `executeOnResize` has to be fired.
* @function componentDidUpdate
*/
componentDidUpdate(prevProps, prevState) {
const { isImageLoading: wasImageLoading } = prevState;
const { isImageLoading } = this.state;
const { executeOnResize } = this.props;
if (wasImageLoading !== isImageLoading && typeof executeOnResize === 'function') {
executeOnResize();
}
}
/**
* Update state accordingly when image is loaded.
* @function handleImageLoad
*/
handleImageLoad() {
this.setState({
isImageLoading: false,
});
}
render() {
const { isImageLoading } = this.state;
return (
<article className={`${COMPONENT_NAME}${isImageLoading ? ` ${COMPONENT_NAME}--image-loading` : ''}`}>
<div className={`${COMPONENT_NAME}__inner`}>
<div className={`${COMPONENT_NAME}__LikeButton`}>
<LikeButton />
</div>
<header className={`${COMPONENT_NAME}__header`}>
<section className={`${COMPONENT_NAME}__content`}>
<p className={`${COMPONENT_NAME}__name`}>ELISHA EXTRA SLIM FIT - Zakelijk overhemd</p>
<p className={`${COMPONENT_NAME}__brand`}>Hugo BOSS</p>
</section>
<section className={`${COMPONENT_NAME}__financial`}>
<p className={`${COMPONENT_NAME}__price`}>€79,95</p>
</section>
<section className={`${COMPONENT_NAME}__actions`}>
<button
className={`${COMPONENT_NAME}__add-to-cart`}
type="button"
>
Add to basket
<img
className={`${COMPONENT_NAME}__add-to-cart-icon`}
alt="Add to basket"
style={{ display: 'none' }}
// src={addToCartIcon}
/>
</button>
</section>
</header>
<figure className={`${COMPONENT_NAME}__image-wrapper js-drag-handle`}>
<img
src={this.imageSrc}
alt="Name of product"
onLoad={this.handleImageLoad}
/>
</figure>
</div>
</article>
);
}
}
Hi David, I love your work. Trying to use Packery in React via https://github.com/eiriklv/react-packery-component . Got it very close but am getting a TypeError. And I am using a different pattern than he has in github. I am holding the array object in state and rendering it by calling renderData().