Skip to content

Commit

Permalink
Merge pull request #14 from xtuc/feat-dynamic-import
Browse files Browse the repository at this point in the history
Improve dynamic import support
  • Loading branch information
xtuc authored Apr 24, 2017
2 parents da57ee8 + 882854e commit 4e3bf7f
Show file tree
Hide file tree
Showing 14 changed files with 253 additions and 11 deletions.
1 change: 1 addition & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
## React

- [Basic example](https://github.com/xtuc/async-reactor/tree/master/examples/React-basic)
- [Dynamic import example](https://github.com/xtuc/async-reactor/tree/master/examples/React-dynamic-import)
4 changes: 4 additions & 0 deletions examples/React-dynamic-import/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/coverage
/dist
/node_modules
npm-debug.log*
29 changes: 29 additions & 0 deletions examples/React-dynamic-import/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# React

## Prerequisites

[Node.js](http://nodejs.org/) >= v4 must be installed.

## Installation

- Running `npm install` in the app's root directory will install everything you need for development.

## Development Server

- `npm start` will run the app's development server at [http://localhost:3000](http://localhost:3000) with hot module reloading.

## Running Tests

- `npm test` will run the tests once.

- `npm run test:coverage` will run the tests and produce a coverage report in `coverage/`.

- `npm run test:watch` will run the tests on every change.

## Building

- `npm run build` creates a production build by default.

To create a development build, set the `NODE_ENV` environment variable to `development` while running this command.

- `npm run clean` will delete built resources.
3 changes: 3 additions & 0 deletions examples/React-dynamic-import/nwb.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
type: 'react-app'
}
28 changes: 28 additions & 0 deletions examples/React-dynamic-import/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"name": "React",
"version": "1.0.0",
"description": "Async-reactor in React example",
"private": true,
"scripts": {
"build": "nwb build-react-app",
"clean": "nwb clean-app",
"start": "nwb serve-react-app",
"test": "nwb test-react",
"test:coverage": "nwb test-react --coverage",
"test:watch": "nwb test-react --server"
},
"dependencies": {
"async-reactor": "^1.0.4",
"react": "^15.5.4",
"react-dom": "^15.5.4"
},
"devDependencies": {
"nwb": "0.15.x"
},
"author": "Sven SAULEAU",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/xtuc/async-reactor-examples.git"
}
}
18 changes: 18 additions & 0 deletions examples/React-dynamic-import/src/App.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
.container {
width: 500px;
background-color: white;
margin: 20px auto;
}

.box {
box-shadow: 0 4px 5px 0 rgba(0,0,0,.14), 0 1px 10px 0 rgba(0,0,0,.12), 0 2px 4px -1px rgba(0,0,0,.2);
border-radius: 2px;
padding: 80px 56px;
padding-bottom: 30px;
margin: 30px;
}

h2 {
font-weight: 500;
color: rgb(255,64,129);
}
34 changes: 34 additions & 0 deletions examples/React-dynamic-import/src/App.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import './App.css';

import React from 'react'
import {asyncReactor} from 'async-reactor';

function Loader() {

return (
<div className='container'>
<div className='box'>
<h2>Loading ...</h2>
</div>
</div>
);
}

const Post = asyncReactor(import('./Components/Post'), Loader);

async function AsyncPosts() {
const Container = (await import('./Components/Container')).default;

const data = await fetch('https://jsonplaceholder.typicode.com/posts');
const posts = await data.json();

return (
<Container>
{posts.map((post) => (
<Post title={post.title} body={post.body} key={post.id} />
))}
</Container>
);
}

export default asyncReactor(AsyncPosts, Loader);
10 changes: 10 additions & 0 deletions examples/React-dynamic-import/src/Components/Container.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import React from 'react';

export default function Container({children}) {

return (
<div className="container">
{children}
</div>
);
}
11 changes: 11 additions & 0 deletions examples/React-dynamic-import/src/Components/Post.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React from 'react'

export default function Post({title, body}) {
return (
<article className="box">
<h2>{title}</h2>

<p>{body}</p>
</article>
);
}
13 changes: 13 additions & 0 deletions examples/React-dynamic-import/src/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title>React</title>
<meta name="description" content="">
</head>
<body>
<div id="app"></div>
</body>
</html>
18 changes: 18 additions & 0 deletions examples/React-dynamic-import/src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React from 'react';
import {render} from 'react-dom';
import {asyncReactor} from 'async-reactor';

function Loader() {

return (
<div className='container'>
<div className='box'>
<h2>Loading ...</h2>
</div>
</div>
);
}

const App = asyncReactor(import('./App'), Loader);

render(<App/>, document.querySelector('#app'));
20 changes: 20 additions & 0 deletions src/element.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/* @flow */

import {Component, createElement} from 'react';

export function createReactorElement(
Reactor: any /* Component */,
component: Function,
loaderComponent: Component<any,any,any> | string = 'div'
) {

return function renderReactorElement(passthroughProps: Object = {}) {
const props = {
wait: component,
loader: loaderComponent,
passthroughProps: passthroughProps,
};

return createElement(Reactor, props);
};
}
33 changes: 22 additions & 11 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
/* @flow */

import {Component, createElement, isValidElement} from 'react';
import {createReactorElement} from './element';

function interopRequireModule(obj) {
return obj && obj.__esModule ? obj.default : obj;
}

function isFunction(p) {
return typeof p === 'function';
}

function isPromise(p = {}) {
return isFunction(p.then);
return p && isFunction(p.then);
}

type ReactorState = {
Expand Down Expand Up @@ -41,7 +46,13 @@ class Reactor extends Component {

render() {
if ('data' in this.state) {
return this.state.data;
let renderer: any = interopRequireModule(this.state.data);

if (isFunction(renderer)) {
renderer = createElement(renderer, this.props.passthroughProps);
}

return renderer;
}

return createElement(this.props.loader);
Expand All @@ -59,17 +70,17 @@ export function asyncReactor(
);
}

if (isPromise(component)) {
return createReactorElement(
Reactor,
() => component,
loaderComponent
);
}

if (!isFunction(component)) {
throw new Error(`You must provide an async component, ${JSON.stringify(component)} given`);
}

return function (passthroughProps: Object = {}) {
const props = {
wait: component,
loader: loaderComponent,
passthroughProps: passthroughProps,
};

return createElement(Reactor, props);
};
return createReactorElement(Reactor, component, loaderComponent);
}
42 changes: 42 additions & 0 deletions test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -197,5 +197,47 @@ describe('Async reactor', () => {
});
});

describe('Promise', () => {

it('should render a Promise', (done) => {
const App = asyncReactor(
Promise.resolve(<h1>test</h1>)
);

const wrapper = mount(<App />);

setTimeout(() => {
assert.equal(wrapper.text(), 'test');
done();
}, 10);
});

it('should render a Promise with ES6 module', (done) => {
const App = asyncReactor(
Promise.resolve({__esModule: true, default: <h1>test</h1>})
);

const wrapper = mount(<App />);

setTimeout(() => {
assert.equal(wrapper.text(), 'test');
done();
}, 10);
});

it('should render a Promise with props', (done) => {
const App = asyncReactor(
Promise.resolve(({text}) => <h1>{text}</h1>)
);

const wrapper = mount(<App text={'ok'}/>);

setTimeout(() => {
assert.equal(wrapper.text(), 'ok');
done();
}, 10);
});
});

});
});

0 comments on commit 4e3bf7f

Please sign in to comment.