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

Redux and React Server Rendering

hui.liu
April 10, 2016

Redux and React Server Rendering

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')