简体   繁体   English

使用redux进行服务器端渲染

[英]Server side rendering with redux

I have a simple app built with reactjs and redux. 我有一个使用reactjs和redux构建的简单应用程序。 As im just started learning redux i have some problems doing server side rendering. 由于我刚刚开始学习redux,我在服务器端渲染时遇到了一些问题。

What i have so far is... Client App.js rendering App component. 到目前为止我所拥有的是... Client App.js渲染App组件。

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

An App component: 一个App组件:

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

Where both of items are containers SearchContainer is getting input from input box, firing an action that is dispatching a message with loaded todo`s (from remote rest service). 如果两个项都是容器,则SearchContainer从输入框获取输入,触发一个动作,该动作将使用加载的todo`s(来自远程休息服务)调度消息。

Now id like to load those todo`s on page load on server side and show them once page is shown. 现在我喜欢在服务器端的页面加载上加载那些todo,并在页面显示后显示它们。 How would i do it? 我该怎么办? Is there some way to not use server side rendering and load items before page is actually displayed? 有没有办法在页面实际显示之前不使用服务器端渲染和加载项目?

What ive come so far is routes.js file with: 到目前为止,我到目前为止是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

This is normally loading and app, but how do i push loaded data into TodoContainer? 这通常是加载和应用程序,但我如何将加载的数据推送到TodoContainer? Should it be some way of dispatching a message or should i initialize App component with todos array as properties? 它应该是某种方式来分派消息,还是应该使用todos数组作为属性来初始化App组件?

You do not need server side rendering. 您不需要服务器端渲染。

The most common way to solve the issue you're facing is to load the data from componentDidMount . 解决您遇到的问题的最常见方法是从componentDidMount加载数据。 Until this data is returned, you need to display something, such as a spinner or throbber or a message or blank page. 在返回此数据之前,您需要显示某些内容,例如微调器或笨蛋或消息​​或空白页。 That's just the way it is. 就是那样子。 Your app won't be the only one with a loading indicator... 您的应用不会是唯一一个带有加载指示器的应用...

However, what you can also do, is fetch the data server-side, before you send the page down, and send it down with the page in a <script> tag and the help of JSON.stringify . 不过,你也可以做的,就是获取数据的服务器端,你发送的页面下来之前,和页面的送下来<script>标记和帮助JSON.stringify

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

And then you can use this to initialize the store. 然后你可以用它来初始化商店。 This makes the data available immediately and removes the need for an API endpoint. 这使数据立即可用,并消除了对API端点的需求。

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

You could use this same data to render on the server as well, but it's not required by any means. 您也可以使用相同的数据在服务器上进行渲染,但无论如何都不需要它。

Finally I'd like to point out that you're rendering to document.body , which is a bad idea because a lot of browser extensions and plug-ins add a div or something else into the DOM for their own needs. 最后,我想指出你正在渲染document.body ,这是一个坏主意,因为很多浏览器扩展和插件为了自己的需要在DOM中添加了div或其他东西。 React doesn't play well with those. React不适合那些。 It expects control over the element it's passed. 它期望控制它传递的元素。 It's better to just create a div and render into that instead. 最好只创建一个div并将其渲染成一个div

Consider if you really need SSR in todo app. 考虑一下你是否真的需要在todo app中使用SSR。 The main pros are improved SEO and that your app is ready a bit faster (it's already rendered). 主要优点是改进了SEO,你的应用程序准备好了一点(它已经渲染)。 If it won't be very heavy you may want to skip that. 如果它不会很重,你可能想跳过它。

Is there some way to not use server side rendering and load items before page is actually displayed? 有没有办法在页面实际显示之前不使用服务器端渲染和加载项目?

Yes, for example you can dispatch action that fetches data and pushes it into Redux state in componentWillMount . 是的,例如,您可以调度获取数据的操作并将其推送到componentWillMount Redux状态。 Until data is not there you can render null of some loading indicator. 在数据不存在之前,您可以渲染某些加载指示器的null

Well, having gained some experience with react, redux, nodejs and some other client and server side techs here is what i found and how it works for me. 好吧,我已经获得了一些反应,redux,nodejs和其他一些客户端和服务器端技术的经验,这是我发现的以及它如何为我工作。

Server side rendering in react/redux app consist of several steps: 1. Loading data on server 2. Pushing data from server to client 3. Load data into redux storage react / redux应用程序中的服务器端呈现包括以下几个步骤:1。在服务器上加载数据2.将数据从服务器推送到客户端3.将数据加载到redux存储

Here is a small example uploading translations for 'redux-polyglot' component. 这是一个上传'redux-polyglot'组件翻译的小例子。

routes.js [handles express server requests]: 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)
      });
}

A 'home' value here is handlebars template name which has: 这里的'home'值是把手模板名称,它具有:

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

Application`s responsibility then is to load data from 'phrases' script tag and set it as default language with polyglot provided functionality. 然后,应用程序的职责是从“短语”脚本标记加载数据,并将其设置为具有多语言提供功能的默认语言。

app.js app.js

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

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

LoginContainer.js [sample container used from the App] LoginContainer.js [从应用程序中使用的样本容器]

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

Where 'login' is the value loaded from phrases json on server: en.js 其中'login'是从服务器上的短语json加载的值:en.js

export default {
  login: "Login"
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM