与Redux和路由器反应 - 服务器渲染

时间:2016-08-29 12:44:12

标签: javascript reactjs react-router react-redux

我正在尝试使用异步调用使服务器呈现工作。我的问题是,在渲染之前没有下载数据。

我的代码(也可在github:https://github.com/tomekbuszewski/server-rendering上找到)

server.js

require('babel-register');

import express from 'express';
import path from 'path';

import React from 'react';
import { renderToString } from 'react-dom/server';
import { Provider } from 'react-redux';
import { getState } from 'redux';
import { match, RouterContext } from 'react-router'

import routes from './app/routes';
import store from './app/store';

const app = express();
const port         = 666;

app.get('/', (req, res) => {
  match({ routes, location: req.url }, (error, redirectLocation, renderProps) => {
    if (renderProps) {
      console.log(renderProps.components);
      res.send(renderToString(
        <Provider store={store}>
          <RouterContext {...renderProps} />
        </Provider>
      ))
    } else {
      console.log('err')
    }
  });
});

app.use('/public', express.static(path.join(__dirname, 'public')));
app.use('/data', express.static(path.join(__dirname, 'data')));

app.listen(port);
console.log(`localhost:${port}`);

routes.js

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

import App from './Components/App';

const routes = (
  <Router history={browserHistory}>
    <Route path="/" component={App} />
  </Router>
);

export default routes;

App组件具有提取功能:

const fetch = (dispatch) => {
    const endpoint = '/data/index.json';

    axios.get(endpoint).then((res) => {
        Array.prototype.forEach.call(res.data, d => {
            const payload = {
                id:    d.id,
                title: d.title
            };

            dispatch({type: 'ADD_CONTENT', payload});
        });
    });
};

发送&#39; ADD_CONTENT&#39;动作:

case 'ADD_CONTENT':
  return { ...state, data: [...state.data, action.payload] };

所有作品都很棒,客户端。

1 个答案:

答案 0 :(得分:0)

  1. 您的redux操作应返回在商店正确加载数据时履行的承诺
  2. 例如:

    const fetch = (dispatch) => {
        const endpoint = '/data/index.json';
    
        return axios.get(endpoint).then((res) => {
            Array.prototype.forEach.call(res.data, d => {
                const payload = {
                    id:    d.id,
                    title: d.title
                };
    
                dispatch({type: 'ADD_CONTENT', payload});
            });
        });
    };
    
    1. 您必须使用像redux-connect这样的包装器,在加载组件之前调用这些操作。
    2. 在您的示例中,路由组件为App

      在这种情况下,您将使用所需的redux操作来装饰该组件,该操作将预加载数据。

      import { asyncConnect } from 'redux-connect';
      
      @asyncConnect([{
          promise: ({ store: { dispatch } }) => {
              // `fetch` is your redux action returning a promise
              return dispatch(fetch());
          }
      }])
      @connect(
          state => ({
              // At this point, you can access your redux data as the
              // fetch will have finished 
              data: state.myReducer.data
          })
      )
      export default class App extends Component {
          // ...the `data` prop here is preloaded even on the server
      }
      

      如果您不使用顶部容器中的数据,@connect可以装饰嵌套组件,因为商店在应用范围内可用,但@asyncConnect必须装饰直接调用的组件通过react-router,它不能(到目前为止)在渲染树中的嵌套组件上使用,或者在初始渲染期间不会被解析

      因为组件树的呈现仅在服务器上发生一次,所以组件本身无法调用该函数,需要在加载之前调用 via redux-connect以及支持promises的redux操作,例如使用redux-thunk中间件。