├── index.js ├── .gitignore ├── gulpfile.js ├── README.md ├── LICENSE ├── package.json ├── lib └── BackgroundImage.js └── dist └── BackgroundImage.js /index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./dist/BackgroundImage.js'); 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # exclude osx meta-files 2 | .DS_Store 3 | .npmignore 4 | .npmrc 5 | # exclude all node_modules 6 | node_modules/ 7 | 8 | # ignore npm error logs 9 | npm-debug.log -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'); 2 | var path = require('path'); 3 | var babel = require('gulp-babel'); 4 | 5 | function build() { 6 | return gulp 7 | .src(['lib/**/*.js']) 8 | .pipe(babel({ 9 | optional: ['runtime', 'es7.decorators'] 10 | })) 11 | .pipe(gulp.dest(__dirname + '/dist')); 12 | } 13 | 14 | function watch() { 15 | gulp.watch(['lib/**/*.js'], ['build']); 16 | build(); 17 | } 18 | 19 | gulp.task('build', build); 20 | gulp.task('watch', watch); -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-background-image-loader 2 | Allows you display a placeholder image while the actual background image loads 3 | 4 | ## Installation 5 | `npm install react-background-image-loader --save` 6 | 7 | In order to build / modify the component locally just run `npm watch`. 8 | 9 | ## Usage 10 | ```javascript 11 | import React from 'react'; 12 | import BackgroundImage from 'react-background-image-loader'; 13 | 14 | export default (props) => { 15 | const {source, ...otherProps} = props; 16 | const localImage = '/path/to/local/asset'; 17 | 18 | return( 19 | 20 |
21 | Some more markup 22 |
23 | 24 |
25 | ); 26 | } 27 | ``` 28 | 29 | ## Props 30 | prop | type | notes 31 | ------------|--------|----------------------------------------- 32 | src | string | Remote image to be loaded 33 | placeholder | string | Local image to be immediately displayed 34 | 35 | ## License 36 | 37 | MIT License 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Jed Watson 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-background-image-loader", 3 | "version": "0.0.5", 4 | "description": "This package allows you to display a placeholder image while the actual background image loads", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "build": "gulp build", 9 | "watch": "gulp watch" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/danieltimpone/react-background-image-loader.git" 14 | }, 15 | "keywords": [ 16 | "react", 17 | "image", 18 | "loader", 19 | "background" 20 | ], 21 | "author": "Daniel Timpone", 22 | "license": "ISC", 23 | "bugs": { 24 | "url": "https://github.com/danieltimpone/react-background-image-loader/issues" 25 | }, 26 | "homepage": "https://github.com/danieltimpone/react-background-image-loader#readme", 27 | "dependencies": { 28 | "prop-types": "^15.5.10", 29 | "react": "^15.5.4" 30 | }, 31 | "devDependencies": { 32 | "babel-core": "^5.8.22", 33 | "babel-loader": "^5.3.2", 34 | "babel-runtime": "^5.8.25", 35 | "gulp": "^3.8.11", 36 | "gulp-babel": "^5.3.0" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /lib/BackgroundImage.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | /* 4 | This component displays a placeholder image that is hosted locally 5 | while it waits for a remote image to load. 6 | 7 | Usage: 8 | {...child components} 9 | 10 | */ 11 | export default class BackgroundLoader extends React.Component { 12 | static get propTypes () { 13 | return { 14 | src: PropTypes.string.isRequired, 15 | placeholder: PropTypes.string.isRequired, 16 | className: PropTypes.string, 17 | style: PropTypes.object, 18 | children: PropTypes.node, 19 | }; 20 | } 21 | 22 | constructor(props) { 23 | super(props); 24 | 25 | this.state = { 26 | loaded: false, 27 | error: false, 28 | }; 29 | 30 | this.handleLoad = this.handleLoad.bind(this); 31 | this.handleError = this.handleError.bind(this); 32 | } 33 | 34 | componentDidMount() { 35 | // Making this a global so it can be later 36 | // nullified when the component unmounts 37 | this.image = new Image(); 38 | 39 | this.image.src = this.props.src; 40 | this.image.onload = this.handleLoad; 41 | this.image.onerror = this.handleError; 42 | } 43 | 44 | shouldComponentUpdate(nextState, nextProps) { 45 | return !this.state.loaded; 46 | } 47 | 48 | componentWillUnmount() { 49 | this.image.onerror = null; 50 | this.image.onload = null; 51 | this.image = null; 52 | } 53 | 54 | handleLoad(e) { 55 | this.setState({ 56 | loaded: true, 57 | }); 58 | } 59 | 60 | handleError(e) { 61 | console.error('Failed to load ', this.props.src); 62 | 63 | this.setState({ 64 | error: true, 65 | }); 66 | } 67 | 68 | render() { 69 | const {src, placeholder, children, ...props} = this.props; 70 | const source = !this.state.loaded || this.state.error ? placeholder : src; 71 | 72 | return ( 73 |
74 | {children} 75 |
76 | ); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /dist/BackgroundImage.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _get = require('babel-runtime/helpers/get')['default']; 4 | 5 | var _inherits = require('babel-runtime/helpers/inherits')['default']; 6 | 7 | var _createClass = require('babel-runtime/helpers/create-class')['default']; 8 | 9 | var _classCallCheck = require('babel-runtime/helpers/class-call-check')['default']; 10 | 11 | var _objectWithoutProperties = require('babel-runtime/helpers/object-without-properties')['default']; 12 | 13 | var _extends = require('babel-runtime/helpers/extends')['default']; 14 | 15 | var _interopRequireDefault = require('babel-runtime/helpers/interop-require-default')['default']; 16 | 17 | Object.defineProperty(exports, '__esModule', { 18 | value: true 19 | }); 20 | 21 | var _react = require('react'); 22 | 23 | var _react2 = _interopRequireDefault(_react); 24 | 25 | var _propTypes = require('prop-types'); 26 | 27 | var _propTypes2 = _interopRequireDefault(_propTypes); 28 | 29 | /* 30 | This component displays a placeholder image that is hosted locally 31 | while it waits for a remote image to load. 32 | 33 | Usage: 34 | {...child components} 35 | 36 | */ 37 | 38 | var BackgroundLoader = (function (_React$Component) { 39 | _inherits(BackgroundLoader, _React$Component); 40 | 41 | _createClass(BackgroundLoader, null, [{ 42 | key: 'propTypes', 43 | get: function get() { 44 | return { 45 | src: _propTypes2['default'].string.isRequired, 46 | placeholder: _propTypes2['default'].string.isRequired, 47 | className: _propTypes2['default'].string, 48 | style: _propTypes2['default'].object, 49 | children: _propTypes2['default'].node 50 | }; 51 | } 52 | }]); 53 | 54 | function BackgroundLoader(props) { 55 | _classCallCheck(this, BackgroundLoader); 56 | 57 | _get(Object.getPrototypeOf(BackgroundLoader.prototype), 'constructor', this).call(this, props); 58 | 59 | this.state = { 60 | loaded: false, 61 | error: false 62 | }; 63 | 64 | this.handleLoad = this.handleLoad.bind(this); 65 | this.handleError = this.handleError.bind(this); 66 | } 67 | 68 | _createClass(BackgroundLoader, [{ 69 | key: 'componentDidMount', 70 | value: function componentDidMount() { 71 | // Making this a global so it can be later 72 | // nullified when the component unmounts 73 | this.image = new Image(); 74 | 75 | this.image.src = this.props.src; 76 | this.image.onload = this.handleLoad; 77 | this.image.onerror = this.handleError; 78 | } 79 | }, { 80 | key: 'shouldComponentUpdate', 81 | value: function shouldComponentUpdate(nextState, nextProps) { 82 | return !this.state.loaded; 83 | } 84 | }, { 85 | key: 'componentWillUnmount', 86 | value: function componentWillUnmount() { 87 | this.image.onerror = null; 88 | this.image.onload = null; 89 | this.image = null; 90 | } 91 | }, { 92 | key: 'handleLoad', 93 | value: function handleLoad(e) { 94 | this.setState({ 95 | loaded: true 96 | }); 97 | } 98 | }, { 99 | key: 'handleError', 100 | value: function handleError(e) { 101 | console.error('Failed to load ', this.props.src); 102 | 103 | this.setState({ 104 | error: true 105 | }); 106 | } 107 | }, { 108 | key: 'render', 109 | value: function render() { 110 | var _props = this.props; 111 | var src = _props.src; 112 | var placeholder = _props.placeholder; 113 | var children = _props.children; 114 | 115 | var props = _objectWithoutProperties(_props, ['src', 'placeholder', 'children']); 116 | 117 | var source = !this.state.loaded || this.state.error ? placeholder : src; 118 | 119 | return _react2['default'].createElement( 120 | 'div', 121 | _extends({ style: { backgroundImage: 'url(' + source + ')' } }, props), 122 | children 123 | ); 124 | } 125 | }]); 126 | 127 | return BackgroundLoader; 128 | })(_react2['default'].Component); 129 | 130 | exports['default'] = BackgroundLoader; 131 | module.exports = exports['default']; --------------------------------------------------------------------------------