【问题标题】:React router server side not working correctly反应路由器服务器端无法正常工作
【发布时间】:2017-03-15 21:54:58
【问题描述】:

我的应用代码在这里:https://github.com/WebTerminator/aldemar/commits/master

我正在尝试让我的 react 应用程序也可以在服务器端运行,在这个阶段它可以部分运行。

我遇到的问题是:(sam 问题发生在本地主机上)

如果我在浏览器中导航一切正常,当我刷新此 URL https://aldemar-productions.herokuapp.com/projects/margam2 时,我会收到如下控制台错误:

bundle.js:1 Uncaught SyntaxError: Unexpected token

如果我刷新其他 URL,例如“https://aldemar-productions.herokuapp.com/projects”或“https://aldemar-productions.herokuapp.com/about”,它们可以正常工作。

server.js

import express from 'express';
import path from 'path';
import React from 'react';
import { renderToString } from 'react-dom/server';
import { match, RouterContext } from 'react-router';
import routes from './src/client/app/config/routes.jsx';

let port = process.env.PORT || 8080;
let app = express();

app.use(express.static('src/client/'));

// app.get('/', (req, res) => {
//  res.sendFile(path.resolve(__dirname + '/src/client/index.html'))
// });

app.get('*', (req, res) => {
  match(
    { routes, location: req.url },
    (err, redirectLocation, renderProps) => {

      // in case of error display the error message
      if (err) {
        return res.status(500).send(err.message);
      }

      // in case of redirect propagate the redirect to the browser
      if (redirectLocation) {
        return res.redirect(302, redirectLocation.pathname + redirectLocation.search);
      }

      // generate the React markup for the current route
      let markup;
      if (renderProps) {
        // if the current route matched we have renderProps
        markup = renderToString(<RouterContext {...renderProps}/>);
      } 
      // else {
      //   // otherwise we can render a 404 page
      //   markup = renderToString(<NotFoundPage/>);
      //   res.status(404);
      // }

      // render the index template with the embedded React markup
      return res.sendFile('index.html', {root : __dirname + '/src/client/'});
    }
  );
});

app.listen(port);
console.log('server started');

routes.jsx

import React from 'react';
import { Route, Router, browserHistory } from 'react-router';
import ReactDOM from 'react-dom';

import Wrapper       from './../components/wrapper.jsx';
import Home          from './../components/home.jsx';
import Projects      from './../components/projects.jsx';
import SingleProject from './../components/projectContent/singleProject.jsx';
import About         from './../components/aboutUs.jsx'

if(typeof window !== 'undefined') {
    console.log('here baby');
    ReactDOM.render((
        <Router history={browserHistory} >
            <Route component={Wrapper} >
                <Route path="/" component={Home} />
                <Route path="projects" component={Projects} />
                <Route path="projects/:id" component={SingleProject} />
                <Route path="about" component={About} />
            </Route>
        </Router>
    ), document.getElementById('app'));
}

singleProject.jsx(我从 url 获取 ID 参数以加载特定数据)

import React from 'react';

import Video       from  './../video.jsx';
import Overview    from  './overview.jsx';
import Photography from  './photography.jsx';
import Details     from  './details.jsx';
import Cast        from  './cast.jsx';

import porgectsCollection from './../../data/projectInfo.js';

import { StickyContainer, Sticky } from 'react-sticky';

class Nav extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      mobileMenu: false
    };
  }
  showMobileMenu () {
    this.setState({ mobileMenu: !this.state.mobileMenu });
  }
  render () {
    let links = this.props.project.links.map(function(el, i){
      return <li key={i}>{el}</li>;
    });
    const open = this.state.mobileMenu ? ' open' : '';

    return (
      <Sticky stickyClassName="sticky-nav" topOffset={-100}>
        <span onClick={this.showMobileMenu.bind(this)} className="mobile-trigger">X</span>
        <nav className={"secondary-nav" + open}>
          <ul>
            {links}
          </ul>
        </nav>
      </Sticky>
    );
  }
}

class SingleProject extends React.Component {
  getProjectDataFromUrl() {
    return **porgectsCollection.filter(el => el.title === this.props.params.id)**;
  }
  render () {
    let data = this.getProjectDataFromUrl(),
        project = data[0];
    return (
        <section className="project-page">
        <StickyContainer>
          <Video project={project} />
          <Nav project={project} />
          <Overview project={project} />
          <Photography project={project} />
          <Details project={project}  />
          <Cast project={project} />
        </StickyContainer>
        </section>
    );
  }
}

export default SingleProject;

当我点击“https://aldemar-productions.herokuapp.com/projects/margam2”这样的网址时,我会根据我的路线收集“margam2”:

<Route path="projects/:id" component={SingleProject} />

然后我根据该参数加载特定数据。我相信问题出在服务器端渲染上。

UPDATE-1

在我的 index.html 的头部添加这个可以让我在刷新页面时显示内容,但是缺少 CSS:

<base href="/" />

http://localhost:8080/css/style.css 可以完全访问css,但是当我刷新“http://localhost:8080/projects/margam2”时,会显示内容但不会显示css。

【问题讨论】:

    标签: javascript node.js reactjs heroku react-router


    【解决方案1】:

    好的,经过 2 天的研究,这对我有所帮助:

    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="utf-8">
        <title></title>
        **<base href="/" />**
        <link rel="stylesheet" href="./css/foundation.min.css">
        <link href="https://fonts.googleapis.com/css?family=Montserrat:400,700" rel="stylesheet">
        <link rel="stylesheet" href="./css/font-awesome.min.css">
        <link rel="stylesheet" href="./css/style.css">
        <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.6.0/slick.min.css" />
        <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.6.0/slick-theme.min.css" />
      </head>
      <body>
        <div id="app"></div>
        <script src="./public/bundle.js" type="text/javascript"></script>
      </body>
    </html>
    

    但是我也在控制台中发现了这一点:

    browser.js:49 警告:自动设置 basename using 已弃用,将在下一个主要版本中删除。的语义与 basename 略有不同。请在创建历史的选项中明确传递基本名称

    所以需要为此找到解决方案。

    update-1

    我认为更好的解决方案。我已经更改了相对于绝对路径的资产路径形式:

    查看每个本地资产前面的 "/"

    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="utf-8">
        <title></title>
        <link rel="stylesheet" href="/css/foundation.min.css">
        <link href="https://fonts.googleapis.com/css?family=Montserrat:400,700" rel="stylesheet">
        <link rel="stylesheet" href="/css/font-awesome.min.css">
        <link rel="stylesheet" href="/css/style.css">
        <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.6.0/slick.min.css" />
        <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.6.0/slick-theme.min.css" />
      </head>
      <body>
        <div id="app"></div>
        <script src="/public/bundle.js" type="text/javascript"></script>
      </body>
    </html>
    

    【讨论】:

      【解决方案2】:

      在您的项目页面上,您正在使用内联关闭 div,如下所示:

      &lt;div id="app" /&gt;

      在所有其他页面中,您使用的是空 div

      &lt;div id="app" &gt; &lt;/div&gt;

      这是正确的做法。

      React-Router 不会重新渲染您的页面,它只会将您的反应代码“重新添加”到您的 id="app"
      这就是为什么当你打开点击它时它会起作用,而当你刷新它时它就坏了。

      【讨论】:

        猜你喜欢
        • 2017-11-09
        • 2019-06-17
        • 1970-01-01
        • 2019-05-08
        • 1970-01-01
        • 2017-10-13
        • 2018-02-05
        • 2018-04-14
        • 1970-01-01
        相关资源
        最近更新 更多