使用redux进行服务器端渲染

时间:2016-11-20 18:05:41

标签: javascript node.js reactjs redux

我有一个使用reactjs和redux构建的简单应用程序。由于我刚开始学习redux,我在服务器端渲染时遇到了一些问题。

到目前为止我所拥有的是...... 客户端App.js呈现App组件。

render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.body
);

应用程序组件:

const App = () => (
  <div>
    <SearchContainer />
    <TodoContainer />
  </div>
)

如果两个项都是容器,则SearchContainer从输入框获取输入,触发一个动作,该动作用于加载todo`s(来自远程休息服务)的消息。

现在我喜欢在服务器端加载页面加载上的那些todo,并在显示页面后显示它们。我该怎么办?有没有办法在实际显示页面之前不使用服务器端渲染和加载项目?

到目前为止,我发现的是routes.js文件:

  const middleware = [ thunk ]
  if (process.env.NODE_ENV !== 'production') {
    middleware.push(createLogger())
  }

  const store = createStore(reducer,applyMiddleware(...middleware))

  app.get('/', function(req, res) {
    res.render('home',{
      markup: ReactDOMServer.renderToString(
        <Provider store={store}>
          <App />
        </Provider>
      )
    });
//Some code calling remote service goes here

这通常是加载和应用程序,但如何将加载的数据推送到TodoContainer?它应该是某种方式来分派消息,还是应该使用todos数组作为属性初始化App组件?

3 个答案:

答案 0 :(得分:1)

您不需要服务器端渲染。

解决您遇到的问题的最常见方法是从componentDidMount加载数据。在返回此数据之前,您需要显示某些内容,例如微调器或笨蛋或消息​​或空白页。这就是它的方式。您的应用程序不会是唯一一个带有加载指示符的应用程序......

但是,您还可以执行的操作是在发送页面之前获取数据服务器端,然后使用<{em> 将页面发送到<script>标记中JSON.stringify的帮助。

<script>
  window.initialData = {
    "myData": [ 1, 2, 3 ]
  };
</script>

然后你可以用它来初始化商店。这使数据立即可用,并消除了对API端点的需求。

const store = createStore(reducer, window.initialData, applyMiddleware(...middleware));

您也可以使用相同的数据在服务器上呈现,但无论如何都不需要它。

最后,我想指出您要渲染到document.body,这是一个坏主意,因为很多浏览器扩展和插件都会添加div或其他内容。 DOM满足自己的需求。 React并没有很好地发挥这些作用。它期望控制它传递的元素。最好只创建一个div并将其渲染到其中。

答案 1 :(得分:0)

考虑一下你是否真的需要在todo app中使用SSR。主要的优点是改进了搜索引擎优化,你的应用程序准备好了一点(它已经渲染)。如果它不是很重,你可能想跳过它。

  

在实际显示页面之前,有没有办法不使用服务器端渲染和加载项目?

是的,例如,您可以调度获取数据的操作,并将其推送到componentWillMount中的Redux状态。在数据不存在之前,您可以呈现某个加载指示符的null

答案 2 :(得分:0)

嗯,在这里获得了一些反应,redux,nodejs和其他一些客户端和服务器端技术的经验,这是我发现的以及它对我有用的方式。

react / redux应用程序中的服务器端呈现包含几个步骤: 1.在服务器上加载数据 2.将数据从服务器推送到客户端 3.将数据加载到redux存储

以下是上传'redux-polyglot'组件翻译的小例子。

routes.js [处理快速服务器请求]:

//...all of your imports goes here
import en_phrases from './resources/phrases/en'

app.get('/', async function(req, res) {

    const store = createStore(reducers, applyMiddleware(...whatevermiddlewareyouneed))
    return res.render('home', {
            markup:  ReactDOMServer.renderToString(
              <Provider store={store}>
                <App/>
              </Provider>
            ),
            otherPreloadedStateThanPhrases: JSON.stringify(...anythingelse)
            phrases: JSON.stringify(en_phrases)
      });
}

这里的'home'值是把手模板名称,其中包含:

<script type="application/json" id="phrases">
  {{{ phrases }}}
</script>

然后,应用程序负责从“短语”脚本标记加载数据,并将其设置为默认语言,并提供多语言提供的功能。

app.js

const phrases = JSON.parse(document.getElementById('phrases').innerHTML);

const store = createStore(reducers, otherPreloadedStateThanPhrases, applyMiddleware(...middleware));
store.dispatch(setLanguage('en', phrases));

LoginContainer.js [从应用程序中使用的样本容器]

let LoginContainer = ({p}) => {
     <span>{p.tc('login')}</span>
}
exports.LoginContainer = connect((state) => ()(translate(LoginContainer))

其中'login'是从服务器上的短语json加载的值: en.js

export default {
  login: "Login"
}