Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Workshop 27: Isomorphic web apps with ReactJS

257 views

Published on

Workshop Isomorphic Web Apps with ReactJS:

- Universal web apps - Isomorphic
- Server Side Rendering (SSR) with ReactJS
- Server Side Rendering with Redux
- Server Side Rendering with React Router
- Server Side Rendering: server.js - Main Entry Point
- Server Side Rendering: server.js - HTML Template
- Client main entry point: client.js
- Webpack bundles
- Avoiding FOUC - Webpack ExtractTextPlugin
- Webpack code splitting
- React Router - Configuration with Plain Routes
- React Router - Dynamic Routing & WebPack
- Dynamic Routing with new Reducers
- Combining new Reducers - ReducerRegistry
- Data fetching before rendering
- React Router + Redux + Redial: Server Side
- React Router + Redux + Redial: provideHooks
- React Router + Redux + Redial: Client Side
- SEO friendly universal web apps - React-Helmet
- React-Helmet - Server Side Rendering

Presentado por ingeniero: Marc Torrent

Published in: Software
  • Be the first to comment

  • Be the first to like this

Workshop 27: Isomorphic web apps with ReactJS

  1. 1. Front End Workshops Isomorphic Web Apps With ReactJs Marc Torrent mtorrent@visual-engin.com
  2. 2. Isomorphic what?? First review ReactJS + Redux recap workshops
  3. 3. Universal web apps - Isomorphic Web Application Code (JS) Server - Routing and Data gathering (Rest API) ClientBrowser HTTP Request, a new Page With the data, inject it to our application code render() and obtain valid HTML HTTP Response with HTML, Web Application Code and JSON Data Web Application Code (JS) Request Data, AJAX or Web sockets → JSON Routing Isomorphic: the Client and the Server share the same code for routing, data gathering and rendering.
  4. 4. HTML Page Server Side Rendering (SSR) with ReactJS react-dom/server renderToString(ReactElement) <MyReactComponent {...props} /> HTML + ReactJS Virtual DOM ID’sReactDOM.render(App(window.APP_PROPS), document.getElementById('content') No re-rendering as there’s no difference in Virtual DOM !!!
  5. 5. Server Side Rendering with Redux react-dom/server const htmlEl = renderToString(ReactElement) const store = createStore(reducers); <Provider store={store}> <MyReactComponent {...props} /> </ Provider> No re-rendering as there’s no difference in Virtual DOM !!! const initialState = store.getState(); const html = ` <HTML> <body> <script>window.initialState = JSON.Stringify(initialState);</script> <div>${htmlEl}</div> </body></HTML>`; res.send(html); Client.jsx const initialState = window.initialState; const store = createStore(reducers, initialState); <Provider store={store}> <MyReactComponent {...props} /> </ Provider>
  6. 6. Server Side Rendering with React Router import { createMemoryHistory, RouterContext, match } from 'react-router'; Finds the route from the current location and returns the component to be rendered. Creates a Location object from the current url to be used by the match function. Renders the component tree for a given router state. import { createMemoryHistory, RouterContext, match } from 'react-router'; const history = createMemoryHistory(req.path); match({ routes, history }, (err, redirectLocation, renderProps) => { … const InitialComponent = (<RouterContext {...renderProps} />); … const componentHTML = renderToString(InitialComponent); ...
  7. 7. Server Side Rendering: server.js - Main Entry Point
  8. 8. Server Side Rendering: server.js - HTML Template
  9. 9. Client main entry point: client.js
  10. 10. Webpack bundles Entry point Output Loaders main: [ ‘client.js’ }, vendor: { ‘react’, ‘react-dom’, ‘react-router’, ‘redux’ } .../main.js .../vendor.js .../[chunk_id].chunk.js Babel_loader: ES6 → ES5 Style_loader | css_loader | sass_loader Plugins HotModule ReplacementPlugin() CommonsChunkPlugin() DefinePlugin() ProvidePlugin() ExtractTextPlugin() Module
  11. 11. Avoiding FOUC - Webpack ExtractTextPlugin
  12. 12. Webpack code splitting // polyfill webpack require.ensure if (typeof require.ensure !== 'function') require.ensure = (d, c) => c(require); … require.ensure([‘myModulesDependencies’], (require) => { const a = require('./ModuleA').default; const b = require('./ModuleB').default; }); Output .../main.js .../vendor.js .../1.chunk.js .../2.chunk.js
  13. 13. React Router - Configuration with Plain Routes <Route path=”/” component={App}> <IndexRoute component={Dashboard} /> <Route path=”about” component={About} /> <Route path=”inbox” component={Inbox} > <Route path=”messages/:id” component={Message} /> </Route> </Route> { path: ‘/’, component: App, indexRoute: { component: Dashboard }, childRoutes: [ { path: ‘about’, component: About }, { path: ‘inbox’, component: Inbox, childRoutes: [ { path: ‘messages/:id’, component: Message} ] } ] } from ... … to
  14. 14. React Router - Dynamic Routing & WebPack { path: ‘/’, component: App, indexRoute: { component: Dashboard }, getChildRoutes(location, cb) { require.ensure([], require => { cb(null, [ require(‘./About’).default, require(‘./Inbox’).default ]); }); } } import About from ‘./components/About’; { path: ‘about’, component: About } { path: ‘inbox’, component: Inbox, childRoutes: [ { path: ‘messages/:id’, component: Message} ] } About.js Inbox.js
  15. 15. Dynamic Routing with new Reducers At initialization we combine reducers to build the store... const rootReducer = combineReducers({authReducer, otherReducer}); const store = createStore(rootReduer, initialState, applyMiddleware(...middleware); … <Provider store={store}> <Router routes={routes} /> </Proider> … But what happens if we load a route containing a new reducer that is needed for the components of that new route???
  16. 16. Combining new Reducers - ReducerRegistry { path: ‘faq’, getComponents:(location, cb) { require.ensure([‘./components/FAQ’, ‘./reducer’], require => { const FAQ = require(‘./components/FAQ’).default; const faqReducer = require(‘./reducer’).default; store.replaceReducer(combineReducers({...existingRedu cers, faqReducer})); cb(null, FAQ); }); } } Now we have the initial reducers combined with the new ones and applied to the store via store.replaceReducer
  17. 17. Data fetching before rendering We need data to be accessible to Route Components before rendering those components. In SSR it’s not possible to fetch data in componentWillMount or componentDidMount: 1. componentDidMount is not available on server rendering. 2. componentWillMount is called immediately before rendering and changes in state won’t trigger a re-rendering → fetching data here doesn’t ensures that the render method will have all the data that is needed. ReactRouter → onEnter = Function to be called before rendering a Route’s Component
  18. 18. REDIAL → Data fetching before rendering HOC exposing three actions to take BEFORE & AFTER rendering & only CLIENT SIDE.
  19. 19. React Router + Redux + Redial: Server Side 1. Call trigger function which is an action creator that returns a Promise 2. State is update through usual Redux cycle 3. Render the vurrent Route with the current state 4. Get the state and make it available to the client
  20. 20. React Router + Redux + Redial: provideHooks FAQ-Component.js FAQ-Actions.js
  21. 21. React Router + Redux + Redial: Client Side 1. Listen to navigation events: browserHistory.listen() 2. Match routes to get the component 3. Trigger fetch on the component 4. Render the Component
  22. 22. Bonus Track
  23. 23. SEO friendly universal web apps - React-Helmet Isomorphic Web Apps is intended to improve SEO… .... we need something to manage our meta tags !!!! React Helmet is the solution for managing the meta tags of a Route Component
  24. 24. React-Helmet - Server Side Rendering const head = Helmet.rewind(); head.title.toString()
  25. 25. Thank you!

×