From 80197eff76a1784eb29120fd7e8817b1e56b88a7 Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Tue, 1 Sep 2015 02:17:25 +0300 Subject: [PATCH] Change examples to explicitly use replaceReducer() for hot reloading --- .../async/containers/{AsyncApp.js => App.js} | 6 ++-- examples/async/containers/Root.js | 16 --------- examples/async/index.js | 11 ++++-- examples/async/store/configureStore.js | 12 ++++++- .../containers/{CounterApp.js => App.js} | 0 examples/counter/containers/Root.js | 16 --------- examples/counter/index.js | 10 ++++-- examples/counter/store/configureStore.js | 14 ++++++-- .../{CounterApp.spec.js => App.spec.js} | 4 +-- examples/real-world/containers/Root.js | 34 ------------------- examples/real-world/index.js | 23 +++++++++++-- examples/real-world/reducers/index.js | 14 ++++++-- examples/real-world/store/configureStore.js | 18 +++++++--- .../todomvc/containers/{TodoApp.js => App.js} | 8 ++--- examples/todomvc/containers/Root.js | 17 ---------- examples/todomvc/index.js | 10 ++++-- examples/todomvc/store/configureStore.js | 16 +++++++++ examples/universal/store/configureStore.js | 12 ++++++- 18 files changed, 128 insertions(+), 113 deletions(-) rename examples/async/containers/{AsyncApp.js => App.js} (95%) delete mode 100644 examples/async/containers/Root.js rename examples/counter/containers/{CounterApp.js => App.js} (100%) delete mode 100644 examples/counter/containers/Root.js rename examples/counter/test/containers/{CounterApp.spec.js => App.spec.js} (95%) delete mode 100644 examples/real-world/containers/Root.js rename examples/todomvc/containers/{TodoApp.js => App.js} (84%) delete mode 100644 examples/todomvc/containers/Root.js create mode 100644 examples/todomvc/store/configureStore.js diff --git a/examples/async/containers/AsyncApp.js b/examples/async/containers/App.js similarity index 95% rename from examples/async/containers/AsyncApp.js rename to examples/async/containers/App.js index cfeeb3f4dd..75cf1de1c5 100644 --- a/examples/async/containers/AsyncApp.js +++ b/examples/async/containers/App.js @@ -4,7 +4,7 @@ import { selectReddit, fetchPostsIfNeeded, invalidateReddit } from '../actions'; import Picker from '../components/Picker'; import Posts from '../components/Posts'; -class AsyncApp extends Component { +class App extends Component { constructor(props) { super(props); this.handleChange = this.handleChange.bind(this); @@ -72,7 +72,7 @@ class AsyncApp extends Component { } } -AsyncApp.propTypes = { +App.propTypes = { selectedReddit: PropTypes.string.isRequired, posts: PropTypes.array.isRequired, isFetching: PropTypes.bool.isRequired, @@ -99,4 +99,4 @@ function mapStateToProps(state) { }; } -export default connect(mapStateToProps)(AsyncApp); +export default connect(mapStateToProps)(App); diff --git a/examples/async/containers/Root.js b/examples/async/containers/Root.js deleted file mode 100644 index 50c34afe76..0000000000 --- a/examples/async/containers/Root.js +++ /dev/null @@ -1,16 +0,0 @@ -import React, { Component } from 'react'; -import { Provider } from 'react-redux'; -import configureStore from '../store/configureStore'; -import AsyncApp from './AsyncApp'; - -const store = configureStore(); - -export default class Root extends Component { - render() { - return ( - - {() => } - - ); - } -} diff --git a/examples/async/index.js b/examples/async/index.js index 3d60c6a5c5..0d564f8690 100644 --- a/examples/async/index.js +++ b/examples/async/index.js @@ -1,9 +1,14 @@ import 'babel-core/polyfill'; - import React from 'react'; -import Root from './containers/Root'; +import { Provider } from 'react-redux'; +import App from './containers/App'; +import configureStore from './store/configureStore'; + +const store = configureStore(); React.render( - , + + {() => } + , document.getElementById('root') ); diff --git a/examples/async/store/configureStore.js b/examples/async/store/configureStore.js index 55c17daefe..bef5a6f3e4 100644 --- a/examples/async/store/configureStore.js +++ b/examples/async/store/configureStore.js @@ -9,5 +9,15 @@ const createStoreWithMiddleware = applyMiddleware( )(createStore); export default function configureStore(initialState) { - return createStoreWithMiddleware(rootReducer, initialState); + const store = createStoreWithMiddleware(rootReducer, initialState); + + if (module.hot) { + // Enable Webpack hot module replacement for reducers + module.hot.accept('../reducers', () => { + const nextRootReducer = require('../reducers'); + store.replaceReducer(nextRootReducer); + }); + } + + return store; } diff --git a/examples/counter/containers/CounterApp.js b/examples/counter/containers/App.js similarity index 100% rename from examples/counter/containers/CounterApp.js rename to examples/counter/containers/App.js diff --git a/examples/counter/containers/Root.js b/examples/counter/containers/Root.js deleted file mode 100644 index f86fa26aa4..0000000000 --- a/examples/counter/containers/Root.js +++ /dev/null @@ -1,16 +0,0 @@ -import React, { Component } from 'react'; -import { Provider } from 'react-redux'; -import CounterApp from './CounterApp'; -import configureStore from '../store/configureStore'; - -const store = configureStore(); - -export default class Root extends Component { - render() { - return ( - - {() => } - - ); - } -} diff --git a/examples/counter/index.js b/examples/counter/index.js index 6f19211f76..69ddf88caf 100644 --- a/examples/counter/index.js +++ b/examples/counter/index.js @@ -1,7 +1,13 @@ import React from 'react'; -import Root from './containers/Root'; +import { Provider } from 'react-redux'; +import App from './containers/App'; +import configureStore from './store/configureStore'; + +const store = configureStore(); React.render( - , + + {() => } + , document.getElementById('root') ); diff --git a/examples/counter/store/configureStore.js b/examples/counter/store/configureStore.js index b3d4a9bd6b..dfd4dc57a1 100644 --- a/examples/counter/store/configureStore.js +++ b/examples/counter/store/configureStore.js @@ -1,11 +1,21 @@ import { createStore, applyMiddleware } from 'redux'; import thunk from 'redux-thunk'; -import rootReducer from '../reducers'; +import reducer from '../reducers'; const createStoreWithMiddleware = applyMiddleware( thunk )(createStore); export default function configureStore(initialState) { - return createStoreWithMiddleware(rootReducer, initialState); + const store = createStoreWithMiddleware(reducer, initialState); + + if (module.hot) { + // Enable Webpack hot module replacement for reducers + module.hot.accept('../reducers', () => { + const nextReducer = require('../reducers'); + store.replaceReducer(nextReducer); + }); + } + + return store; } diff --git a/examples/counter/test/containers/CounterApp.spec.js b/examples/counter/test/containers/App.spec.js similarity index 95% rename from examples/counter/test/containers/CounterApp.spec.js rename to examples/counter/test/containers/App.spec.js index 71fa71ed41..5496d0ba10 100644 --- a/examples/counter/test/containers/CounterApp.spec.js +++ b/examples/counter/test/containers/App.spec.js @@ -2,7 +2,7 @@ import expect from 'expect'; import jsdomReact from '../jsdomReact'; import React from 'react/addons'; import { Provider } from 'react-redux'; -import CounterApp from '../../containers/CounterApp'; +import App from '../../containers/App'; import configureStore from '../../store/configureStore'; const { TestUtils } = React.addons; @@ -11,7 +11,7 @@ function setup(initialState) { const store = configureStore(initialState); const app = TestUtils.renderIntoDocument( - {() => } + {() => } ); return { diff --git a/examples/real-world/containers/Root.js b/examples/real-world/containers/Root.js deleted file mode 100644 index ab0120dd7c..0000000000 --- a/examples/real-world/containers/Root.js +++ /dev/null @@ -1,34 +0,0 @@ -import React, { Component, PropTypes } from 'react'; -import { Provider } from 'react-redux'; -import { Router, Route } from 'react-router'; -import configureStore from '../store/configureStore'; -import App from './App'; -import UserPage from './UserPage'; -import RepoPage from './RepoPage'; - -const store = configureStore(); - -export default class Root extends Component { - render() { - return ( -
- - {() => - - - - - - - } - -
- ); - } -} - -Root.propTypes = { - history: PropTypes.object.isRequired, -}; diff --git a/examples/real-world/index.js b/examples/real-world/index.js index 7127e34fa7..ef6d1f2cf3 100644 --- a/examples/real-world/index.js +++ b/examples/real-world/index.js @@ -1,9 +1,28 @@ import 'babel-core/polyfill'; import React from 'react'; -import Root from './containers/Root'; import BrowserHistory from 'react-router/lib/BrowserHistory'; +import { Provider } from 'react-redux'; +import { Router, Route } from 'react-router'; +import configureStore from './store/configureStore'; +import App from './containers/App'; +import UserPage from './containers/UserPage'; +import RepoPage from './containers/RepoPage'; + +const history = new BrowserHistory(); +const store = configureStore(); React.render( - , + + {() => + + + + + + + } + , document.getElementById('root') ); diff --git a/examples/real-world/reducers/index.js b/examples/real-world/reducers/index.js index f5bd315a5a..994f215e8d 100644 --- a/examples/real-world/reducers/index.js +++ b/examples/real-world/reducers/index.js @@ -4,7 +4,7 @@ import paginate from './paginate'; import { combineReducers } from 'redux'; // Updates an entity cache in response to any action with response.entities. -export function entities(state = { users: {}, repos: {} }, action) { +function entities(state = { users: {}, repos: {} }, action) { if (action.response && action.response.entities) { return merge({}, state, action.response.entities); } @@ -13,7 +13,7 @@ export function entities(state = { users: {}, repos: {} }, action) { } // Updates error message to notify about the failed fetches. -export function errorMessage(state = null, action) { +function errorMessage(state = null, action) { const { type, error } = action; if (type === ActionTypes.RESET_ERROR_MESSAGE) { @@ -26,7 +26,7 @@ export function errorMessage(state = null, action) { } // Updates the pagination data for different actions. -export const pagination = combineReducers({ +const pagination = combineReducers({ starredByUser: paginate({ mapActionToKey: action => action.login, types: [ @@ -44,3 +44,11 @@ export const pagination = combineReducers({ ] }) }); + +const rootReducer = combineReducers({ + entities, + pagination, + errorMessage +}); + +export default rootReducer; diff --git a/examples/real-world/store/configureStore.js b/examples/real-world/store/configureStore.js index c8b39095c9..5c863d5df0 100644 --- a/examples/real-world/store/configureStore.js +++ b/examples/real-world/store/configureStore.js @@ -1,17 +1,25 @@ -import { createStore, applyMiddleware, combineReducers } from 'redux'; +import { createStore, applyMiddleware } from 'redux'; import thunkMiddleware from 'redux-thunk'; import apiMiddleware from '../middleware/api'; import loggerMiddleware from 'redux-logger'; -import * as reducers from '../reducers'; +import rootReducer from '../reducers'; -const reducer = combineReducers(reducers); const createStoreWithMiddleware = applyMiddleware( thunkMiddleware, apiMiddleware, loggerMiddleware )(createStore); -// Creates a preconfigured store for this example. export default function configureStore(initialState) { - return createStoreWithMiddleware(reducer, initialState); + const store = createStoreWithMiddleware(rootReducer, initialState); + + if (module.hot) { + // Enable Webpack hot module replacement for reducers + module.hot.accept('../reducers', () => { + const nextRootReducer = require('../reducers'); + store.replaceReducer(nextRootReducer); + }); + } + + return store; } diff --git a/examples/todomvc/containers/TodoApp.js b/examples/todomvc/containers/App.js similarity index 84% rename from examples/todomvc/containers/TodoApp.js rename to examples/todomvc/containers/App.js index 0bad6919cb..14cd353478 100644 --- a/examples/todomvc/containers/TodoApp.js +++ b/examples/todomvc/containers/App.js @@ -5,7 +5,7 @@ import Header from '../components/Header'; import MainSection from '../components/MainSection'; import * as TodoActions from '../actions/todos'; -class TodoApp extends Component { +class App extends Component { render() { const { todos, dispatch } = this.props; const actions = bindActionCreators(TodoActions, dispatch); @@ -19,15 +19,15 @@ class TodoApp extends Component { } } -TodoApp.propTypes = { +App.propTypes = { todos: PropTypes.array.isRequired, dispatch: PropTypes.func.isRequired }; -function select(state) { +function mapStateToProps(state) { return { todos: state.todos }; } -export default connect(select)(TodoApp); +export default connect(mapStateToProps)(App); diff --git a/examples/todomvc/containers/Root.js b/examples/todomvc/containers/Root.js deleted file mode 100644 index 2bea989b3f..0000000000 --- a/examples/todomvc/containers/Root.js +++ /dev/null @@ -1,17 +0,0 @@ -import React, { Component } from 'react'; -import TodoApp from './TodoApp'; -import { createStore } from 'redux'; -import { Provider } from 'react-redux'; -import rootReducer from '../reducers'; - -const store = createStore(rootReducer); - -export default class Root extends Component { - render() { - return ( - - {() => } - - ); - } -} diff --git a/examples/todomvc/index.js b/examples/todomvc/index.js index 3c3a45b39c..2a0b4c14c4 100644 --- a/examples/todomvc/index.js +++ b/examples/todomvc/index.js @@ -1,10 +1,16 @@ import 'babel-core/polyfill'; import React from 'react'; -import Root from './containers/Root'; +import { Provider } from 'react-redux'; +import App from './containers/App'; +import configureStore from './store/configureStore'; import 'todomvc-app-css/index.css'; +const store = configureStore(); + React.render( - , + + {() => } + , document.getElementById('root') ); diff --git a/examples/todomvc/store/configureStore.js b/examples/todomvc/store/configureStore.js new file mode 100644 index 0000000000..f9588c43dd --- /dev/null +++ b/examples/todomvc/store/configureStore.js @@ -0,0 +1,16 @@ +import { createStore } from 'redux'; +import rootReducer from '../reducers'; + +export default function configureStore(initialState) { + const store = createStore(rootReducer, initialState); + + if (module.hot) { + // Enable Webpack hot module replacement for reducers + module.hot.accept('../reducers', () => { + const nextReducer = require('../reducers'); + store.replaceReducer(nextReducer); + }); + } + + return store; +} diff --git a/examples/universal/store/configureStore.js b/examples/universal/store/configureStore.js index b3d4a9bd6b..d45fdcbdb2 100644 --- a/examples/universal/store/configureStore.js +++ b/examples/universal/store/configureStore.js @@ -7,5 +7,15 @@ const createStoreWithMiddleware = applyMiddleware( )(createStore); export default function configureStore(initialState) { - return createStoreWithMiddleware(rootReducer, initialState); + const store = createStoreWithMiddleware(rootReducer, initialState); + + if (module.hot) { + // Enable Webpack hot module replacement for reducers + module.hot.accept('../reducers', () => { + const nextRootReducer = require('../reducers'); + store.replaceReducer(nextRootReducer); + }); + } + + return store; }