NextJS:如何在根处处理多个动态路由

时间:2020-01-17 16:04:52

标签: express next.js

目标::我想实现github风格的路由,其中​​abcd中的github.com/abcd可以解析为用户个人资料页面或团队页面。

我目前有一个可以正常工作的版本(请参见下文)。不幸的是,在2条动态路线之间导航时,偶尔会出现白页闪烁。

我的服务器文件如下:

const express = require('express');
const next = require('next');
const { parse } = require('url');
const resolveRoute = require('./resolveRoute');

const port = parseInt(process.env.PORT, 10) || 3000;
const dev = process.env.NODE_ENV !== 'production';
const nextApp = next({
  dev,
});
const nextHandle = nextApp.getRequestHandler();

const STATIC_ROUTES = [
  '/about',
  '/news',
  '/static',
];

const DYNAMIC_ROUTE_MAP = {
  user: '/[user]',
  team: '/teams/[team]',
};

nextApp.prepare().then(() => {
  const server = express();

  server.get('*', async (req, res) => {
    // pass through next routes
    if (req.url.indexOf('/_next') === 0) {
      return nextHandle(req, res);
    }

    // pass through static routes
    if (
      req.url === '/' ||
      STATIC_ROUTES.map(route => req.url.indexOf(route) === 0).reduce(
        (prev, curr) => prev || curr,
      )
    ) {
      return nextHandle(req, res);
    }

    // try to resolve the route
    // if successful resolves to an object:
    // { type: 'user' | 'team' }
    const resolvedRoute = await resolveRoute(req.url);
    if (!resolvedRoute || !resolvedRoute.type) {
      console.error('? Unable to resolve route...');
      return nextHandle(req, res);
    }

    // set query
    const { pathname } = parse(req.url);
    const paths = pathname.split('/').filter(path => path.length > 0);
    const query = {
      [resolvedRoute.type]: paths.length > 0 ? paths[0] : null,
    };

    // render route
    return nextApp.render(
      req,
      res,
      DYNAMIC_ROUTE_MAP[resolvedRoute.type],
      query,
    );
  });

  server.listen(port, err => {
    if (err) throw err;
    console.log(`? Ready on http://localhost:${port}`);
  });
});

我想知道是否有更好的方法来解决这个问题,或者我是否需要离开NextJS。

1 个答案:

答案 0 :(得分:10)

Next.JS内置了动态路由,不需要您创建自定义server.js文件。如果要与Next.JS完全兼容,则应使用它的动态路由。

要在Next.JS中创建动态路由,您可以创建名称用方括号括起来的页面,例如/pages/[username].js。这将匹配您基础域上的所有路由,因此您可以设置您在github中提到的示例,例如http://yourwebsite.com/csbarneshttp://yourwebsite.com/anotherusername

在上面的示例中,您可以像使用任何查询字符串参数一样,从getInitialProps中的查询参数中获取Next.JS页面中的用户名:

static getInitialProps({query}) {
  console.log(query.username); // the param name is the part in [] in your filename
  return {query}; // you can now access this as this.props.query in your page
}

Next.JS总是在动态路由之前匹配静态路由,这意味着您的/pages/目录看起来像这样:

pages/index.js       -> (will match http://yourwebsite.com)
pages/about.js       -> (will match http://yourwebsite.com/about)
pages/contact.js     -> (will match http://yourwebsite.com/contact)
pages/[username].js  -> (will match http://yourwebsite.com/[anything_else])

多个细分

您可以在http://website.com/[username]/[repo]目录中使用多个分段动态路由,例如pages

pages/[username].js      -> (matches http://yourwebsite.com/[username])
pages/[username]/[repo]  -> (matches http://yourwebsite.com/[username]/[repo])

在这种情况下,您的查询对象将包含2个参数:{ username: ..., repo: ...}

路由“前缀”

如果愿意,可以通过在pages目录中创建文件夹来使用带有不同“前缀”的多个动态路由。这是具有website.com/[username]路由和website.com/teams/[team]路由的示例文件夹结构:

multiple dynamic routes

不同网段的动态数量

您还可以使用具有任意数量的动态细分的动态路由。为此,您需要在动态路由文件名中使用省略号(“ ...”):

/pages/[...userDetails].js  -> (will match http://website.com/[username]/[repo]/[etc]/[etc]/[forever]) 

在这种情况下,您的this.props.userDetails变量将返回数组而不是字符串。