react服务端渲染的几个问题

各位大侠,小弟最近搞react服务端渲染,遇到了几个问题,想向大家求证下。

这是node的代码:

import express from 'express';
import path from 'path';
import React from 'react';
import {
    match
} from 'react-router';
import routes from '../client/router';
import configureStore from '../client/redux';
import _render from './render';
import * as API from '../client/api';

var app = express();
app.use('/', express.static(path.join(process.cwd(), 'dist', 'client')));

//开发环境没有弄公共文件,直接引入入口文件main.client.js
function renderFullPage(html, initialState) {
    return `
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <link rel="stylesheet" href="/css/main.css" />
    </head>
    <body>
      <div id="app">
        <div>
          ${html}
        </div>
      </div>
      <script>
        window.__INITIAL_STATE__ = ${JSON.stringify(initialState)};
      </script>
      <script src="/js/main.client.js"></script>
    </body>
    </html>
  `;
}

//返回页面
const getComponentState = (store, renderProps, res) => {
    //如果组件有static getInitState()这个方法就获取相关数据后返回
    if (renderProps.components[3].getInitState) {
        renderProps.components[3].getInitState(store.dispatch).then(ret => {
            //__render的方法是引进来的
            var html = _render(store, renderProps);
            res.end(renderFullPage(html, store.getState()));
        }, err => {
            console.log(err)
        }).catch(e => {});
    } else {
        var html = _render(store, renderProps);
        res.end(renderFullPage(html, store.getState()));
    }

}


//当前页面刷新匹配相应的路由
app.use((req, res) => {
    console.log(req.url, 'urlurlurlurlurl')
    var store = configureStore();
    match({
        routes,
        location: req.url
    }, (err, redirectLocation, renderProps) => {
        if (err) {
            res.status(500).end(`Internal Server Error ${err}`);
        } else if (redirectLocation) {
            res.redirect(redirectLocation.pathname + redirectLocation.search);
        } else if (renderProps) {
            getComponentState(store, renderProps, res);
        } else {
            res.status(404).end('Not found');
        }
    });
});
app.listen(3000);

这是客户端Home首页的代码:

import React from 'react';
import BFooter from '../components/common/Footer';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { browserHistory } from 'react-router';
import ArticleList from '../components/article/ArticleList';
import ACT from '../redux/actions';
import $$ from '../utils';
import * as API from '../api';
import '../assets/css/home/index.css';


class Home extends React.Component {
    static getInitState(dispatch){
        return new Promise((resolve, reject)=>{
            API.getArticleList().then(res=>{
                dispatch(ACT.home.setArticleList(res.data));
                resolve(res.data);
            }, err=>{ reject(err)}).catch(e=>{console.log(e)})
        })
    }
    componentWillMount() {
        console.log('server: '+__isServer__, 'client: '+__isClient__ , '平台')
        //如果是通过前端路由切换过来的就执行这个方法,因为服务端在前端切换路由的时候,不会执行static
        __isClient__ && this.constructor.getInitState(this.props.dispatch);
    }
    componentDidMount(){

    }
    componentWillReceiveProps(){

    }
    render(){
        return (
            <div className="home">
                <div className="main">
                    <div className="wrapper">
                        <div className="left-cont">
                            <ArticleList onLoadMore={()=>{}} isShowMore={true} isMobile={false} isMore={false} articleList={this.props.articleList} />
                        </div>
                    </div>
                </div>
                <BFooter />
            </div>
        )
    }
}

const mapStateProps = state=>{
    return {
        state,
        articleList:state.home.articleList
    }
}

const mapDispatchProps = dispatch=>{
    return{
        dispatch,
        getArticleList:(params)=>dispatch(ACT.home.getArticleList(params))
        
    }
}

export default connect(mapStateProps, mapDispatchProps)(Home);

main.js的代码:

import React from 'react';
import { render } from 'react-dom';
import { Router } from 'react-router';
import createBrowserHistory from 'history/lib/createBrowserHistory';
import { Provider } from 'react-redux';
import routes from './router';
import configureStore from './redux';

const initialState = window.__INITIAL_STATE__;
const store = configureStore(initialState);

render(
    <Provider store={store}>
          {routes}
    </Provider>, 
    document.getElementById('app')
);
export default store;

路由:

import React from 'react';
import {Router, Route, IndexRoute, browserHistory, hashHistory} from 'react-router';
import './assets/css/common/base.css';
import './assets/libs/Font-Awesome-3.2.1/css/font-awesome.min.css';
if (typeof require.ensure !== 'function') {
    require.ensure = function(dependencies, callback) {
        callback(require)
    }
}
const App = (location, cb) => {
    require.ensure([], require => {
        cb(null, require('./App').default)
    },'App')
}
const Home = (location, cb) => {
    require.ensure([], require => {
        cb(null, require('./views/Home').default)
    },'Home')
}
const Search = (location, cb) => {
    require.ensure([], require => {
        cb(null, require('./views/Search').default)
    },'Search')
}
const Message = (location, cb) => {
    require.ensure([], require => {
        cb(null, require('./views/Message').default)
    },'Message')
}
const About = (location, cb) => {
    require.ensure([], require => {
        cb(null, require('./views/About').default)
    },'About')
}

const router = (
    <div>
        <Router history={browserHistory}>
            <Route path="/" getComponent={App}>
                <IndexRoute getComponent={Home}/>
                <Route path="/search" getComponent={Search}/>
                <Route path="/message" getComponent={Message}/>
                <Route path="/About" getComponent={About}/>
            </Route>
        </Router>
    </div>
)

export default router;

这里是我遇到的几个问题:

  1. 只做首页的服务端数据返回渲染,就可以解决一定程度的SEO问题了吗?其他的路由的不想搞服务端渲染,因为我觉得这样会导致redux相关代码的体积过大,加大工作量,所以除了首页外都使用了客户端的获取数据渲染方式,操作组件的自身的state会比较方便。
  2. 既然服务端渲染是为了减少首屏时间和seo,那么当刷新首页(单独这个页面做服务端渲染),可不可以延迟用户状态的获取,就是在服务端返回无权限数据渲染的html后,重新通过客户端来验证用户状态(cookie和localstorage这种情况下应该都可以使用了,现在还没做用户验证)。
  3. 现在面临的问题是:每当首页在服务端返回html后,客户端都会重新渲染一遍(查看源代码data-react-checksum等属性,但是审查元素却没有该属性了),我对比了一下store的数据,是一致的,为啥客户端还会渲染一次啊?
阅读 2.8k
1 个回答
  1. 如果你只打算做首页seo,你这种方式是可以的
  2. 肯定需要在首页渲染之前就做用户状态的验证了,cookie任何时候一个请求都可以获取到,不是页面加载完再去获取的。
  3. 按照正确配置下是不需要重新渲染的,可能的原因就是你服务端渲染没有生效
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题