Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Redux and React Server Rendering

Avatar for hui.liu hui.liu
April 10, 2016

Redux and React Server Rendering

Avatar for hui.liu

hui.liu

April 10, 2016
Tweet

More Decks by hui.liu

Other Decks in Technology

Transcript

  1. // Default function actionCreator() { return { type: 'ACTION_TYPE_CONSTANT', payload:

    'payload' } } Action { type: ‘TYPE_CONSTANT’, payload: payload } thunk middleware promise middleware // Thunk function actionCreator() { return (dispatch) => { dispatch({ type: 'ACTION_TYPE_CONSTANT', payload: 'xx' }) // Async operation } } // Promise function actionCreator() { return { type: 'ACTION_TYPE_CONSTANT', payload: Promise.resolve(‘payload') } }
  2. Reducer function reducer(state, action) { switch(action.type) { case 'ACTION_TYPE_CONSTANT': //

    Update state return newState; default: return state; } } (previousState, action) => newState
  3. Store import { createStore } from 'redux' import rootReducer from

    './reducers' let store = createStore(rootReducer) ӞӻଫአํӬՐํӞӻ Store // store.getState() ᬬࢧ State ᇫா໅ // store.dispatch(action) ᥶ݎ reducer ๅෛ State // store.subscribe(listener) ፊލ State ๅෛ
  4. Data Flow • action ฎӞӻ۱ތ { type, payload } ጱ੒᨝

    • reducer ڍහ᭗ᬦ store.dispatch(action) ᥶ݎ • reducer ڍහളݑ (state, action) ӷӻ݇හ • reducer ڍහڣෙ action.type ᆐݸ॒ቘ੒ଫጱ action.payload හഝ๶ๅ ෛᇫா໅҅ᬬࢧӞӻෛጱ state • store.subscribe(listener) ፊލ state ๅෛ
  5. react-redux // index.js import { render } from 'react-dom'; import

    { Provider } from 'react-redux'; import App from './app'; render( <Provider store={store}> <App /> </Provider>, document.getElementById('root') ); // app.js class App extends Component { ... } export default connect( mapStateToProps, mapDispatchProps )(App); <Provider /> connect const mapStateToProps = (state) => ({ propA: stateA, … }) const mapDispatchProps = (dispatch) => ({ propDoAction: (args) => dispatch(actionCreator(args)) ... })
  6. Server Rendering import { renderToString } from 'react-dom/server'; function renderFullPage(html,

    initialState) { return ` <!DOCTYPE html> ... <div id=“root”>${html}</div> <script> window.__INITIAL_STATE__ = ${JSON.stringify(initialState)}; </script> ... ` } app.use((req, res) => { store.dispatch(fetchActionCreator()) .then(_ => { const html = renderToString( <Provider store={store}> <App /> </Provider> ); res.end(renderFullPage(html, store.getState())); }); }); }); Browser SPA const initialState = window.__INITIAL_STATE__; const store = createStore(rootReducer, initialState); Browser SPA componentDidMount() { store.dispatch(fetchActionCreator()); }
  7. react-router (Client) import { Route, IndexRoute } from 'react-router'; const

    Container = (props) => <div>{props.children}</div>; const routes = ( <Route path="/" component={Container} > <IndexRoute component={App} /> <Route path=“path/:other” component={Other} /> </Route> ); export default routes;
  8. react-router (Server) import { renderToString } from 'react-dom/server' import {

    match, RouterContext } from 'react-router' import routes from './routes' function renderFullPage(html, initialState) { … } app.use((req, res) => { match({ routes, location: req.url }, (error, redirectLocation, renderProps) => { if (error) { res.status(500).send(error.message) } else if (redirectLocation) { res.redirect(302, redirectLocation.pathname + redirectLocation.search) } else if (renderProps) { store.dispatch(fetchActionCreator()) .then(_ => { const html = renderToString( <Provider store={store}> <RoutingContext {...renderProps} /> </Provider> ); res.end(renderFullPage(html, store.getState())); }); } else { res.status(404).send('Not found') } }) }) match({ routes, location: req.url }, (error, redirectLocation, renderProps) => { import routes from './routes' <RoutingContext {...renderProps} /> Browser SPA <Route path="/" component={Container} > <IndexRoute component={App} /> <Route path=“path/:other” component={Other} /> </Route>
  9. – reactjs/react-router “Knowing what code should run on the server

    and on the client is important to using React in a universal app.”
  10. Client or Server • componentDidMount()
 Invoked once, only on the

    client (not on the server) • <Link /> or <a /> • isomorphic-fetch
  11. Server Consistent function renderFullPage(html, initialState) { return ` <!DOCTYPE html>

    ... <div id=“root”>${html}</div> ... ` } Browser document.addEventListener('DOMContentLoaded', () => { render(<App />, document.getElementById('root')); }); <div id=“root”></div> <div id=“root”>${html}</div> document.getElementById('root')