javascript - 服务器端的 React-router v4,如何将请求 url 与 jsx 路由匹配?

标签 javascript reactjs react-redux server-side-rendering react-router-v4

迁移到 React-router v4 后,我注意到我必须找到一种方法来将请求的 URL 与应用程序路由文件(即 JSX)进行比较。

文件routes.js包含所有react-router路由并相应导出。因此,我想知道如何获取定义的路径,以与服务器端请求的 URL 进行比较或匹配;如果不匹配,这将返回 404 或任何其他 React 组件!

找到下面的源代码:

// routes.js
import React from 'react'
import { Route } from 'react-router'
import example from './example'

export default (
  <Route path='/' component={example.containers.App} />
)

这是 Express 获取请求处理程序:

app.get('*', (req, res) => {
  const preloadedState = {'foobar': 1}
    // Create a new Redux store instance
  const store = configureStore(preloadedState)
    // Render the component to a string
  const myAppHtml = renderToString(<StaticRouter context={{}} location={req.url}>
    <Provider store={store}>
      <MyApp store={store} />
    </Provider>
  </StaticRouter>)
    // Grab the initial state from our Redux store
  const finalState = store.getState()
  res.render('index', {
    app: myAppHtml,
    state: JSON.stringify(finalState).replace(/</g, '\\x3c'),
    bundle: webpackAssets.main.js,
    build: config.build_name,
    css: '/assets/css/main.min.css'
  })
})

您还可以在下面找到完整的服务器代码:

// server.dev.js
import express from 'express'
import path from 'path'
import superagent from 'superagent'
import chalk from 'chalk'

import React from 'react'
import { renderToString } from 'react-dom/server'
import { StaticRouter, matchPath } from 'react-router'
import routes from './src/js/routes'

import configureStore from './src/js/rootStore'
import { Provider } from 'react-redux'

import MyApp from './src/js/example/containers/app'

const app = express()
const port = process.env.PORT ? process.env.PORT : 3000
var serverInstance = null
var dist = path.join(__dirname, (['staging', 'production'].indexOf(process.env.NODE_ENV) > -1 ? 'dist/' + process.env.NODE_ENV : 'src'))
var config = null
const webpack = require('webpack')
const webpackHotMiddleware = require('webpack-hot-middleware')
const webpackDevConfig = require('./webpack.dev.config')
const compiler = webpack(require('./webpack.dev.config'))
var webpackDevMiddleware = require('webpack-dev-middleware')
const webpackAssets = require('./webpack-assets.json')

config = require('./config')

/**
 * Process error handling
 */
process.on('uncaughtException', (err) => {
  throw err
})

process.on('SIGINT', () => {
  serverInstance.close()
  process.exit(0)
})

app.set('views', path.join(__dirname, 'src'))
app.set('view engine', 'ejs')

app.use(webpackDevMiddleware(compiler, {
  noInfo: true,
  publicPath: webpackDevConfig.output.publicPath,
  stats: {
    colors: true,
    hash: false,
    version: true,
    timings: false,
    assets: false,
    chunks: false,
    modules: false,
    reasons: false,
    children: false,
    source: false,
    errors: true,
    errorDetails: true,
    warnings: true,
    publicPath: false
  }
}))

app.use(webpackHotMiddleware(compiler, {
  log: console.log
}))

/**
 * The Cross origin resource sharing rules
 */
app.use((req, res, next) => {
  res.setHeader('Access-Control-Allow-Origin', '*')
  res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE')
  res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type')
  res.setHeader('Access-Control-Allow-Credentials', true)
  next()
})

/**
 * Health check
 */
app.use('/healthcheck', (req, res) => {
  res.json({
    'env': {
      'NODE_ENV': process.env.NODE_ENV
    }
  })
  res.end()
})

app.use('/api/test', (req, res) => {
  superagent
    .get('https://jsonip.com/')
    .end((err, response) => {
      if (err) {
        console.log('api test err', err)
      }
      res.send(response.body)
    })
})

app.use('/assets', express.static(dist))

// READ HERE
app.get('*', (req, res) => {
  const preloadedState = {'foobar': 1}
    // Create a new Redux store instance
  const store = configureStore(preloadedState)
    // Render the component to a string
  const myAppHtml = renderToString(<StaticRouter context={{}} location={req.url}>
    <Provider store={store}>
      <MyApp store={store} />
    </Provider>
  </StaticRouter>)
    // Grab the initial state from our Redux store
  const finalState = store.getState()
  res.render('index', {
    app: myAppHtml,
    state: JSON.stringify(finalState).replace(/</g, '\\x3c'),
    bundle: webpackAssets.main.js,
    build: config.build_name,
    css: '/assets/css/main.min.css'
  })
})

serverInstance = app.listen(port, (error) => {
  if (error) {
    console.log(error) // eslint-disable-line no-console
  }
  console.log(chalk.green('[' + config.build_name + '] listening on port ' + port + '!'))
})

一个解决方案是声明一个包含所有路由的变量,但这会违反 DRY 原则;或者也许,转译 paths.js 并获得非 JSX 版本,但到目前为止我的所有想法听起来都有些过分了!

最佳答案

我认为"matchPath" (从react-router-dom导出)就是你正在寻找的。

关于javascript - 服务器端的 React-router v4,如何将请求 url 与 jsx 路由匹配?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44074541/

相关文章:

php - 客户端还是服务器端处理?

javascript - jQuery 将元素的类保存在静态变量中并重用

javascript - 如何识别调用组件的位置以显示正确的文本

reactjs - 单击外部 url 的图像react.js

reactjs - 受控组件的内存使用问题

javascript - 悬停子元素时保持父元素的 CSS 样式

javascript - 在 ES6 + Angular 1.4 指令中插入

javascript - 无法分配给 React useRef 中的只读属性 'current'

javascript - React,纯函数警告?

javascript - 表单复选框和单选按钮如何与 React.js 配合使用?