React-Router/Redux - 动态同构路由

React-Router/Redux - Dynamic Isomorphic Routes

I'm working off of github's erikras/react-redux-universal-hot-example repository.
I am trying to make the routes dynamic to aptly reflect a real world scenario.

  1. client/entry.js 页面调用共享模块函数 'getRoutes' 传递存储参数。

    const component = (
      <Router render={(props) =>
                <ReduxAsyncConnect {...props} helpers={{client}} 
                   filter={item => !item.deferred} />
             } history={history}>
        // where the routes are populated
        {getRoutes(store)} // <-- function call
      </Router>
    

    );

  2. 服务器的同构-routes.config.server.js也调用getRoutes(store)与客户端进行路由匹配:

        match({history, routes: getRoutes(store), location: req.originalUrl},    
        (error, redirectLocation, renderProps) => {
         .....
      });
    
  3. 共享的 dynamic-routes.shared.js 页面是一个 reg JavaScript 函数 'getRoutes':

     export default (store) => {
        ......
    
      let dynRoutes= [];
      store.dispatch(loadNav()).then(result => {
      dynRoutes = result;
      })
    
    return (
     <Route path="/" component={App}>
       { /* Home (main) route */ }
       <IndexRoute component={Home}/>
        { /* Get dynamic routes from database */ }
        { dynRoutes.length > 0 ?
         <DynamicRoutes dynRoutes={dynRoutes} />
         : ''}    
        { /* Catch all route */ }
        <Route path="*" component={NotFound} status={404} />
       </Route>
       )
      };
    

而在第二个 'go around' 上,dynRoutes 的数组确实接收到路由集合,return 语句将不会重新处理并且 组件被确定为零长度,回调值将被忽略。

我知道这不是一个提供重新加载新 return 值的好处的 React 组件,但是,有没有人知道我如何获得这个 JavaScript 函数return 与回调值?

谢谢。

标准解决方案是将 getRoutes 设置为一个真正的 React 组件,它遵循 React 组件生命周期,在这种情况下,您可以在回调 returns 时使用 this.setState({ dynRoutes })触发重新渲染。在其当前设置中,getRoutes 将永远无法强制 caller/parent 重新渲染。

您需要将 store.dispatch(loadNav()) 调用与组件呈现分开,并构建代码,以便承诺处理程序在具有 setState 层次结构更上层的组件内触发重新呈现,或再次调用根 ReactDOM.render

The short answer is I needed to make not only the dynamic-routes.shared.js asynchronous,
but also any other function calls, from both the server & client.

I used promises on the dynamic-routes.shared.js, and async/await on the server/client calls to dynamic-routes.shared.js.

I didn't bother throwing the data into a JSON, you can pretty much figure that out yourself.

1.动态-routes.shared.js

      function routesWithStore(store) {
       return new Promise(function(resolve, reject) {
       // you can use something like this to actually have these
       // routes in a database
       // let dynRoutes= [];
       // store.dispatch(loadNav()).then(result => {
       // dynRoutes = result;
       // }) 
       // resolve(dynRoutes.map(route => {
       //   ..... your code here .....
       // }))
         resolve(
           {
             path: '',
             component: App,
             childRoutes: [
               {path: '/', component: Home},
               {path: 'home', component: Home},
               {path: 'about', component: About},
               {path: '*', component: NotFound}
             ]
           }
         )
       });
     }

       function getRoutes(store) {      
        return(
          routesWithStore(store)
         )
       }

     exports.getRoutes = getRoutes;

2.client/entry.js

    // async call to dynamic-routes.shared.js ////////
    async function main() {
      try {
        const result = await getRoutes(store);
        processRoutes(result);
      } catch(err) {
        console.log(err.message)
      }
    }

    function processRoutes(result) {
      const component = (
        <Router render={(props) =>
            <ReduxAsyncConnect {...props} helpers={{client}} 
              filter={item => !item.deferred} />
                } history={history}>
                {result} <------------- client value from dynamic-routes.shared.js
              </Router>
            );

      ReactDOM.render(
        <Provider store={store} key="provider">
          {component}
        </Provider>,
         document.querySelector('#root');
         );

_

  if (process.env.NODE_ENV !== 'production') {
        window.React = React; // enable debugger

      if (!dest || !dest.firstChild 
                || !dest.firstChild.attributes 
                || !dest.firstChild.attributes['data-react-checksum']) {
      console.error
       ('Server-side React render was discarded. ' + 
        'Make sure that your initial render does not contain any client-side code.');
       }
     }

      if (__DEVTOOLS__ && !window.devToolsExtension) {
       const DevTools = require('shared/redux/dev-tools/dev-tools.redux.shared');
       ReactDOM.render(
        <Provider store={store} key="provider">
           <div>
            {component}
            <DevTools />
           </div>
        </Provider>,
         document.querySelector('#root');
        );
      }
    }

   main();

3。同构-routes.config.server

     module.exports = (app) => {
      app.use((req, res) => {
        if (__DEVELOPMENT__) {
          // Do not cache webpack stats: the script file would change since
          // hot module replacement is enabled in the development env
          webpackIsomorphicTools.refresh();
        }
        const client = new ApiClient(req);
        const memoryHistory = createHistory(req.originalUrl);
        const store = createStore(memoryHistory, client);
        const history = syncHistoryWithStore(memoryHistory, store);

        function hydrateOnClient() {
          res.send('<!doctype html>\n' +
            ReactDOM.renderToString(

              <Html assets={webpackIsomorphicTools.assets()} 
                   store={store}/>));
        }

        if (__DISABLE_SSR__) {
          hydrateOnClient();
          return;
        }

_

        // Async call to dynamic-routes.shared.js ////////

        async function main() {
          try {
            const routesResult = await getRoutes(store);
            // pass routesResult below
            match({history, routes: routesResult, location: req.originalUrl}, 
                 (error, redirectLocation, renderProps) => {
              if (redirectLocation) {
                res.redirect(redirectLocation.pathname + redirectLocation.search);
              } else if (error) {
                console.error('ROUTER ERROR:', pretty.render(error));
                res.status(500);
                hydrateOnClient();

_

              } else if (renderProps) {
                loadOnServer({...renderProps, store, helpers: {client}}).then(() => {
                  const component = (
                    <Provider store={store} key="provider">
                      <ReduxAsyncConnect {...renderProps} />
                    </Provider>
                  );

                  res.status(200);

                  global.navigator = {userAgent: req.headers['user-agent']};

                  res.send('<!doctype html>\n' +
                    ReactDOM.renderToString(
                         <Html assets={webpackIsomorphicTools.assets()}   
                          component={component} store={store}/>));
                });
              } else {
                res.status(404).send('Iso Routes Not Found ' + routeResult);
              }
            });

          } catch(error) {
            console.error(error);
          }
        }

        main();

      });
    };

我希望这对希望使同构路由动态化的任何人有所帮助。
让美国再次伟大!