├── .circleci
└── config.yml
├── .gitignore
├── LICENSE
├── README.md
├── babel.config.js
├── misc
├── requestAnimationFrame.js
├── testSetup.js
└── zenika.png
├── package.json
├── packages
├── core
│ ├── README.md
│ ├── build
│ │ ├── core.js
│ │ └── index.js
│ ├── package.json
│ └── src
│ │ ├── __snapshots__
│ │ └── index.spec.js.snap
│ │ ├── core.jsx
│ │ ├── index.js
│ │ └── index.spec.js
├── examples
│ ├── .env
│ ├── LICENSE
│ ├── package.json
│ ├── public
│ │ ├── favicon.png
│ │ └── index.html
│ ├── publish.js
│ └── src
│ │ ├── components
│ │ ├── App.jsx
│ │ ├── App.scss
│ │ ├── Code
│ │ │ ├── Code.jsx
│ │ │ ├── Code.scss
│ │ │ └── index.js
│ │ ├── Example
│ │ │ ├── Button
│ │ │ │ ├── Button.jsx
│ │ │ │ ├── Button.scss
│ │ │ │ └── index.js
│ │ │ ├── Example.jsx
│ │ │ ├── Example.scss
│ │ │ └── index.js
│ │ ├── Examples
│ │ │ ├── Base.jsx
│ │ │ ├── DontWait.jsx
│ │ │ ├── ErrorIndicator.jsx
│ │ │ ├── Examples.jsx
│ │ │ ├── Examples.scss
│ │ │ ├── LoadingIndicator.jsx
│ │ │ ├── OneParam.jsx
│ │ │ ├── TwoParams.jsx
│ │ │ └── index.js
│ │ └── index.js
│ │ └── index.js
└── full
│ ├── README.md
│ ├── build
│ ├── ErrorCross
│ │ ├── ErrorCross.js
│ │ └── index.js
│ ├── TailSpin
│ │ ├── TailSpin.js
│ │ └── index.js
│ ├── index.js
│ └── utils
│ │ ├── colorUtil.js
│ │ └── index.js
│ ├── package.json
│ └── src
│ ├── ErrorCross
│ ├── ErrorCross.jsx
│ ├── ErrorCross.spec.js
│ └── index.js
│ ├── TailSpin
│ ├── TailSpin.jsx
│ ├── TailSpin.spec.js
│ └── index.js
│ ├── index.js
│ ├── index.spec.js
│ └── utils
│ ├── colorUtil.js
│ └── index.js
└── yarn.lock
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | jobs:
3 | debug:
4 | docker:
5 | - image: circleci/node:latest
6 | steps:
7 | - run: node --version
8 | - run: yarn --version
9 |
10 | build:
11 | docker:
12 | - image: circleci/node:latest
13 | steps:
14 | - checkout
15 | - restore_cache:
16 | keys:
17 | - dependencies-{{ checksum "package.json" }}
18 | - dependencies-
19 | - run: yarn
20 | - save_cache:
21 | paths:
22 | - node_modules
23 | key: dependencies-{{ checksum "package.json" }}
24 | - run: yarn ci
25 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 |
6 | # Runtime data
7 | pids
8 | *.pid
9 | *.seed
10 |
11 | # Directory for instrumented libs generated by jscoverage/JSCover
12 | lib-cov
13 |
14 | # Coverage directory used by tools like istanbul
15 | coverage
16 |
17 | # nyc test coverage
18 | .nyc_output
19 |
20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
21 | .grunt
22 |
23 | # node-waf configuration
24 | .lock-wscript
25 |
26 | # Compiled binary addons (http://nodejs.org/api/addons.html)
27 | build/Release
28 |
29 | # Dependency directories
30 | node_modules
31 | jspm_packages
32 |
33 | # Optional npm cache directory
34 | .npm
35 |
36 | # Optional REPL history
37 | .node_repl_history
38 | .DS_Store
39 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016 uni rakun
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.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # hoc-react-loader
2 | [](https://circleci.com/gh/unirakun/hoc-react-loader/tree/master) [](https://www.npmjs.com/package/hoc-react-loader) [](https://coveralls.io/github/unirakun/hoc-react-loader?branch=master)
3 |
4 | This is a [higher order component](https://facebook.github.io/react/docs/higher-order-components.html) ("HOC"). It's an advanced pattern used in React that let you reuse code logic, it can be summarized as a component factory. It improves isolation, interoperability and maintainability of your code base.
5 |
6 | **hoc-react-loader**'s purpose is to call a `load` callback passed through the `props` of a component only once (at `componentWillMount`). This is convenient to load data from a backend for instance. The component shows a loading indicator when it's waiting for the props to be defined. The loading indicator can be changed easily.
7 |
8 | - To see full documentation: [click here](./packages/core/README.md)
9 | - Do you want a default LoadingIndicator and a default ErrorIndicator?, you can use [@hoc-react-loader/full](./packages/full/README.md)
10 | - You want your bundle not being bloated?, you can use [@hoc-react-loader/core](./packages/core/README.md)
11 |
12 | ## Example
13 | ```jsx
14 | import React from 'react'
15 | import loader from '@hoc-react-loader/core'
16 |
17 | const Component = ({ data }) =>
Component {JSON.stringify(data)}
18 | const load = props => console.log(props)
19 |
20 | export default loader({ print: ['data'], load })(Component)
21 | ```
22 |
23 | In this example `load` will be called at first mount, then the wrapped `Component` will be printed only if `props.data` is truthy.
24 |
25 | `load` function can be the moment you ask for your API data.
26 |
27 | ## Demos
28 | You can test some examples [here](https://unirakun.github.io/hoc-react-loader/).
29 |
30 | # About uni rakun
31 | **uni rakun** is created by two passionate french developers.
32 |
33 | Do you want to contact them ? Go to their [website](https://unirakun.fr)
34 |
35 |
44 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | /*
2 | * needed to be this file (babel.config.js) for jest
3 | * because jest doesn't look for .babelrc or package.json.babel ... :(
4 | */
5 | module.exports = {
6 | presets: [
7 | '@babel/preset-env',
8 | '@babel/preset-react',
9 | ],
10 | plugins: [
11 | '@babel/plugin-proposal-class-properties',
12 | ],
13 | }
14 |
--------------------------------------------------------------------------------
/misc/requestAnimationFrame.js:
--------------------------------------------------------------------------------
1 | global.requestAnimationFrame = (cb) => {
2 | setTimeout(cb, 0)
3 | }
4 |
--------------------------------------------------------------------------------
/misc/testSetup.js:
--------------------------------------------------------------------------------
1 | import './requestAnimationFrame'
2 | import Enzyme from 'enzyme'
3 | import Adapter from 'enzyme-adapter-react-16'
4 |
5 | Enzyme.configure({ adapter: new Adapter() })
6 |
--------------------------------------------------------------------------------
/misc/zenika.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unirakun/hoc-react-loader/6392271292e27f857b20e2d0820a4af050027166/misc/zenika.png
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hoc-react-loader",
3 | "version": "7.0.0",
4 | "description": "Higher order component to call a load function from props at mount.",
5 | "license": "MIT",
6 | "private": true,
7 | "author": "Fabien JUIF ",
8 | "contributors": [
9 | "Yvonnick FRIN ",
10 | "Yoann Prot ",
11 | "Benjamin CAVY "
12 | ],
13 | "workspaces": [
14 | "packages/*"
15 | ],
16 | "scripts": {
17 | "build:core": "yarn --cwd packages/core build",
18 | "build:full": "yarn --cwd packages/full build",
19 | "build": "run-p build:*",
20 | "lint": "eslint . --ext js,jsx --ignore-pattern dist/ --ignore-pattern coverage/ --ignore-pattern node_modules/ --ignore-pattern misc/ --ignore-pattern public/ --ignore-pattern build/",
21 | "test": "jest",
22 | "coveralls": "jest --coverage && cat ./coverage/lcov.info | coveralls",
23 | "ci": "run-p lint coveralls"
24 | },
25 | "devDependencies": {
26 | "@babel/core": "^7.1.2",
27 | "@babel/plugin-proposal-class-properties": "^7.1.0",
28 | "@babel/preset-env": "^7.1.0",
29 | "@babel/preset-react": "^7.0.0",
30 | "babel-core": "^7.0.0-bridge.0",
31 | "babel-eslint": "^10.0.1",
32 | "babel-jest": "^23.6.0",
33 | "coveralls": "^3.0.2",
34 | "enzyme": "^3.7.0",
35 | "enzyme-adapter-react-16": "^1.6.0",
36 | "eslint": "^5.7.0",
37 | "eslint-config-airbnb": "^17.1.0",
38 | "eslint-plugin-babel": "^5.2.1",
39 | "eslint-plugin-import": "^2.14.0",
40 | "eslint-plugin-jsx-a11y": "^6.1.1",
41 | "eslint-plugin-react": "^7.11.0",
42 | "jest": "^23.6.0",
43 | "npm-run-all": "^4.1.3",
44 | "prop-types": "^15.6.2",
45 | "react": "^16.5.2",
46 | "react-dom": "^16.5.2",
47 | "tinycolor2": "^1.4.1"
48 | },
49 | "eslintConfig": {
50 | "parser": "babel-eslint",
51 | "extends": [
52 | "airbnb"
53 | ],
54 | "plugins": [
55 | "babel"
56 | ],
57 | "rules": {
58 | "max-len": [
59 | 2,
60 | 200
61 | ],
62 | "semi": [
63 | 2,
64 | "never"
65 | ],
66 | "react/forbid-prop-types": "off",
67 | "react/no-unescaped-entities": "off"
68 | }
69 | },
70 | "jest": {
71 | "coveragePathIgnorePatterns": [
72 | "/node_modules/",
73 | "/dist/",
74 | "/misc/",
75 | "/build/"
76 | ],
77 | "setupFiles": [
78 | "./misc/testSetup.js"
79 | ]
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/packages/core/README.md:
--------------------------------------------------------------------------------
1 | # @hoc-react-loader/core
2 | [](https://circleci.com/gh/unirakun/hoc-react-loader/tree/master) [](https://www.npmjs.com/package/hoc-react-loader) [](https://coveralls.io/github/unirakun/hoc-react-loader?branch=master)
3 |
4 | This is a [higher order component](https://facebook.github.io/react/docs/higher-order-components.html) ("HOC"). It's an advanced pattern used in React that let you reuse code logic, it can be summarized as a component factory. It improves isolation, interoperability and maintainability of your code base.
5 |
6 | **@hoc-react-loader/core**'s purpose is to call a `load` callback passed through the `props` of a component only once (at `componentWillMount`). This is convenient to load data from a backend for instance. The component shows a loading indicator when it's waiting for the props to be defined. The loading indicator can be changed easily.
7 |
8 | ## Demos
9 | You can test some examples [here](https://unirakun.github.io/hoc-react-loader/).
10 |
11 | ## Installation
12 | `yarn add @hoc-react-loader/core`
13 |
14 | ## Usage
15 | ### With `this.props`
16 | ```es6
17 | import loader from '@hoc-react-loader/core'
18 |
19 | const Component = ({ data }) =>
Component {JSON.stringify(data)}
20 |
21 | export default loader({ print: ['data'] })(Component)
22 | ```
23 | In this case, the loader waits for `this.props.data` to be truthy, then mounts its child component and calls `this.props.load` if it exists. This is useful when the parent has control over the injected data, or when the `Component` is connected with `redux`. `this.props.load` should be injected by the parent component or injected by a `Container` (redux).
24 |
25 | The `print` parameter should be an array of props to waits. All these props should become truthy at some point.
26 |
27 | Since the `LoadingIndicator` is not specified, `null` (nothing) is displayed while waiting for all the props. Here's an exemple with a specified loader:
28 | ```es6
29 | import loader from '@hoc-react-loader/core'
30 |
31 | const MyLoadingIndicator = () =>
Waiting...
32 | const Component = ({ data }) =>
Component {data}
33 |
34 | export default loader({ print: ['data'], LoadingIndicator: MyLoadingIndicator })(Component)
35 | ```
36 |
37 | The `print` parameter can also be a Promise. The loading indicator is displayed until `print` Promise is resolved or rejected.
38 |
39 | ### Don't wait
40 | ```es6
41 | import loader from '@hoc-react-loader/core'
42 |
43 | const LoadingIndicator = () =>
Waiting...
44 | const Component = ({ data }) =>
Component {JSON.stringify(data)}
45 |
46 | export default loader({ LoadingIndicator })(Component)
47 | ```
48 | In this example, the loader component doesn't wait for props. `this.props.load` is called once, but the `LoadingIndicator` component isn't displayed.
49 |
50 | ### Load as a function parameter
51 | ```es6
52 | import loader from '@hoc-react-loader/core'
53 |
54 | const LoadingIndicator = () =>
Waiting...
55 | const Component = ({ data }) =>
Component {JSON.stringify(data)}
56 |
57 | export default loader({ LoadingIndicator, load: () => console.log('here') })(Component)
58 | ```
59 | In this case, the loader calls `this.props.load` if it exists *AND* the `load` parameter, resulting in `here` to be printed.
60 |
61 | The default `print` parameter value is `true`. It means that in this example the `LoadingIndicator` isn't displayed.
62 |
63 | ### Load as a string parameter
64 | ```es6
65 | import loader from '@hoc-react-loader/core'
66 |
67 | const LoadingIndicator = () =>
Waiting...
68 | const Component = ({ data }) =>
Component {JSON.stringify(data)}
69 |
70 | export default loader({ LoadingIndicator, load: 'myLoader' })(Component)
71 | ```
72 | In this case, the loader calls `this.props.myLoader` if it exists.
73 |
74 | The default `print` parameter value is `true`. It means that in this example the `LoadingIndicator` isn't displayed.
75 |
76 | ### Print as a function
77 | The `print` parameter can also be a function. Then the `props` and `context` are given to it (in this order), and it should return a boolean indicating wether or not the actual component should be displayed.
78 |
79 | ### Error handling
80 | The `error` parameter allows to specify a prop that indicates wether or not a placeholder error component should be displayed in replacement of the real component.
81 | It's usefull when data that are required for the correct display of a component are missing.
82 |
83 | Like for the `print` prop, `error` can be a `boolean`, a `string` (referencing a prop name), an array of `string` (an array of prop names) or a `function` (whose result will be converted to `boolean`).
84 |
85 | ```js
86 | // default error component will be displayed if 'error' prop is truthy
87 | export default loader()(MyComponent)
88 |
89 | // default error component will be displayed (null, meaning nothing)
90 | export default loader({ error: true })(MyComponent)
91 |
92 | // default error component will be displayed if 'errorMessage' prop is truthy
93 | export default loader({ error: 'errorMessage' })(MyComponent)
94 |
95 | // CustomErrorComponent will be displayed if 'error' prop is truthy
96 | export default loader({ ErrorIndicator: CustomErrorComponent })(MyComponent)
97 | ```
98 |
99 | ### Delay parameter
100 |
101 | When a component loads very quickly, you will see a flash of the loading component.
102 | To avoid this behaviour, you can add a `delay` parameter to the loader with a time in milliseconds.
103 | Then, the loading indicator will be rendered after the delay if the Component can't be rendered before that.
104 |
105 | ```js
106 | // loading indicator will be displayed only after 200ms
107 | export default loader({ print: ['data'], delay: 200 })(MyComponent)
108 | ```
109 |
110 | By default, no delay is defined.
111 |
--------------------------------------------------------------------------------
/packages/core/build/core.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 | exports.default = void 0;
7 |
8 | var _react = _interopRequireWildcard(require("react"));
9 |
10 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } }
11 |
12 | function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
13 |
14 | function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }
15 |
16 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
17 |
18 | function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
19 |
20 | function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
21 |
22 | function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
23 |
24 | function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
25 |
26 | function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
27 |
28 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
29 |
30 | function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
31 |
32 | function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
33 |
34 | // eslint-disable-line import/no-extraneous-dependencies
35 | var getTypeOf = function getTypeOf(something) {
36 | var getType = {};
37 | return something && getType.toString.call(something);
38 | }; // http://stackoverflow.com/a/7356528
39 |
40 |
41 | var isFunction = function isFunction(functionToCheck) {
42 | var type = getTypeOf(functionToCheck);
43 | return type && type === '[object Function]';
44 | };
45 |
46 | var isString = function isString(stringToCheck) {
47 | var type = getTypeOf(stringToCheck);
48 | return type && type === '[object String]';
49 | };
50 |
51 | var hasStatus = function hasStatus(prop, propProcessor, defaultProp, defaultValue) {
52 | return function (props, state, context) {
53 | if (prop === undefined) {
54 | var status = props[defaultProp];
55 | return status === undefined ? defaultValue : !!status;
56 | }
57 |
58 | if (Array.isArray(prop)) {
59 | var boolProps = prop.map(function (p) {
60 | return !!props[p];
61 | });
62 | return propProcessor(boolProps);
63 | }
64 |
65 | if (isFunction(prop)) {
66 | return !!prop(props, context);
67 | }
68 |
69 | return !!prop;
70 | };
71 | };
72 |
73 | var getDisplayName = function getDisplayName(c) {
74 | return c.displayName || c.name || 'Component';
75 | };
76 |
77 | var _default = function _default() {
78 | var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
79 | LoadingIndicator = _ref.LoadingIndicator,
80 | ErrorIndicator = _ref.ErrorIndicator,
81 | print = _ref.print,
82 | load = _ref.load,
83 | error = _ref.error,
84 | delay = _ref.delay;
85 |
86 | var loadFunctionName = isString(load) ? load : 'load';
87 | var isLoadFunction = isFunction(load);
88 | var isLoaded = hasStatus(print, function (bs) {
89 | return !bs.includes(false);
90 | }, 'loaded', true);
91 | var isInError = hasStatus(error, function (bs) {
92 | return bs.includes(true);
93 | }, 'error', false);
94 | return function (ComposedComponent) {
95 | var _class, _temp;
96 |
97 | var displayName = "Loader(".concat(getDisplayName(ComposedComponent), ")");
98 | return _temp = _class =
99 | /*#__PURE__*/
100 | function (_Component) {
101 | _inherits(_class, _Component);
102 |
103 | _createClass(_class, null, [{
104 | key: "getDerivedStateFromProps",
105 | value: function getDerivedStateFromProps(props, state) {
106 | var isLoadAFunction = isFunction(props[loadFunctionName]);
107 |
108 | if (isLoadAFunction) {
109 | return _objectSpread({}, state, {
110 | props: _objectSpread({}, props, _defineProperty({}, loadFunctionName, undefined))
111 | });
112 | }
113 |
114 | return _objectSpread({}, state, {
115 | props: props
116 | });
117 | }
118 | }]);
119 |
120 | function _class(props, context) {
121 | var _this;
122 |
123 | _classCallCheck(this, _class);
124 |
125 | _this = _possibleConstructorReturn(this, _getPrototypeOf(_class).call(this, props, context));
126 | _this.state = {
127 | props: {},
128 | print: true
129 | };
130 | return _this;
131 | }
132 |
133 | _createClass(_class, [{
134 | key: "componentDidMount",
135 | value: function componentDidMount() {
136 | var _this2 = this;
137 |
138 | // Load from hoc argument
139 | if (isLoadFunction) {
140 | load(this.props, this.context);
141 | } // Load from props
142 |
143 |
144 | var loadFunction = this.props[loadFunctionName]; // eslint-disable-line react/destructuring-assignment
145 |
146 | if (isFunction(loadFunction)) {
147 | loadFunction(this.props, this.context);
148 | } // set delay
149 |
150 |
151 | if (delay) {
152 | this.setState(function (state) {
153 | return _objectSpread({}, state, {
154 | print: false
155 | });
156 | });
157 | this.timer = setTimeout(function () {
158 | return _this2.setState(function (state) {
159 | return _objectSpread({}, state, {
160 | print: true
161 | });
162 | });
163 | }, delay);
164 | }
165 | }
166 | }, {
167 | key: "componentWillUnmount",
168 | value: function componentWillUnmount() {
169 | if (this.timer) {
170 | clearTimeout(this.timer);
171 | }
172 | }
173 | }, {
174 | key: "render",
175 | value: function render() {
176 | var props = this.state.props;
177 |
178 | if (isInError(this.props, this.state, this.context)) {
179 | // react renders nothing if you return null but is not happy if you return undefined
180 | return ErrorIndicator === undefined ? null : _react.default.createElement(ErrorIndicator, props);
181 | }
182 |
183 | if (isLoaded(this.props, this.state, this.context)) {
184 | return _react.default.createElement(ComposedComponent, props);
185 | }
186 |
187 | if (!this.state.print) {
188 | // eslint-disable-line react/destructuring-assignment
189 | return null;
190 | } // react renders nothing if you return null but is not happy if you return undefined
191 |
192 |
193 | return LoadingIndicator === undefined ? null : _react.default.createElement(LoadingIndicator, props);
194 | }
195 | }]);
196 |
197 | return _class;
198 | }(_react.Component), _defineProperty(_class, "displayName", displayName), _temp;
199 | };
200 | };
201 |
202 | exports.default = _default;
--------------------------------------------------------------------------------
/packages/core/build/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 | Object.defineProperty(exports, "default", {
7 | enumerable: true,
8 | get: function get() {
9 | return _core.default;
10 | }
11 | });
12 |
13 | var _core = _interopRequireDefault(require("./core"));
14 |
15 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
--------------------------------------------------------------------------------
/packages/core/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@hoc-react-loader/core",
3 | "version": "7.0.0",
4 | "description": "Higher order component to call a load function from props at mount",
5 | "main": "build/index.js",
6 | "repository": "https://github.com/alakarteio/hoc-react-loader",
7 | "author": "Fabien JUIF ",
8 | "contributors": [
9 | "Yvonnick FRIN ",
10 | "Yoann Prot ",
11 | "Benjamin CAVY "
12 | ],
13 | "keywords": [
14 | "react",
15 | "loader",
16 | "hoc",
17 | "placeholder"
18 | ],
19 | "license": "MIT",
20 | "private": false,
21 | "scripts": {
22 | "build": "babel --ignore \"**/*.spec.js\" ./src/ --out-dir build"
23 | },
24 | "devDependencies": {
25 | "@babel/cli": "^7.1.2",
26 | "@babel/core": "^7.1.2",
27 | "@babel/plugin-proposal-class-properties": "^7.1.0",
28 | "@babel/preset-env": "^7.1.0",
29 | "@babel/preset-react": "^7.0.0",
30 | "enzyme": "^3.7.0",
31 | "react": "^16.5.2"
32 | },
33 | "babel": {
34 | "presets": [
35 | "@babel/preset-env",
36 | "@babel/preset-react"
37 | ],
38 | "plugins": [
39 | "@babel/plugin-proposal-class-properties"
40 | ]
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/packages/core/src/__snapshots__/index.spec.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`@hoc-react-loader/core Indicators parameters should print the given ErrorIndicator 1`] = `"
Error
"`;
4 |
5 | exports[`@hoc-react-loader/core Indicators parameters should print the given LoadingIndicator 1`] = `"
Loader
"`;
6 |
7 | exports[`@hoc-react-loader/core delay parameter should render component when loaded when delay not past 1`] = `"
Component
"`;
8 |
9 | exports[`@hoc-react-loader/core delay parameter should render component when loaded when delay past 1`] = `"
Component
"`;
10 |
11 | exports[`@hoc-react-loader/core delay parameter should render loading indicator after delay and component not still loaded 1`] = `"
load
"`;
12 |
13 | exports[`@hoc-react-loader/core delay parameter should render nothing before delay and component not still loaded 1`] = `null`;
14 |
15 | exports[`@hoc-react-loader/core error parameter should print Component -error as a value- 1`] = `"
Component
"`;
16 |
17 | exports[`@hoc-react-loader/core error parameter should print Component -error as an array- 1`] = `"
Component
"`;
18 |
19 | exports[`@hoc-react-loader/core error parameter should print Component -error as an array- 2`] = `"
Component
"`;
20 |
21 | exports[`@hoc-react-loader/core error parameter should print Component -error as an array- 3`] = `"
Component
"`;
22 |
23 | exports[`@hoc-react-loader/core error parameter should print Component -error as function- 1`] = `"
Component
"`;
24 |
25 | exports[`@hoc-react-loader/core error parameter should print Component -error as function- 2`] = `
26 | Array [
27 | Array [
28 | Object {
29 | "some": "props",
30 | },
31 | Object {},
32 | ],
33 | ]
34 | `;
35 |
36 | exports[`@hoc-react-loader/core error parameter should print error Component -error as a value- 1`] = `null`;
37 |
38 | exports[`@hoc-react-loader/core error parameter should print error Component -error as an array- 1`] = `null`;
39 |
40 | exports[`@hoc-react-loader/core error parameter should print error Component -error as an array- 2`] = `null`;
41 |
42 | exports[`@hoc-react-loader/core error parameter should print error Component -error as an array- 3`] = `null`;
43 |
44 | exports[`@hoc-react-loader/core error parameter should print error Component -error as an array- 4`] = `null`;
45 |
46 | exports[`@hoc-react-loader/core error parameter should print error Component -error as function- 1`] = `null`;
47 |
48 | exports[`@hoc-react-loader/core error parameter should print error Component -error as function- 2`] = `
49 | Array [
50 | Array [
51 | Object {
52 | "some": "props",
53 | },
54 | Object {},
55 | ],
56 | ]
57 | `;
58 |
59 | exports[`@hoc-react-loader/core print parameter should not print Component -loaded props- 1`] = `null`;
60 |
61 | exports[`@hoc-react-loader/core print parameter should not print Component -loaded props- 2`] = `null`;
62 |
63 | exports[`@hoc-react-loader/core print parameter should not print Component -print as a value- 1`] = `null`;
64 |
65 | exports[`@hoc-react-loader/core print parameter should not print Component -print as function- 1`] = `null`;
66 |
67 | exports[`@hoc-react-loader/core print parameter should not print Component -print as function- 2`] = `
68 | Array [
69 | Array [
70 | Object {
71 | "some": "props",
72 | },
73 | Object {},
74 | ],
75 | ]
76 | `;
77 |
78 | exports[`@hoc-react-loader/core print parameter should print Component -empty parameters- 1`] = `"
28 | This is a higher order component ("HOC").
29 | Its purpose is to call a
30 |
load
31 | callback passed through the
32 |
props
33 | of a component only once (at
34 |
componentWillMount
35 | ). This is convenient to load
36 | data from a backend for instance. The component shows a loading indicator when it's
37 | waiting for the props to be defined. The loading indicator can be changed easily.
38 |
39 |
40 |
41 | Check out the examples below. Use the button to trigger a stubbed loading.
42 |