├── src
├── style
│ ├── resources
│ │ └── _variables.scss
│ └── main.scss
├── routes
│ ├── stories.js
│ ├── homePage
│ │ ├── homePageRoute.js
│ │ ├── homePageRoute.story.js
│ │ └── homePageRoute.test.js
│ └── root
│ │ ├── rootRoute.test.js
│ │ └── rootRoute.js
├── containers
│ ├── stories.js
│ └── displayStars
│ │ ├── displayStarsContainer.story.js
│ │ ├── displayStarsContainer.test.js
│ │ └── displayStarsContainer.js
├── components
│ ├── displayStars
│ │ ├── displayStarsComponent.scss
│ │ ├── displayStarsComponent.story.js
│ │ ├── displayStarsComponent.js
│ │ └── displayStarsComponent.test.js
│ ├── stories.js
│ └── appWrapper
│ │ ├── appWrapperComponent.test.js
│ │ ├── appWrapperComponent.scss
│ │ ├── appWrapperComponent.story.js
│ │ └── appWrapperComponent.js
├── stories.js
├── __tests__
│ ├── shoryshots.test.js
│ └── __snapshots__
│ │ └── shoryshots.test.js.snap
├── redux
│ ├── reducers
│ │ ├── index.js
│ │ └── basicReducer
│ │ │ ├── basicReducerReducer.test.js
│ │ │ └── basicReducerReducer.js
│ ├── sagas
│ │ ├── index.js
│ │ └── basic
│ │ │ ├── basicSaga.test.js
│ │ │ └── basicSaga.js
│ └── store.js
├── index.js
├── services
│ └── network
│ │ ├── networkService.js
│ │ └── mocks
│ │ └── github.js
├── registerServiceWorker.js
└── assets
│ └── icons
│ └── logo.svg
├── .browserslistrc
├── blueprints
├── component
│ ├── files
│ │ └── __root__
│ │ │ └── components
│ │ │ └── __name__
│ │ │ ├── __name__Component.scss
│ │ │ ├── __name__Component.js
│ │ │ ├── __name__Component.story.js
│ │ │ └── __name__Component.test.js
│ └── index.js
├── route
│ ├── files
│ │ └── __root__
│ │ │ └── routes
│ │ │ └── __name__
│ │ │ ├── __name__Route.js
│ │ │ ├── __name__Route.story.js
│ │ │ └── __name__Route.test.js
│ └── index.js
├── saga
│ ├── files
│ │ └── __root__
│ │ │ └── redux
│ │ │ └── sagas
│ │ │ └── __name__
│ │ │ ├── __name__Saga.test.js
│ │ │ └── __name__Saga.js
│ └── index.js
├── container
│ ├── files
│ │ └── __root__
│ │ │ └── containers
│ │ │ └── __name__
│ │ │ ├── __name__Container.test.js
│ │ │ ├── __name__Container.story.js
│ │ │ └── __name__Container.js
│ └── index.js
└── reducer
│ ├── index.js
│ └── files
│ └── __root__
│ └── redux
│ └── reducers
│ └── __name__
│ ├── __name__Reducer.test.js
│ └── __name__Reducer.js
├── .reduxrc
├── public
├── favicon.ico
├── manifest.json
└── index.html
├── .vscode
├── settings.json
└── extensions.json
├── .eslintrc
├── .storybook
├── config.js
└── webpack.config.js
├── .editorconfig
├── .gitignore
├── config
├── jest
│ ├── fileTransform.js
│ └── cssTransform.js
├── polyfills.js
├── paths.js
├── env.js
├── webpackDevServer.config.js
├── webpack.config.dev.js
└── webpack.config.prod.js
├── .flowconfig
├── scripts
├── test.js
├── start.js
└── build.js
├── package.json
└── README.md
/src/style/resources/_variables.scss:
--------------------------------------------------------------------------------
1 | $wide: 300px;
2 |
--------------------------------------------------------------------------------
/.browserslistrc:
--------------------------------------------------------------------------------
1 | > 1%
2 | Last 2 versions
3 | IE 10 # sorry
--------------------------------------------------------------------------------
/src/routes/stories.js:
--------------------------------------------------------------------------------
1 | import './homePage/homePageRoute.story'
2 |
--------------------------------------------------------------------------------
/blueprints/component/files/__root__/components/__name__/__name__Component.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/containers/stories.js:
--------------------------------------------------------------------------------
1 | import './displayStars/displayStarsContainer.story'
2 |
--------------------------------------------------------------------------------
/.reduxrc:
--------------------------------------------------------------------------------
1 | {"sourceBase":"src","testBase":"","smartPath":"","dumbPath":"","fileCasing":"camel"}
2 |
--------------------------------------------------------------------------------
/src/components/displayStars/displayStarsComponent.scss:
--------------------------------------------------------------------------------
1 | .button {
2 | width: $wide;
3 | }
4 |
--------------------------------------------------------------------------------
/src/style/main.scss:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akrigline/react-redux-saga-starter/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "flow.useNPMPackagedFlow": true,
3 | "javascript.validate.enable": false
4 | }
--------------------------------------------------------------------------------
/src/stories.js:
--------------------------------------------------------------------------------
1 | import './routes/stories'
2 | import './containers/stories'
3 | import './components/stories'
4 |
--------------------------------------------------------------------------------
/src/__tests__/shoryshots.test.js:
--------------------------------------------------------------------------------
1 | import initStoryshots from '@storybook/addon-storyshots'
2 |
3 | initStoryshots()
4 |
--------------------------------------------------------------------------------
/src/components/stories.js:
--------------------------------------------------------------------------------
1 | import './displayStars/displayStarsComponent.story'
2 | import './appWrapper/appWrapperComponent.story'
3 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": ["react-app", "plugin:jsx-a11y/recommended", "standard", "standard-react"],
3 | "plugins": ["jsx-a11y"]
4 | }
5 |
--------------------------------------------------------------------------------
/.storybook/config.js:
--------------------------------------------------------------------------------
1 | import { configure } from '@storybook/react';
2 |
3 | function loadStories() {
4 | require('../src/stories');
5 | }
6 |
7 | configure(loadStories, module);
8 |
--------------------------------------------------------------------------------
/src/redux/reducers/index.js:
--------------------------------------------------------------------------------
1 | import {combineReducers} from 'redux'
2 | import basicReducer from './basicReducer/basicReducerReducer'
3 | export default combineReducers({basicReducer})
4 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | "rtorr.vscode-flow",
4 | "dbaeumer.vscode-eslint",
5 | "EditorConfig.editorconfig",
6 | "dzannotti.vscode-babel-coloring"
7 | ]
8 | }
--------------------------------------------------------------------------------
/blueprints/component/files/__root__/components/__name__/__name__Component.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | export default function <%= pascalEntityName %> (props) {
4 | return (
5 |
8 | )
9 | }
10 |
--------------------------------------------------------------------------------
/src/redux/sagas/index.js:
--------------------------------------------------------------------------------
1 | import watchBasic, {actionCreators as basicActions} from './basic/basicSaga'
2 |
3 | export const actions = {
4 | basicActions
5 | }
6 | export default function * rootSaga () {
7 | yield [
8 | watchBasic()
9 | ]
10 | }
11 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig is awesome: http://EditorConfig.org
2 |
3 | # top-most EditorConfig file
4 | root = true
5 |
6 | # Unix-style newlines with a newline ending every file
7 | [*]
8 | end_of_line = lf
9 | insert_final_newline = true
10 | indent_style = space
11 | indent_size = 2
--------------------------------------------------------------------------------
/src/components/displayStars/displayStarsComponent.story.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { storiesOf } from '@storybook/react'
3 | import DisplayStars from './displayStarsComponent'
4 | storiesOf('DisplayStars', module).add('with text', () =>
5 | Hello World
6 | )
7 |
--------------------------------------------------------------------------------
/src/components/appWrapper/appWrapperComponent.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { shallow } from 'enzyme'
3 | import AppWrapper from './appWrapperComponent'
4 |
5 | it('renders without crashing', () => {
6 | const appWrapperComponent = shallow()
7 | expect(appWrapperComponent.length).toBe(1)
8 | })
9 |
--------------------------------------------------------------------------------
/src/redux/sagas/basic/basicSaga.test.js:
--------------------------------------------------------------------------------
1 | import {getBasic} from './BasicSaga'
2 | import { call } from 'redux-saga/effects'
3 | import axios from 'axios'
4 |
5 | it('should call the api', () => {
6 | const iterator = getBasic()
7 | expect(iterator.next().value).toEqual(call(axios.get, 'https://api.github.com/repos/akrigline/react-redux-saga-starter'))
8 | })
9 |
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "192x192",
8 | "type": "image/png"
9 | }
10 | ],
11 | "start_url": "./index.html",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # testing
7 | /coverage
8 |
9 | # production
10 | /build
11 |
12 | # misc
13 | .DS_Store
14 | .env.local
15 | .env.development.local
16 | .env.test.local
17 | .env.production.local
18 |
19 | npm-debug.log*
20 | yarn-debug.log*
21 | yarn-error.log*
22 |
--------------------------------------------------------------------------------
/config/jest/fileTransform.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const path = require('path');
4 |
5 | // This is a custom Jest transformer turning file imports into filenames.
6 | // http://facebook.github.io/jest/docs/tutorial-webpack.html
7 |
8 | module.exports = {
9 | process(src, filename) {
10 | return `module.exports = ${JSON.stringify(path.basename(filename))};`;
11 | },
12 | };
13 |
--------------------------------------------------------------------------------
/blueprints/route/files/__root__/routes/__name__/__name__Route.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | class <%= pascalEntityName %>Scene extends React.Component {
4 | props: {
5 |
6 | }
7 |
8 | render () {
9 | return (
10 |
11 |
12 | Things!
13 |
14 |
15 | )
16 | }
17 | }
18 |
19 | export default <%= pascalEntityName %>Scene
20 |
--------------------------------------------------------------------------------
/config/jest/cssTransform.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // This is a custom Jest transformer turning style imports into empty objects.
4 | // http://facebook.github.io/jest/docs/tutorial-webpack.html
5 |
6 | module.exports = {
7 | process() {
8 | return 'module.exports = {};';
9 | },
10 | getCacheKey() {
11 | // The output is always the same.
12 | return 'cssTransform';
13 | },
14 | };
15 |
--------------------------------------------------------------------------------
/src/routes/homePage/homePageRoute.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import SmartDisplayStars from '../../containers/displayStars/displayStarsContainer'
3 |
4 | class HomePageRoute extends React.Component {
5 | render () {
6 | return (
7 |
8 |
This is the Homepage
9 |
10 |
11 | )
12 | }
13 | props: {}
14 | }
15 | export default HomePageRoute
16 |
--------------------------------------------------------------------------------
/blueprints/saga/files/__root__/redux/sagas/__name__/__name__Saga.test.js:
--------------------------------------------------------------------------------
1 | import {get<%= pascalEntityName %>} from './<%= pascalEntityName %>Saga'
2 | import { call } from 'redux-saga/effects'
3 | import axios from 'axios'
4 |
5 | it('should call the api', () => {
6 | const iterator = get<%= pascalEntityName %>()
7 | expect(iterator.next().value).toEqual(call(axios.get, 'https://api.github.com/repos/ericwooley/react-native-redux-jest-starter-kit'))
8 | })
9 |
--------------------------------------------------------------------------------
/src/components/appWrapper/appWrapperComponent.scss:
--------------------------------------------------------------------------------
1 | .app {
2 | text-align: center;
3 | }
4 |
5 | .appLogo {
6 | animation: app-logo-spin infinite 20s linear;
7 | height: 80px;
8 | }
9 |
10 | .appHeader {
11 | background-color: #222;
12 | height: 150px;
13 | padding: 20px;
14 | color: white;
15 | }
16 |
17 | .appIntro {
18 | font-size: large;
19 | }
20 |
21 | @keyframes app-logo-spin {
22 | from { transform: rotate(0deg); }
23 | to { transform: rotate(360deg); }
24 | }
25 |
--------------------------------------------------------------------------------
/blueprints/component/files/__root__/components/__name__/__name__Component.story.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { storiesOf } from '@storybook/react'
3 | import { action } from '@storybook/addon-actions'
4 | import '../../style/main.scss'
5 | import <%= pascalEntityName %> from './<%= camelEntityName %>Component'
6 | storiesOf('<%= pascalEntityName %>', module)
7 | .add('with text', () => (
8 | <<%= pascalEntityName %>>
9 | Hello World
10 | <%= pascalEntityName %>>
11 | ))
12 |
--------------------------------------------------------------------------------
/blueprints/component/files/__root__/components/__name__/__name__Component.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import <%= pascalEntityName %> from './<%= camelEntityName %>Component'
3 | import {shallow} from 'enzyme'
4 |
5 | it('should call onClick', () => {
6 | const onClickMock = jest.fn()
7 | const <%= camelEntityName %> = shallow(<<%= pascalEntityName %> onClick={onClickMock} />)
8 | <%= camelEntityName %>.find('button').simulate('click')
9 | expect(onClickMock.mock.calls.length).toBe(1)
10 | })
11 |
--------------------------------------------------------------------------------
/src/containers/displayStars/displayStarsContainer.story.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { storiesOf } from '@storybook/react'
3 | import { Provider } from 'react-redux'
4 | import createReduxStore from '../../redux/store'
5 | import DisplayStars from './displayStarsContainer'
6 |
7 | storiesOf('DisplayStarsContainer', module).add('with stars', () => {
8 | const reduxStore = createReduxStore()
9 | return (
10 |
11 |
12 |
13 | )
14 | })
15 |
--------------------------------------------------------------------------------
/src/routes/homePage/homePageRoute.story.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { storiesOf } from '@storybook/react'
3 | import { Provider } from 'react-redux'
4 | import createReduxStore from '../../redux/store'
5 | import HomePage from './homePageRoute'
6 |
7 | const reduxStore = createReduxStore()
8 |
9 | const provider = storyFn =>
10 |
11 | {storyFn()}
12 |
13 |
14 | storiesOf('Homepage', module)
15 | .addDecorator(provider)
16 | .add('should Render', () => )
17 |
--------------------------------------------------------------------------------
/blueprints/container/files/__root__/containers/__name__/__name__Container.test.js:
--------------------------------------------------------------------------------
1 | import {mapStateToProps, propsMapping} from './<%= camelEntityName %>Container'
2 | describe('<%= camelEntityName %> container', () => {
3 | it('should map state to props', () => {
4 | const state = {counter: {count: 12}}
5 | const mappedState = mapStateToProps(state)
6 | expect(mappedState).toEqual({starCount: 12})
7 | })
8 | it('should have a propsMapping', () => {
9 | expect(typeof propsMapping.onClick).toEqual('function')
10 | })
11 | })
12 |
--------------------------------------------------------------------------------
/src/components/appWrapper/appWrapperComponent.story.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { storiesOf } from '@storybook/react'
3 | import { Provider } from 'react-redux'
4 | import createReduxStore from '../../redux/store'
5 | import AppWrapper from './appWrapperComponent'
6 |
7 | const reduxStore = createReduxStore()
8 |
9 | const provider = storyFn =>
10 |
11 | {storyFn()}
12 |
13 |
14 | storiesOf('App Wrapper', module)
15 | .addDecorator(provider)
16 | .add('should Render', () => )
17 |
--------------------------------------------------------------------------------
/.flowconfig:
--------------------------------------------------------------------------------
1 | [ignore]
2 | .*/blueprints/.*
3 | .*/src/components/.*/*.story.js
4 | .*/src/components/.*/*.test.js
5 | .*/src/containers/.*/*.story.js
6 | .*/src/containers/.*/*.test.js
7 | .*/src/scenes/.*/*.story.js
8 | .*/src/scenes/.*/*.test.js
9 | .*/src/redux/reducers/.*/*.test.js
10 | .*/src/redux/sagas/.*/*.test.js
11 |
12 | [include]
13 | .*/src/components/.*/*.js
14 | .*/src/scenes/.*/*.js
15 | .*/src/containers/.*/*.js
16 | .*/src/redux/reducers/.*/*.js
17 | .*/src/redux/sagas/.*/*.js
18 |
19 | [libs]
20 |
21 | [options]
22 | module.name_mapper.extension='scss' -> 'empty/object'
23 |
--------------------------------------------------------------------------------
/src/components/appWrapper/appWrapperComponent.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import logo from '../../assets/icons/logo.svg'
3 | import styles from './appWrapperComponent.scss'
4 |
5 | class AppWrapper extends Component {
6 | render () {
7 | return (
8 |
9 |
10 |

11 |
Welcome to React
12 |
13 | {this.props.children}
14 |
15 | )
16 | }
17 |
18 | props: {
19 | children: any
20 | }
21 | }
22 |
23 | export default AppWrapper
24 |
--------------------------------------------------------------------------------
/blueprints/route/files/__root__/routes/__name__/__name__Route.story.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { storiesOf } from '@storybook/react'
3 | import { Provider } from 'react-redux'
4 | import createReduxStore from '../../redux/store'
5 | import <%= pascalEntityName %> from './<%= camelEntityName %>Scene'
6 |
7 |
8 | const reduxStore = createReduxStore()
9 |
10 | const provider = (storyFn) => (
11 |
12 | { storyFn() }
13 |
14 | )
15 |
16 | storiesOf('<%= pascalEntityName %> Scene', module)
17 | .addDecorator(provider)
18 | .add('should Render', () => (
19 | <<%= pascalEntityName %> />
20 | ))
21 |
--------------------------------------------------------------------------------
/blueprints/container/files/__root__/containers/__name__/__name__Container.story.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { storiesOf } from '@storybook/react'
3 | import { Provider } from 'react-redux'
4 | import { createReduxStore } from '../../redux/store'
5 | import <%= pascalEntityName %> from './<%= camelEntityName %>Container'
6 |
7 | storiesOf('<%= pascalEntityName %>Container', module)
8 | .add('with 7 stars', () => {
9 | const reduxStore = createReduxStore('<%= pascalEntityName %> story store', {counter: {count: 7}})
10 | return (
11 |
12 | <<%= pascalEntityName %> />
13 |
14 | )
15 | })
16 |
--------------------------------------------------------------------------------
/config/polyfills.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | if (typeof Promise === 'undefined') {
4 | // Rejection tracking prevents a common issue where React gets into an
5 | // inconsistent state due to an error, but it gets swallowed by a Promise,
6 | // and the user has no idea what causes React's erratic future behavior.
7 | require('promise/lib/rejection-tracking').enable();
8 | window.Promise = require('promise/lib/es6-extensions.js');
9 | }
10 |
11 | // fetch() polyfill for making API calls.
12 | require('whatwg-fetch');
13 |
14 | // Object.assign() is commonly used with React.
15 | // It will use the native implementation if it's present and isn't buggy.
16 | Object.assign = require('object-assign');
17 |
--------------------------------------------------------------------------------
/scripts/test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // Do this as the first thing so that any code reading it knows the right env.
4 | process.env.BABEL_ENV = 'test';
5 | process.env.NODE_ENV = 'test';
6 | process.env.PUBLIC_URL = '';
7 |
8 | // Makes the script crash on unhandled rejections instead of silently
9 | // ignoring them. In the future, promise rejections that are not handled will
10 | // terminate the Node.js process with a non-zero exit code.
11 | process.on('unhandledRejection', err => {
12 | throw err;
13 | });
14 |
15 | // Ensure environment variables are read.
16 | require('../config/env');
17 |
18 | const jest = require('jest');
19 | const argv = process.argv.slice(2);
20 |
21 | jest.run(argv);
22 |
--------------------------------------------------------------------------------
/.storybook/webpack.config.js:
--------------------------------------------------------------------------------
1 | // you can use this file to add your custom webpack plugins, loaders and anything you like.
2 | // This is just the basic way to add additional webpack configurations.
3 | // For more information refer the docs: https://storybook.js.org/configurations/custom-webpack-config
4 |
5 | // IMPORTANT
6 | // When you add this file, we won't add the default configurations which is similar
7 | // to "React Create App". This only has babel loader to load JavaScript.
8 |
9 | let mainWebpackConfig = require('../config/webpack.config.dev')
10 |
11 | module.exports = {
12 | plugins: mainWebpackConfig.plugins,
13 | module: {
14 | rules: mainWebpackConfig.module.rules,
15 | },
16 | };
17 |
--------------------------------------------------------------------------------
/src/components/displayStars/displayStarsComponent.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 | import styles from './displayStarsComponent.scss'
4 |
5 | export default function DisplayStars (props) {
6 | return (
7 |
8 |
9 | {props.starCount} Things!
10 |
11 |
14 |
17 |
18 | )
19 | }
20 |
21 | DisplayStars.propTypes = {
22 | starCount: PropTypes.string,
23 | increment: PropTypes.func,
24 | decrement: PropTypes.func
25 | }
26 |
--------------------------------------------------------------------------------
/src/containers/displayStars/displayStarsContainer.test.js:
--------------------------------------------------------------------------------
1 | import { mapStateToProps, propsMapping } from './displayStarsContainer'
2 | import createReduxStore from '../../redux/store'
3 |
4 | describe('displayStars container', () => {
5 | it('should map state to props', () => {
6 | const store = createReduxStore()
7 | const state = store.getState()
8 | const mappedProps = mapStateToProps(state)
9 | const keys = Object.keys(mappedProps)
10 | let errors = []
11 | keys.forEach(key => {
12 | if (mappedProps[key] === undefined) {
13 | errors.push(key)
14 | }
15 | })
16 |
17 | expect(errors.length).toEqual(0)
18 | })
19 | it('should have a propsMapping', () => {
20 | expect(typeof propsMapping.fetchBasic).toEqual('function')
21 | })
22 | })
23 |
--------------------------------------------------------------------------------
/src/redux/store.js:
--------------------------------------------------------------------------------
1 | import { createStore, applyMiddleware } from 'redux'
2 | import reducers from './reducers'
3 | import createSagaMiddleware from 'redux-saga'
4 | import rootSaga from './sagas'
5 | import { composeWithDevTools } from 'redux-devtools-extension'
6 | // create the saga middleware
7 |
8 | export default function createReduxStore (name, initialState = {}) {
9 | const sagaMiddleware = createSagaMiddleware()
10 | const middleware = composeWithDevTools(applyMiddleware(sagaMiddleware))
11 | let store = createStore(reducers, initialState, middleware)
12 | sagaMiddleware.run(rootSaga)
13 | if (module.hot) {
14 | // Enable Webpack hot module replacement for reducers
15 | module.hot.accept('./reducers', () => {
16 | const nextRootReducer = require('./reducers/index')
17 | store.replaceReducer(nextRootReducer)
18 | })
19 | }
20 | return store
21 | }
22 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import { Provider } from 'react-redux'
4 | import Root from './routes/root/rootRoute'
5 | import registerServiceWorker from './registerServiceWorker'
6 | import './style/main.scss'
7 | import createReduxStore from './redux/store'
8 | import { AppContainer } from 'react-hot-loader'
9 |
10 | const store = createReduxStore()
11 |
12 | const render = Component => {
13 | ReactDOM.render(
14 |
15 |
16 |
17 |
18 | ,
19 | document.getElementById('root')
20 | )
21 | }
22 |
23 | render(Root)
24 |
25 | if (module.hot) {
26 | module.hot.accept('./routes/root/rootRoute', () => {
27 | // render(Root)
28 | render(require('./routes/root/rootRoute').default)
29 | })
30 | }
31 |
32 | registerServiceWorker()
33 |
--------------------------------------------------------------------------------
/src/redux/reducers/basicReducer/basicReducerReducer.test.js:
--------------------------------------------------------------------------------
1 | import basicReducerReducer, {actions, actionCreators} from './basicReducerReducer'
2 |
3 | it('should create increment actions', () => {
4 | expect(actionCreators.increment(1)).toEqual({type: actions.INCREMENT, payload: 1})
5 | })
6 | it('should create decrement actions', () => {
7 | expect(actionCreators.decrement(1)).toEqual({type: actions.DECREMENT, payload: 1})
8 | })
9 |
10 | it('should reduce increments', () => {
11 | expect(basicReducerReducer({count: 5}, actionCreators.increment(1))).toEqual({count: 6})
12 | })
13 | it('should reduce decrements', () => {
14 | expect(basicReducerReducer({count: 5}, actionCreators.decrement(2))).toEqual({count: 3})
15 | })
16 | it('should set the stars to whatever comes from the setStars saga', () => {
17 | expect(basicReducerReducer({count: 938}, {type: actions.FETCH_BASIC_SUCCESS, payload: 9999})).toEqual({count: 9999})
18 | })
19 |
--------------------------------------------------------------------------------
/blueprints/saga/index.js:
--------------------------------------------------------------------------------
1 | var path = require('path')
2 | var chalk = require('chalk')
3 | module.exports = {
4 | locals: function (options) {
5 | // Return custom template variables here.
6 | return {}
7 | },
8 |
9 | fileMapTokens: function (options) {
10 | // Return custom tokens to be replaced in your files
11 | return {
12 | __token__: function (options) {
13 | // logic to determine value goes here
14 | return 'value'
15 | }
16 | }
17 | },
18 |
19 | filesPath: function () {
20 | // if you want to store generated files in a folder named
21 | // something other than 'files' you can override this
22 | return path.join(this.path, 'files')
23 | },
24 |
25 | // before and after install hooks
26 | beforeInstall: function (options) {},
27 | afterInstall: function (options) {
28 | console.warn(chalk.red('Make sure you add your saga to the root saga in src/redux/sagas/index.js'))
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/blueprints/reducer/index.js:
--------------------------------------------------------------------------------
1 | var path = require('path')
2 | var chalk = require('chalk')
3 | module.exports = {
4 | locals: function (options) {
5 | // Return custom template variables here.
6 | return {}
7 | },
8 |
9 | fileMapTokens: function (options) {
10 | // Return custom tokens to be replaced in your files
11 | return {
12 | __token__: function (options) {
13 | // logic to determine value goes here
14 | return 'value'
15 | }
16 | }
17 | },
18 |
19 | filesPath: function () {
20 | // if you want to store generated files in a folder named
21 | // something other than 'files' you can override this
22 | return path.join(this.path, 'files')
23 | },
24 |
25 | // before and after install hooks
26 | beforeInstall: function (options) {},
27 | afterInstall: function (options) {
28 | console.warn(chalk.red('Make sure you add your reducer to the root reducer in src/redux/reducers/index.js'))
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/blueprints/reducer/files/__root__/redux/reducers/__name__/__name__Reducer.test.js:
--------------------------------------------------------------------------------
1 | import <%= camelEntityName %>Reducer, {actions, actionCreators} from './<%= camelEntityName %>Reducer'
2 |
3 | it('should create increment actions', () => {
4 | expect(actionCreators.increment(1)).toEqual({type: actions.INCREMENT, payload: 1})
5 | })
6 | it('should create decrement actions', () => {
7 | expect(actionCreators.decrement(1)).toEqual({type: actions.DECREMENT, payload: 1})
8 | })
9 |
10 | it('should reduce increments', () => {
11 | expect(<%= camelEntityName %>Reducer({count: 5}, actionCreators.increment(1))).toEqual({count: 6})
12 | })
13 | it('should reduce decrements', () => {
14 | expect(<%= camelEntityName %>Reducer({count: 5}, actionCreators.decrement(2))).toEqual({count: 3})
15 | })
16 | it('should set the stars to whatever comes from the setStars saga', () => {
17 | expect(<%= camelEntityName %>Reducer({count: 938}, {type: actions.FETCH_STARS_SUCCESS, payload: 9999})).toEqual({count: 9999})
18 | })
19 |
--------------------------------------------------------------------------------
/blueprints/component/index.js:
--------------------------------------------------------------------------------
1 | var path = require('path')
2 | var fs = require('fs')
3 | module.exports = {
4 | locals: function (options) {
5 | // Return custom template variables here.
6 | return {}
7 | },
8 |
9 | fileMapTokens: function (options) {
10 | // Return custom tokens to be replaced in your files
11 | return {
12 | __token__: function (options) {
13 | // logic to determine value goes here
14 | return 'value'
15 | }
16 | }
17 | },
18 |
19 | filesPath: function () {
20 | // if you want to store generated files in a folder named
21 | // something other than 'files' you can override this
22 | return path.join(this.path, 'files')
23 | },
24 |
25 | // before and after install hooks
26 | beforeInstall: function (options) {},
27 | afterInstall: function (options) {
28 | fs.appendFileSync(path.join(__dirname, '../../src/components/stories.js'), `import './${options.entity.name}/${options.entity.name}Component.story'\n`)
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/blueprints/container/index.js:
--------------------------------------------------------------------------------
1 | var path = require('path')
2 | var fs = require('fs')
3 | module.exports = {
4 | locals: function (options) {
5 | // Return custom template variables here.
6 | return {}
7 | },
8 |
9 | fileMapTokens: function (options) {
10 | // Return custom tokens to be replaced in your files
11 | return {
12 | __token__: function (options) {
13 | // logic to determine value goes here
14 | return 'value'
15 | }
16 | }
17 | },
18 |
19 | filesPath: function () {
20 | // if you want to store generated files in a folder named
21 | // something other than 'files' you can override this
22 | return path.join(this.path, 'files')
23 | },
24 |
25 | // before and after install hooks
26 | beforeInstall: function (options) {},
27 | afterInstall: function (options) {
28 | fs.appendFileSync(path.join(__dirname, '../../src/containers/stories.js'), `import './${options.entity.name}/${options.entity.name}Container.story'\n`)
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/blueprints/reducer/files/__root__/redux/reducers/__name__/__name__Reducer.js:
--------------------------------------------------------------------------------
1 | import { createAction, handleActions } from 'redux-actions'
2 | import {FETCH_STARS_SUCCESS} from '../../sagas/<%= camelEntityName %>/<%= camelEntityName %>Saga'
3 | // Name Spaced Action Types
4 | const INCREMENT = '<%= pascalEntityName %>/INCREMENT'
5 | const DECREMENT = '<%= pascalEntityName %>/DECREMENT'
6 | export const actions = {
7 | INCREMENT,
8 | DECREMENT,
9 | FETCH_STARS_SUCCESS
10 | }
11 |
12 | export const actionCreators = {
13 | increment: createAction(INCREMENT),
14 | decrement: createAction(DECREMENT)
15 | }
16 |
17 | export const initialState = {
18 | count: 0
19 | }
20 |
21 | export default handleActions({
22 | [INCREMENT]: (state, action) =>
23 | ({...state, count: state.count + action.payload}),
24 | [DECREMENT]: (state, action) =>
25 | ({...state, count: state.count - action.payload}),
26 | [FETCH_STARS_SUCCESS]: (state, action) =>
27 | ({...state, count: action.payload})
28 | }, initialState)
29 |
--------------------------------------------------------------------------------
/src/services/network/networkService.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios'
2 | import MockAdapter from 'axios-mock-adapter'
3 | import gitHubMocks from './mocks/github'
4 |
5 | /**
6 | * There is no unit tests for this functionality because things seem to break upon being pulled into jest.
7 | * Hopefully I can figure that out at some point.
8 | */
9 | let mocksInitiated = false
10 | let mock = null
11 | let mocksEnabled = false
12 | export default axios
13 | export function mockRequests () {
14 | if (!mocksInitiated) {
15 | mock = new MockAdapter(axios)
16 | // Mocks should be added here
17 | gitHubMocks(mock)
18 | } else {
19 | axios.defaults.adapter = mock
20 | }
21 | mocksInitiated = true
22 | }
23 |
24 | export function toggleMocks () {
25 | if (mocksEnabled) {
26 | restoreRequests()
27 | mocksEnabled = false
28 | } else {
29 | mockRequests()
30 | mocksEnabled = true
31 | }
32 | return mocksEnabled
33 | }
34 |
35 | export function restoreRequests () {
36 | mock.restore()
37 | }
38 |
--------------------------------------------------------------------------------
/blueprints/route/index.js:
--------------------------------------------------------------------------------
1 | var path = require('path')
2 | var fs = require('fs')
3 | module.exports = {
4 | locals: function (options) {
5 | // Return custom template variables here.
6 | return {}
7 | },
8 |
9 | fileMapTokens: function (options) {
10 | // Return custom tokens to be replaced in your files
11 | return {
12 | __token__: function (options) {
13 | // logic to determine value goes here
14 | return 'value'
15 | }
16 | }
17 | },
18 |
19 | filesPath: function () {
20 | // if you want to store generated files in a folder named
21 | // something other than 'files' you can override this
22 | return path.join(this.path, 'files')
23 | },
24 |
25 | // before and after install hooks
26 | beforeInstall: function (options) {},
27 | afterInstall: function (options) {
28 | fs.appendFileSync(
29 | path.join(__dirname, '../../src/scenes/stories.js'),
30 | `import './${options.entity.name}/${options.entity.name}Route.story'\n`
31 | )
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/components/displayStars/displayStarsComponent.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import DisplayStars from './displayStarsComponent'
3 | import { shallow } from 'enzyme'
4 | it('should render without stars', () => {
5 | const displayStars = shallow()
6 | expect(displayStars.length).toBe(1)
7 | })
8 | it('should render with stars', () => {
9 | const displayStars = shallow()
10 | expect(displayStars.length).toBe(1)
11 | })
12 | it('should call increment on an increase click', () => {
13 | const mockFunction = jest.fn()
14 | const displayStars = shallow()
15 | displayStars.find('button').at(0).simulate('click')
16 | expect(mockFunction.mock.calls.length).toBe(1)
17 | })
18 | it('should call decrement on an increase click', () => {
19 | const mockFunction = jest.fn()
20 | const displayStars = shallow()
21 | displayStars.find('button').at(1).simulate('click')
22 | expect(mockFunction.mock.calls.length).toBe(1)
23 | })
24 |
--------------------------------------------------------------------------------
/src/redux/reducers/basicReducer/basicReducerReducer.js:
--------------------------------------------------------------------------------
1 | import { createAction, handleActions } from 'redux-actions'
2 | import { FETCH_BASIC_SUCCESS } from '../../sagas/basic/basicSaga'
3 | // Name Spaced Action Types
4 | const INCREMENT = 'BasicReducer/INCREMENT'
5 | const DECREMENT = 'BasicReducer/DECREMENT'
6 | export const actions = {
7 | INCREMENT,
8 | DECREMENT,
9 | FETCH_BASIC_SUCCESS
10 | }
11 |
12 | export const actionCreators = {
13 | increment: createAction(INCREMENT),
14 | decrement: createAction(DECREMENT)
15 | }
16 |
17 | export const initialState = {
18 | count: 0,
19 | string: 'string'
20 | }
21 |
22 | export default handleActions(
23 | {
24 | [INCREMENT]: (state, action) => ({
25 | ...state,
26 | count: state.count + action.payload
27 | }),
28 | [DECREMENT]: (state, action) => ({
29 | ...state,
30 | count: state.count - action.payload
31 | }),
32 | [FETCH_BASIC_SUCCESS]: (state, action) => ({
33 | ...state,
34 | count: action.payload
35 | })
36 | },
37 | initialState
38 | )
39 |
--------------------------------------------------------------------------------
/src/routes/homePage/homePageRoute.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import HomePageRoute from './homePageRoute'
3 | import { shallow } from 'enzyme'
4 |
5 | it('should render', () => {
6 | const homePageRoute = shallow()
7 | expect(homePageRoute.length).toBe(1)
8 | })
9 |
10 | // You could use something like this to test onClick handlers
11 | // it('should call trigger stars naviation', () => {
12 | // const starsButtonMock = jest.fn()
13 | // const appScene = shallow()
14 | // const starsButton = appScene.find('.stars-button')
15 | // starsButton.simulate('press')
16 | // expect(starsButtonMock.mock.calls.length).toBe(1)
17 | // })
18 |
19 | // it('should call trigger dev-panel naviation', () => {
20 | // const starsButtonMock = jest.fn()
21 | // const appScene = shallow()
22 | // const starsButton = appScene.find('.dev-panel-button')
23 | // starsButton.simulate('press')
24 | // expect(starsButtonMock.mock.calls.length).toBe(1)
25 | // })
26 |
--------------------------------------------------------------------------------
/src/redux/sagas/basic/basicSaga.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios'
2 | import { takeLatest, call, put } from 'redux-saga/effects'
3 | import { createAction } from 'redux-actions'
4 |
5 | // Saga action strings
6 | export const FETCH_BASIC = 'saga/Basic/FETCH_BASIC'
7 | export const FETCH_BASIC_SUCCESS = 'saga/Basic/FETCH_BASIC_SUCCESS'
8 | export const FETCH_BASIC_FAILURE = 'saga/Basic/FETCH_BASIC_FAILURE'
9 |
10 | export const actionCreators = {
11 | fetchBasic: createAction(FETCH_BASIC),
12 | fetchBasicSuccess: createAction(FETCH_BASIC_SUCCESS),
13 | fetchBasicFailure: createAction(FETCH_BASIC_FAILURE)
14 | }
15 |
16 | export default function * watchBasic () {
17 | yield takeLatest(FETCH_BASIC, getBasic)
18 | }
19 |
20 | export function * getBasic (action) {
21 | try {
22 | const repoInfo = yield call(
23 | axios.get,
24 | 'https://api.github.com/repos/akrigline/react-redux-saga-starter'
25 | )
26 | yield put(actionCreators.fetchBasicSuccess(repoInfo.data.stargazers_count))
27 | } catch (error) {
28 | yield put(actionCreators.fetchBasicFailure(error))
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/routes/root/rootRoute.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import RootRoute from './rootRoute'
3 | import { shallow } from 'enzyme'
4 | import createReduxStore from '../../redux/store'
5 |
6 | it('should render', () => {
7 | const store = createReduxStore()
8 | const rootRoute = shallow()
9 | expect(rootRoute.length).toBe(1)
10 | })
11 |
12 | // You could use something like this to test onClick handlers
13 | // it('should call trigger stars naviation', () => {
14 | // const starsButtonMock = jest.fn()
15 | // const appScene = shallow()
16 | // const starsButton = appScene.find('.stars-button')
17 | // starsButton.simulate('press')
18 | // expect(starsButtonMock.mock.calls.length).toBe(1)
19 | // })
20 |
21 | // it('should call trigger dev-panel naviation', () => {
22 | // const starsButtonMock = jest.fn()
23 | // const appScene = shallow()
24 | // const starsButton = appScene.find('.dev-panel-button')
25 | // starsButton.simulate('press')
26 | // expect(starsButtonMock.mock.calls.length).toBe(1)
27 | // })
28 |
--------------------------------------------------------------------------------
/blueprints/saga/files/__root__/redux/sagas/__name__/__name__Saga.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios'
2 | import { takeLatest, call, put } from 'redux-saga/effects'
3 | import { createAction } from 'redux-actions'
4 |
5 | // Saga action strings
6 | export const FETCH_STARS = 'saga/<%= pascalEntityName %>/FETCH_STARS'
7 | export const FETCH_STARS_SUCCESS = 'saga/<%= pascalEntityName %>/FETCH_STARS_SUCCESS'
8 | export const FETCH_STARS_FAILURE = 'saga/<%= pascalEntityName %>/FETCH_STARS_FAILURE'
9 |
10 | export const actionCreators = {
11 | fetchStars: createAction(FETCH_STARS),
12 | fetchStarsSuccess: createAction(FETCH_STARS_SUCCESS),
13 | fetchStarsFailure: createAction(FETCH_STARS_FAILURE)
14 | }
15 |
16 | export default function * watch<%= pascalEntityName %> () {
17 | yield takeLatest(FETCH_STARS, get<%= pascalEntityName %>)
18 | }
19 |
20 | export function * get<%= pascalEntityName %> (action) {
21 | try {
22 | const repoInfo = yield call(axios.get, 'https://api.github.com/repos/ericwooley/react-native-redux-jest-starter-kit')
23 | yield put(actions.fetchStarsSuccess(repoInfo.data.stargazers_count))
24 | } catch (error) {
25 | yield put(actions.fetchStarsFailure(error))
26 | }
27 | }
28 |
29 |
--------------------------------------------------------------------------------
/blueprints/route/files/__root__/routes/__name__/__name__Route.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import <%= pascalEntityName %>Scene from './<%= camelEntityName %>Scene'
3 | import {shallow} from 'enzyme'
4 |
5 | it('should render', () => {
6 | const <%= camelEntityName %>Scene = shallow(<<%= pascalEntityName %>Scene />)
7 | expect(<%= camelEntityName %>Scene.length).toBe(1)
8 | })
9 |
10 |
11 | // You could use something like this to test onClick handlers
12 | // it('should call trigger stars naviation', () => {
13 | // const starsButtonMock = jest.fn()
14 | // const appScene = shallow(<<%= pascalEntityName %> navigation={{navigate: starsButtonMock}} />)
15 | // const starsButton = appScene.find('.stars-button')
16 | // starsButton.simulate('press')
17 | // expect(starsButtonMock.mock.calls.length).toBe(1)
18 | // })
19 |
20 | // it('should call trigger dev-panel naviation', () => {
21 | // const starsButtonMock = jest.fn()
22 | // const appScene = shallow(<<%= pascalEntityName %> navigation={{navigate: starsButtonMock}} />)
23 | // const starsButton = appScene.find('.dev-panel-button')
24 | // starsButton.simulate('press')
25 | // expect(starsButtonMock.mock.calls.length).toBe(1)
26 | // })
27 |
--------------------------------------------------------------------------------
/src/containers/displayStars/displayStarsContainer.js:
--------------------------------------------------------------------------------
1 | import { connect } from 'react-redux'
2 | import { compose, lifecycle } from 'recompose'
3 | import DisplayStars from '../../components/displayStars/displayStarsComponent'
4 | import { actions as sagaActions } from '../../redux/sagas/'
5 | import { actionCreators } from '../../redux/reducers/basicReducer/basicReducerReducer'
6 |
7 | // Global State
8 | export function mapStateToProps (state, props) {
9 | return {
10 | starCount: state.basicReducer.count
11 | }
12 | }
13 | // In Object form, each funciton is automatically wrapped in a dispatch
14 | export const propsMapping: Callbacks = {
15 | fetchBasic: sagaActions.basicActions.fetchBasic,
16 | increment: actionCreators.increment,
17 | decrement: actionCreators.decrement
18 | }
19 |
20 | // If you want to use the function mapping
21 | // export const propsMapping = (dispatch, ownProps) => {
22 | // return {
23 | // onClick: () => dispatch(actions.starsActions.FETCH_STARS)
24 | // }
25 | // }
26 |
27 | export default compose(
28 | connect(mapStateToProps, propsMapping),
29 | lifecycle({
30 | componentDidMount: function () {
31 | this.props.fetchBasic && this.props.fetchBasic()
32 | }
33 | })
34 | )(DisplayStars)
35 |
--------------------------------------------------------------------------------
/blueprints/container/files/__root__/containers/__name__/__name__Container.js:
--------------------------------------------------------------------------------
1 | import {connect} from 'react-redux'
2 | // For Lifecycle composing
3 | // import {compose, lifecycle} from 'recompose'
4 | import {actions as sagaActions} from '../../redux/sagas/'
5 | import {actionCreators} from '../../redux/reducers/basicReducer/basicReducerReducer'
6 |
7 | // Global State
8 | export function mapStateToProps (state, props) {
9 | return {
10 | starCount: state.counter.count
11 | }
12 | }
13 | // In Object form, each funciton is automatically wrapped in a dispatch
14 | export const propsMapping = {
15 | onClick: sagaActions.starsActions.FETCH_STARS
16 | }
17 |
18 | // If you want to use the function mapping
19 | // export const propsMapping = (dispatch, ownProps) => {
20 | // return {
21 | // onClick: () => dispatch(actions.starsActions.FETCH_STARS)
22 | // }
23 | // }
24 |
25 | export default connect(mapStateToProps, propsMapping)(<%= pascalEntityName %>)
26 |
27 | // export default compose(
28 | // connect(mapStateToProps, propsMapping),
29 | // lifecycle({
30 | // componentDidMount: function() {
31 | // if (this.props.fetchBasic) {
32 | // this.props.fetchBasic()
33 | // }
34 | // }
35 | // })
36 | // )(<%= pascalEntityName %>)
37 |
--------------------------------------------------------------------------------
/src/__tests__/__snapshots__/shoryshots.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Storyshots App Wrapper should Render 1`] = `
4 |
7 |
10 |

15 |
16 | Welcome to React
17 |
18 |
19 |
20 | `;
21 |
22 | exports[`Storyshots DisplayStars with text 1`] = `
23 |
24 |
25 | Things!
26 |
27 |
33 |
39 |
40 | `;
41 |
42 | exports[`Storyshots DisplayStarsContainer with stars 1`] = `
43 |
44 |
45 | 0
46 | Things!
47 |
48 |
54 |
60 |
61 | `;
62 |
63 | exports[`Storyshots Homepage should Render 1`] = `
64 |
65 |
66 | This is the Homepage
67 |
68 |
69 |
70 | 0
71 | Things!
72 |
73 |
79 |
85 |
86 |
87 | `;
88 |
--------------------------------------------------------------------------------
/src/routes/root/rootRoute.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { BrowserRouter, Route, Switch } from 'react-router-dom'
3 | import AppWrapper from '../../components/appWrapper/appWrapperComponent'
4 |
5 | if (module.hot) {
6 | module.hot.accept()
7 | }
8 | export default class Root extends Component {
9 | constructor () {
10 | super()
11 |
12 | this.views = {}
13 | }
14 |
15 | loadView (fileName) {
16 | if (this.views[fileName]) {
17 | return this.views[fileName]
18 | }
19 |
20 | new Promise(resolve =>
21 | require.ensure([], require => {
22 | switch (fileName) {
23 | case 'home':
24 | if (module.hot) {
25 | module.hot.accept('../homePage/homePageRoute', () => {
26 | require('../homePage/homePageRoute').default // eslint-disable-line
27 | this.forceUpdate()
28 | })
29 | }
30 | resolve(require('../homePage/homePageRoute').default)
31 | break
32 | default:
33 | break
34 | }
35 | })
36 | )
37 | .then(View => {
38 | this.views[fileName] =
39 | })
40 | .then(() => this.forceUpdate())
41 | .catch(err => {
42 | console.error(err)
43 | throw new Error(err)
44 | })
45 |
46 | return
47 | }
48 | render () {
49 | return (
50 |
51 |
52 |
53 | this.loadView('home')} />
54 |
55 |
56 |
57 | )
58 | }
59 | props: {
60 | store: Object
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
11 |
12 |
13 |
22 | React App
23 |
24 |
25 |
28 |
29 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/config/paths.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const path = require('path');
4 | const fs = require('fs');
5 | const url = require('url');
6 |
7 | // Make sure any symlinks in the project folder are resolved:
8 | // https://github.com/facebookincubator/create-react-app/issues/637
9 | const appDirectory = fs.realpathSync(process.cwd());
10 | const resolveApp = relativePath => path.resolve(appDirectory, relativePath);
11 |
12 | const envPublicUrl = process.env.PUBLIC_URL;
13 |
14 | function ensureSlash(path, needsSlash) {
15 | const hasSlash = path.endsWith('/');
16 | if (hasSlash && !needsSlash) {
17 | return path.substr(path, path.length - 1);
18 | } else if (!hasSlash && needsSlash) {
19 | return `${path}/`;
20 | } else {
21 | return path;
22 | }
23 | }
24 |
25 | const getPublicUrl = appPackageJson =>
26 | envPublicUrl || require(appPackageJson).homepage;
27 |
28 | // We use `PUBLIC_URL` environment variable or "homepage" field to infer
29 | // "public path" at which the app is served.
30 | // Webpack needs to know it to put the right