Skip to content
This repository has been archived by the owner on Mar 5, 2024. It is now read-only.

Commit

Permalink
Refactor, change loadImage method to prop
Browse files Browse the repository at this point in the history
  • Loading branch information
mikefey committed Jun 3, 2018
1 parent e62bf1a commit 24840ef
Show file tree
Hide file tree
Showing 7 changed files with 173 additions and 96 deletions.
6 changes: 2 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,9 @@ import { ResponsiveImage, ResponsiveImageSize } from 'react-responsive-image';
**background {Boolean}** - If set to true, the component will render a background image
**className {String}** - An additional className to add to the component
**lazy {Boolean}** - If the component should lazy-load the image
**loadImage {Function}** - Set to `true` to load an image, if the `lazy` prop is set to `true`
**onLoad {Function}** - A callback to fire when the image is loaded
**style {Object}** - A style object to add to the component

## methods for ResponsiveImage component
**loadImage()** - Loads the image, used if the `lazy` prop is set to `true`
**style {Object}** - A style object to add to the component

## props for ResponsiveImageSize component
**default {Boolean}** - If this is the default size to be loaded, before the window width is available. Mainly used for rendering from the server.
Expand Down
76 changes: 50 additions & 26 deletions __test__/responsive-image-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -302,22 +302,23 @@ test('ResponsiveImage component: Should load the placeholder image if the ' +
});


test('ResponsiveImage component: Should load the the proper image if the ' +
'lazy prop is true and loadImage() is called', (assert) => {
test('ResponsiveImage component: Should load the the proper image when ' +
'the loadImage prop is set to true', (assert) => {
window.innerWidth = 1101;

let loadCount = 0;
const resizeEvent =
eventHelper.createEvent('Events', 'resize', 0, 0, 0, 0);
eventHelper.dispatchEvent(window, resizeEvent);
let component = null;

function lazyLoadCallback() {
loadCount++;

// there will be 2 callbacks fired, one for the initial image and another
// because a new image is loaded when the window is resized
if (loadCount === 1) {
const node = ReactDOM.findDOMNode(component).firstChild.firstChild;
const node = ReactDOM.findDOMNode(component).firstChild.firstChild.firstChild;
const nodeSrc = node.getAttribute('src');

assert.equal(nodeSrc, imageData.originalImageUrl);
Expand All @@ -326,28 +327,51 @@ test('ResponsiveImage component: Should load the the proper image if the ' +
}
}

const component = ReactTestUtils.renderIntoDocument(
<ResponsiveImage
lazy
onLoad={lazyLoadCallback}
>
<ResponsiveImageSize
default
minWidth={0}
path={imageData.initialUrl}
/>
<ResponsiveImageSize
minWidth={768}
path={imageData.mediumImageUrl}
/>
<ResponsiveImageSize
minWidth={1100}
path={imageData.originalImageUrl}
/>
</ResponsiveImage>
);
class DemoApp extends React.Component {
constructor(props) {
super(props);

this.state = {
loadImage: false,
};
}

componentDidMount() {
setTimeout(() => {
this.setState({ loadImage: true });
}, 1000);
}

render() {
return (
<div className='component-demo-app'>
<ResponsiveImage
lazy
loadImage={this.state.loadImage}
onLoad={lazyLoadCallback}
>
<ResponsiveImageSize
default
minWidth={0}
path={imageData.initialUrl}
/>
<ResponsiveImageSize
minWidth={768}
path={imageData.mediumImageUrl}
/>
<ResponsiveImageSize
minWidth={1100}
path={imageData.originalImageUrl}
/>
</ResponsiveImage>
</div>
);
}
}

component.loadImage();
component = ReactTestUtils.renderIntoDocument(
<DemoApp />
);
});


Expand Down Expand Up @@ -424,8 +448,8 @@ test('ResponsiveImage component: Should render a fallback image', (assert) => {
<ResponsiveImage>
<ResponsiveImageSize
default
minWidth={0}
path={imageData.initialUrl}
minWidth={0}
path={imageData.initialUrl}
/>
<ResponsiveImageSize
minWidth={1}
Expand Down
82 changes: 60 additions & 22 deletions assets/js/src/components/ResponsiveImage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class ResponsiveImage extends React.Component {
// initial state object
this.state = {
currentImageSize: this.getInitialSize(),
loadInitiated: false,
windowSize: {
width: 0,
height: 0,
Expand All @@ -38,6 +39,21 @@ class ResponsiveImage extends React.Component {
}


/**
* Called after component updates, checks to see if the loadImage prop
* was set to true and loads image accordingly
* @param {Object} prevProps - The component's props before the update
* @returns {undefined} undefined
*/
componentDidUpdate(prevProps) {
const { loadImage } = this.props;

if (!prevProps.loadImage && loadImage) {
this.loadImage();
}
}


/**
* Called before component is removed from the DOM
* @returns {undefined} undefined
Expand All @@ -52,12 +68,13 @@ class ResponsiveImage extends React.Component {
* @returns {ReactElement} React element
*/
render() {
const { className } = this.props;
const currentSizeClone = this.getCurrentSizeClone();
const additionalClass = this.props.className ?
' ' + this.props.className : '';
const className = 'component-responsive-image' + additionalClass;
const additionalClass = className ?
` ${className}` : '';
const newClassName = `component-responsive-image${additionalClass}`;

return (<div className={className}>
return (<div className={newClassName}>
{currentSizeClone}
</div>);
}
Expand All @@ -68,16 +85,17 @@ class ResponsiveImage extends React.Component {
* @returns {undefined} undefined
*/
getInitialSize() {
const { children } = this.props;
let initialSize;

for (let i = 0; i < this.props.children.length; i++) {
if (this.props.children[i].props.default) {
initialSize = this.props.children[i];
for (let i = 0; i < children.length; i++) {
if (children[i].props.default) {
initialSize = children[i];
}
}

if (!initialSize) {
initialSize = this.props.children[0];
initialSize = children[0];
}

return initialSize;
Expand All @@ -89,16 +107,34 @@ class ResponsiveImage extends React.Component {
* @returns {undefined} undefined
*/
getCurrentSizeClone() {
return React.cloneElement(this.state.currentImageSize, {
alt: this.props.alt,
background: this.props.background,
key: 'image-size-' + this.state.currentImageSize.props.minWidth,
lazy: this.props.lazy,
onLoad: this.props.onLoad,
preloadBackground: this.props.preloadBackground,
const {
alt,
background,
lazy,
loadImage,
onLoad,
preloadBackground,
imageStyle,
} = this.props;

const {
currentImageSize,
loadInitiated,
windowSize,
} = this.state;

return React.cloneElement(currentImageSize, {
alt,
background,
key: 'image-size-' + currentImageSize.props.minWidth,
lazy,
loadInitiated,
loadImage,
onLoad,
preloadBackground,
ref: 'currentImageSize',
imageStyle: this.props.imageStyle,
windowSize: this.state.windowSize,
imageStyle,
windowSize,
});
}

Expand All @@ -109,17 +145,17 @@ class ResponsiveImage extends React.Component {
*/
onResize() {
let currentImageSize;

const { children } = this.props;
const windowSize = {
width: window.innerWidth,
height: window.innerHeight,
};

for (let i = 0; i < this.props.children.length; i++) {
const childProps = this.props.children[i].props;
for (let i = 0; i < children.length; i++) {
const childProps = children[i].props;

if (windowSize.width >= childProps.minWidth) {
currentImageSize = this.props.children[i];
currentImageSize = children[i];
}
}

Expand All @@ -129,12 +165,12 @@ class ResponsiveImage extends React.Component {
});
}


/**
* Loads the image, intended as a public method to lazy load the image
* @returns {undefined} undefined
*/
loadImage() {
this.setState({ loadInitiated: true });
this.refs.currentImageSize.preloadImage();
}
}
Expand All @@ -149,6 +185,7 @@ class ResponsiveImage extends React.Component {
* @prop {String} className - An additional className to add to the component
* @prop {Object} imageStyle - A style object to add to the component
* @prop {Boolean} lazy - If the component should lazy-load the image
* @prop {Function} loadImage - Set to true to load an image, when the lazy prop is set to true
* @prop {Function} onLoad - A callback to fire when the image is loaded
* @prop {Boolean} preloadBackground - If the image is a background image,
* setting this to true will preload it before displaying
Expand All @@ -163,6 +200,7 @@ ResponsiveImage.propTypes = {
className: PropTypes.string,
imageStyle: PropTypes.object,
lazy: PropTypes.bool,
loadImage: PropTypes.bool,
onLoad: PropTypes.func,
preloadBackground: PropTypes.bool,
};
Expand Down
Loading

0 comments on commit 24840ef

Please sign in to comment.