React Router/Redux-动态同构路由

React-Router/Redux - Dynamic Isomorphic Routes

本文关键字:同构 路由 动态 Redux- Router React      更新时间:2023-09-26

我在github工作erikras/areact-redux通用热门示例存储库。
我正在努力使路线具有动态性,以恰当地反映真实世界的场景。

  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. 服务器的同构路由config.server.js也调用getRoutes(store)与客户端进行路由匹配:

        match({history, routes: getRoutes(store), location: req.originalUrl},    
        (error, redirectLocation, renderProps) => {
         .....
      });
    
  3. shareddynamic 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>
       )
      };
    

在第二次"复飞"时,dynRoutes的数组确实接收到routes集合,return语句不会重新处理,并且组件被确定为具有零长度,并且回调值被忽略。

我知道这不是一个React组件,它提供了用新的返回值重新加载的好处,但是,有人知道我如何让这个JavaScript函数用回调值返回吗?

谢谢。

简而言之,我不仅需要动态路由.共享.js异步,
还有任何其他函数调用,来自服务器和;客户端

我用过动态路由上承诺。shared.js,在服务器/客户端调用到动态路由.shared.js。

我没有费心将数据放入JSON中,您几乎可以自己解决这个问题。

1.动态路由.共享.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.同构路由.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();
      });
    };

我希望这能帮助任何想要使同构路由动态化的人
让美国再次伟大!

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

您需要将store.dispatch(loadNav())调用与组件呈现分离,并对代码进行结构化,以便promise处理程序使用setState或再次调用根ReactDOM.render触发组件内部的重新呈现。