Next.js + Redux服务器端渲染:有数据,但不在服务器端渲染

时间:2017-09-02 15:08:39

标签: serverside-rendering next.js

我正在尝试将redux集成添加到我的Next.js应用程序中,但我无法让服务器端渲染按照应有的方式工作。我的实施基于the official nextjs redux example

最后,当页面从服务器返回时,数据在输出中以JSON数据的形式出现,但基于此数据的实际呈现没有发生。奇怪的是,在我使用redux之前,内容DID呈现它应该的方式。

当然,我也得到了React的校验和警告,表明服务器上的标记是不同的。

我不知道如何在服务器端正常工作。有什么东西我不见了吗?

这是Next.js生成的HTML:     

<h1 data-reactid="3">Test page</h1>

</div></div></div><div id="__next-error"></div></div><div><script>
          __NEXT_DATA__ = {"props":{"isServer":true,"store":{},

"initialState":{"authors":{"loading":false,"items":{"4nRpnr66B2CcQ4wsY04CIQ":… }

,"initialProps":{}},"pathname":"/test","query":{},"buildId":1504364251326,"buildStats":null,"assetPrefix":"","nextExport":false,"err":null,"chunks":[]}
          module={}
          __NEXT_LOADED_PAGES__ = []
          __NEXT_LOADED_CHUNKS__ = []

          __NEXT_REGISTER_PAGE = function (route, fn) {
            __NEXT_LOADED_PAGES__.push({ route: route, fn: fn })
          }

          __NEXT_REGISTER_CHUNK = function (chunkName, fn) {
            __NEXT_LOADED_CHUNKS__.push({ chunkName: chunkName, fn: fn })
          }
        </script><script async="" id="__NEXT_PAGE__/test" type="text/javascript" src="/_next/1504364251326/page/test"></script><script async="" id="__NEXT_PAGE__/_error" type="text/javascript" src="/_next/1504364251326/page/_error/index.js"></script><div></div><script type="text/javascript" src="/_next/1504364251326/manifest.js"></script><script type="text/javascript" src="/_next/1504364251326/commons.js"></script><script type="text/javascript" src="/_next/1504364251326/main.js"></script></div></body></html>

如您所见,initialState值已填充,它包含所有必需的数据,但DOM仍显示为空!。

如果我在客户端渲染dom,js将获取初始内容并重新呈现包含已加载内容的页面。

这是我的测试页面JS文件:

import React from 'react'
import map from 'lodash.map';
import { initStore } from '../lib/store';
import * as actions from '../lib/actions';
import withRedux from 'next-redux-wrapper';

class IndexPage extends React.PureComponent {
  static getInitialProps = ({ store, req }) => Promise.all([
    store.dispatch(actions.fetchAll)
  ]).then( () => ({}) )

  render() {
    const latestPlants = this.props.plants.latest || [];

    return (
      <div>
        <h1>Test page</h1>
        { map(this.props.plants.items, p => (
          <div>{p.fields.name}</div>
        ))}
      </div>
    )
  }
}

export default withRedux(initStore, data => data, null)(IndexPage)

无论它值多少,这都是我上面所说的行动:

export const fetchAll = dispatch => {
  dispatch({
    type: LOADING_ALL
  })

  return axios.get('/api/frontpage')
    .then( response => {
      const data = response.data
      dispatch({
        type: RESET_AUTHORS,
        payload: data.authors
      })
      dispatch({
        type: RESET_PLANTS,
        payload: data.plants
      })
      dispatch({
        type: RESET_POSTS,
        payload: data.posts
      })
    });
}

对此有任何帮助将不胜感激,我对如何按预期进行此项工作感到茫然。有人有任何线索吗?如果有什么我可以澄清的话,还请评论。

1 个答案:

答案 0 :(得分:0)

我建议将代码分成不同的部分。首先,我将创建一个商店,其中包含以下内容:

import { createStore, applyMiddleware } from 'redux';
import thunkMiddleware from 'redux-thunk';
import reducer from './reducers'

export const initStore = (initialState = {}) => {
  return createStore(reducer, initialState, applyMiddleware(thunkMiddleware))
}

然后我将使用要处理的类型创建商店:

const initialState = {       作者:null,       植物:null,       帖子:null     }

export default (state = initialState, action) => {
  switch (action.type) {
    case 'RESET':
      return Object.assign({}, state, { 
        authors: action.authors,
        plants: action.plants,
        posts: action.posts
      })
    default:
      return state
  }
}

在行动中,我会有这样的事情:

export const fetchAll = dispatch => {
  return axios.get('/api/frontpage')
    .then( response => {
      const data = response.data
      dispatch({
        type: 'RESET',
        authors: data.authors,
        plants: data.plants,
        posts: data.posts
      })
    });
}

索引将是这样的:

import React from 'react'
import { initStore } from '../store'
import withRedux from 'next-redux-wrapper'
import Main from '../components'

class Example extends React.Component {
  render() {
    return (
      <div>
        <Main />
      </div>
    )
  }
}

export default withRedux(initStore, null)(Example)

组件Main:

import React, {Component} from 'react'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { fetchAll } from '../../actions'

class Data extends Component {
  componentWillMount() {
    this.props.fetchAll()
  }

  render() {
    const { state } = this.props
    return (
      <div>
        <h1>Test page</h1>
        { map(state.plants.items, p => (
          <div>{p.fields.name}</div>
        ))}
      </div>
    )
  }
}

const mapStateToProps = (state) => {
  return {
    state
  }
}

const mapDistpatchToProps = dispatch => {
  return {
    fetchAll: bindActionCreators(fetchAll, dispatch)
  }
}

export default connect(mapStateToProps, mapDistpatchToProps)(Data)

根据需要进行更改。

您可以在此处查看一些完整示例:
Form handler
Server Auth