0

react-redux-universal-hot-example имеет универсальный маршрутизатор, см. universalRouter, client.js, server.js. Я хотел бы создать немного улучшенную версию, которая может отображать страницу с ошибкой, если действие API возвратило ошибку. Также я использую react-router 2 в отличие от того, что использовалось в RRUHE.Как реализовать универсальный маршрутизатор с реактивным маршрутизатором v2

Моя проблема заключается в том, что когда я нажимаю ссылку, переход никогда не происходит, и listenBefore никогда не вызывается на клиенте.

Некоторые части моего кода:

universalRouter.js:

import React     from 'react'; 
import { 
    match, 
    RouterContext, 
    Router 
}        from 'react-router'; 
import { Provider }   from 'react-redux'; 

import fetchComponentData from './fetchComponentData'; 

export default function universalRouter(routes, location, store) { 
    return new Promise((resolve, reject) => { 
    rematch(routes, location, store, resolve, reject); 
    }); 
} 

function rematch(routes, location, store, resolve, reject, rematched = false) { 
    match({routes, location}, (error, redirectLocation, renderProps) => { 
    if (error) { 
     return reject(error); 
    } 

    if (redirectLocation) { 
     return resolve({ 
     redirectLocation 
     }); 
    } 

    fetchComponentData(store, renderProps.components, renderProps.params) 
     .then(resolveWithComponent, (error) => { 
     if (!rematched && error.status) { 
      rematch(routes, getErrorPagePath(error), store, resolve, reject, true); 
     } else { 
      reject(error); 
     } 
     }); 

    function resolveWithComponent() { 
     const component = (
     <Provider store={store}> 
      <RouterContext {...renderProps}/> 
     </Provider> 
    ); 
     resolve({component, matchedRoutes: renderProps.routes}) 
    } 
    }); 
} 

// TODO Implement getErrorPagePath, for now return '/404' 
function getErrorPagePath(error) { 
    return '/404'; 
} 

client.js:

... 
const renderApp = (location) => { 
    return universalRouter(routes, location, store) 
    .then(({component}) => { 
     render(component, document.getElementById('react-view')); 
    }, (error) => { 
     // TODO Print error only in a dev mode. 
     console.error(error); 
    }); 
}; 

history.listenBefore((location, callback) => { 
    console.log('this message is never printed to the console'); 
    renderApp(location) 
    .then(callback); 
}); 

renderApp(pathname + search); 

server.js:

... 
universalRouter(routes, req.url, store) 
    .then(({component, matchedRoutes}) => { 
     const componentHTML = renderToString(component); 
     const initialState = store.getState(); 
     const html = ` 
     <!DOCTYPE html> 
     <html> 
     <head> 
      <meta charset="utf-8"> 
      <link rel="shortcut icon" href="/favicon.ico"> 
      <title>Redux Demo</title> 
      <script> 
      window.__INITIAL_STATE__ = ${JSON.stringify(initialState)}; 
      </script> 
     </head> 
     <body> 
      <div id="react-view">${componentHTML}</div> 
      <script type="application/javascript" src="/dist/bundle.js"></script> 
     </body> 
     </html> 
     `; 
     res.status(getStatus(matchedRoutes)).send(html); 
    }, (error) => { 
     res.sendStatus(500); 
     console.error(error) 
    }); 

function getStatus(routes) { 
    return routes.reduce((prev, curr) => curr.status || prev) || 200; 
} 

ответ

0

Fixed это путем предоставления объекта истории в match:

client.js:

return universalRouter(routes, location, store, history) 

universalRouter.js:

... 
export default function universalRouter(routes, location, store, history) { 
    return new Promise((resolve, reject) => { 
    rematch(routes, location, store, history, resolve, reject); 
    }); 
} 

function rematch(routes, location, store, history, resolve, reject, rematched = false) { 
    match({routes, location, history}, (error, redirectLocation, renderProps) => { 
... 

Если кто-то заинтересован в универсальном маршрутизатор, посмотрите на this gist и this comment on github..