Posted by
Mike Wolf
React Hot Module Reloading
I'm thinking of getting back into doing some coding. If I do, I'll need to recover some technology that I once knew. Here are some tidbits to not get lost.
WebPack Hot Module Reloading
From here
And here's a problem with Redux (not copied)
And it looks like ReactHotLoader now does the right stuff, including living peacefully inside create-react-app
WebPack Hot Module Reloading
From here
And here's a problem with Redux (not copied)
And it looks like ReactHotLoader now does the right stuff, including living peacefully inside create-react-app
| import React from "react"; | |
| import ReactDOM from "react-dom"; | |
| import configureStore from "./store/configureStore"; | |
| const store = configureStore(); | |
| const rootEl = document.getElementById("root"); | |
| let render = () => { | |
| const RootAppComponent = require("containers/RootAppComponent").default; | |
| ReactDOM.render( | |
| <RootAppComponent store={store} />, | |
| rootEl | |
| ); | |
| }; | |
| if(module.hot) { | |
| // Support hot reloading of components | |
| // and display an overlay for runtime errors | |
| const renderApp = render; | |
| const renderError = (error) => { | |
| const RedBox = require("redbox-react"); | |
| ReactDOM.render( | |
| <RedBox error={error} />, | |
| rootEl, | |
| ); | |
| }; | |
| render = () => { | |
| try { | |
| renderApp(); | |
| } | |
| catch(error) { | |
| renderError(error); | |
| } | |
| }; | |
| module.hot.accept("./containers/Root", () => { | |
| setTimeout(render); | |
| }); | |
| } | |
| render(); |
| import {createStore, applyMiddleware, compose} from "redux"; | |
| import rootReducer from "../reducers/rootReducer"; | |
| import thunk from "redux-thunk"; | |
| import createSagaMiddleware from 'redux-saga'; | |
| import SagaManager from "sagas/SagaManager"; | |
| /** | |
| * Based on the current environment variable, we need to make sure | |
| * to exclude any DevTools-related code from the production builds. | |
| * The code is envify'd - using 'DefinePlugin' in Webpack. | |
| */ | |
| const sagaMiddleware = createSagaMiddleware(); | |
| const middlewares = [thunk, sagaMiddleware]; | |
| const storeEnhancers = []; | |
| if(__DEV__) { | |
| const DevTools = require("../containers/DevTools").default; | |
| // If the user has the "Redux DevTools" browser extension installed, use that. | |
| // Otherwise, hook up the in-page DevTools UI component. | |
| const debugEnhancer = window.devToolsExtension ? window.devToolsExtension() : DevTools.instrument(); | |
| storeEnhancers.push(debugEnhancer); | |
| } | |
| const middlewareEnhancer = applyMiddleware(...middlewares); | |
| storeEnhancers.unshift(middlewareEnhancer); | |
| export default function configureStore(initialState) { | |
| const store = createStore( | |
| rootReducer, | |
| initialState, | |
| compose(...storeEnhancers) | |
| ); | |
| // run sagas | |
| SagaManager.startSagas(sagaMiddleware); | |
| if(__DEV__) { | |
| // Hot reload reducers (requires Webpack or Browserify HMR to be enabled) | |
| if(module.hot) { | |
| module.hot.accept("../reducers/rootReducer", () => | |
| store.replaceReducer(require("../reducers/rootReducer").default) | |
| ); | |
| module.hot.accept('../sagas/SagaManager', () => { | |
| SagaManager.cancelSagas(store); | |
| require('../sagas/SagaManager').default.startSagas(sagaMiddleware); | |
| }); | |
| } | |
| } | |
| return store; | |
| } |
| // Borrowed from https://gist.github.com/hoschi/6538249ad079116840825e20c48f1690 | |
| // Note that reloading sagas has several issues/caveats to be aware of. | |
| // See https://github.com/yelouafi/redux-saga/issues/22#issuecomment-218737951 for discussion. | |
| import { take, fork, cancel } from 'redux-saga/effects'; | |
| import rootSaga from "./rootSaga"; | |
| const sagas = [rootSaga]; | |
| export const CANCEL_SAGAS_HMR = 'CANCEL_SAGAS_HMR'; | |
| function createAbortableSaga (saga) { | |
| if (process.env.NODE_ENV === 'development') { | |
| return function* main () { | |
| const sagaTask = yield fork(saga); | |
| yield take(CANCEL_SAGAS_HMR); | |
| yield cancel(sagaTask); | |
| }; | |
| } else { | |
| return saga; | |
| } | |
| } | |
| const SagaManager = { | |
| startSagas(sagaMiddleware) { | |
| sagas.map(createAbortableSaga).forEach((saga) => sagaMiddleware.run(saga)); | |
| }, | |
| cancelSagas(store) { | |
| store.dispatch({ | |
| type: CANCEL_SAGAS_HMR | |
| }); | |
| } | |
| }; | |
| export default SagaManager; |
Comments
Post a Comment