Facebook React.js:你如何在服务器上渲染有状态的组件? [英] Facebook React.js: how do you render stateful components on the server?

查看:42
本文介绍了Facebook React.js:你如何在服务器上渲染有状态的组件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我认为我在概念上缺少使用 React.js 进行服务器端渲染的一些东西

I think I'm conceptually missing something with server-side rendering using React.js

假设我想创建一个页面来显示来自服务器端数据库的项目,并带有一个输入字段过滤它们.

Assume I want to create a page to display items from a server-side DB, with an input field to filter them.

我想要一个页面:

  • 响应像 /items?name=foobar
  • 这样的 URL
  • 使用 React 输入字段按名称过滤项目
  • 使用 React 组件来显示过滤项目列表

假设我有一个公共 REST API 来查询客户端的项目.

Assume I have a public REST API to query the items on the client side.

从概念上讲,我在第一个请求 (GET/items?name=foobar) 时想做的是:

Conceptually, what I want to do at first request (GET /items?name=foobar) is :

  • 我希望我的输入字段显示用户作为参数传递的内容,所以我需要将查询参数 ('foobar') 作为 'prop' 传递给 react 组件(如 initialName)

所以我尝试了这个:

 // A stateful component, maintaining the value of a query field
 var ItemForm = React.createClass({
    getInitialState : function () {
        return {
            name : this.props.initialName
        };
    },
    handleInputValueChanged : function() {
        var enteredName = this.refs.query.getDOMNode().value.trim();
        this.props.onNameChanged(enteredName);
    },
    render : function () {

        return React.DOM.form({
            children : [
                React.DOM.label({
                    children : "System name"
                }),
                React.DOM.input({
                    ref : "query",
                    value : this.state.name,
                    onChange : this.handleInputValueChanged
                })
            ]
        });
    }
});

  • 我还必须在服务器上执行我的数据库查询以获取项目列表,并且将此项目列表作为 ItemList 的道具"(如initialItems")传递
    • I also have to do my database query on the server to get a list of items, and pass this list of items as a 'prop' of the ItemList (like 'initialItems')
    • 据我所知,我需要一个简单的组件来显示列表,并将其作为道具"接收:

      As I understand it, I need a simple component to display the list, receiving it as a 'prop':

       // A stateless component, displaying a list of item
       var ItemList = return React.createClass({
      
          propTypes : {
              items : React.PropTypes.array
          },
      
          render : function () {
              return React.DOM.ul({
                  children : _.map(this.props.items, function (item) {
                      return React.DOM.li({
                          children : [
                              React.DOM.span({
                                  children : ["Name : ", item.name].join(" ")
                              })]
                      });
                  })
              });
          }
      });
      

      • 现在,我需要一个组件来显示整个页面;该组件必须维护整个页面的状态,即查看字段中输入的名称,并进行 API 查询以更新列表项.但是我不明白这个组件如何有一个initialState",它既可以在服务器端工作,也可以在客户端稍后呈现.
      • 我试过这个:

         // A stateful react component, maintaining the list of items
         var ItemPage = React.createClass({
        
            getInitialState : function () {
                // ?????
                // This is where I'm sure the problem lies. 
                // How can this be known both on server and client side ? 
                return {
                    items : this.props.initialItems || []
                };
            },
            queryItems : function (enteredName) {
        
                var self = this;
        
                // The field was emptied, we must clear everything
                if (!enteredName) {
                    this.setState({
                        items : []
                    });
        
                } else {
        
                    // The field was changed, we want to do a query
                    // then change the state to trigger a UI update. 
                    // The query code is irrelevant, I think.
                    doQuery(enteredName).then(function (items) {
                        self.setState({
                           items : items
                        });
                    });
                }
            },
            render : function () {
        
                // I don't want to display the same view
                // if there is no results. 
                // This uses a 'state' property of the page
                var results = null;
                if (_.isEmpty(this.state.items)) {
                    results = React.DOM.div({
                        ref : "results",
                        children : "No results"
                    });
                } else {
                    results = ItemListView({
                        // Here items is a 'prop', the ItemList is technically
                        // stateless
                        items : this.state.items
                    });
                }
        
                return React.DOM.div({
                    children : [
                        ItemForm({
                            initialName : this.props.initialName,
                            onNameChanged : this.queryItems
                        }),
                        results
                    ]
                });
            }
        });
        

        这就是我被卡住的地方.我可以使用以下内容在服务器端渲染:

        That's where I'm stuck. I can render things on the server side using something like:

        var name = // The name from the query parameters
        var items = doQueryOnServerSide(name);
        React.renderComponentAsString(ItemPage({
          initialName : name,
          initialItems : items
        });
        

        但是当我尝试编写客户端 javascript 时,我该怎么办?我知道我希望我的 dom 在哪里被渲染,但是我应该将哪些初始道具传递给 react 组件?

        But when I try to do write the client side javascript, what should I do ? I know where I want my dom to be rendered, but what initial props should I pass to the react component?

        React.renderComponent(ItemPage({
          initialName : ??? // Read the name parameter from URL ? 
          initialItems : ??? // I don't know yet, and I don't want to make an API call until the user entered something in the input box 
        });
        

        我尝试过的大多数尝试都以在客户端擦除"DOM 结束,并显示以下消息:

        Most attempts I have tried ends up with the DOM being 'erased' on the client-side, with this message:

        React 尝试在容器中使用重用标记,但校验和无效.这通常意味着您正在使用服务器渲染并且在服务器上生成的标记与客户端不同期待.React 注入了新的标记来补偿哪些有效但你失去了服务器渲染的许多好处.取而代之的是找出为什么生成的标记在客户端上不同或服务器.

        React attempted to use reuse markup in a container but the checksum was invalid. This generally means that you are using server rendering and the markup generated on the server was not what the client was expecting. React injected new markup to compensate which works but you have lost many of the benefits of server rendering. Instead, figure out why the markup being generated is different on the client or server.

        请注意,只有我的 ItemList 组件的标记被擦除,所以我认为这是我的组件的一个实现问题,但我真的不知道从哪里开始.

        Note that only the markup of my ItemList component is erased, so I suppose it's an implementation problem of my component, but I don't really know where to start.

        我在正确的轨道上吗?还是我完全错过了什么?

        Am I on the right track? Or do I miss something entirely?

        推荐答案

        在使用服务器渲染时,您应该始终传递用于在服务器上渲染组件的相同 prop.在这种情况下,您需要传递相同的 initialItems 道具,以便 React.renderComponent 获取服务器渲染的标记(通过简单地对道具进行 JSON 化并将其放入对 renderComponent).

        When using server rendering, you should always pass down the same props that you used to render the component on the server. In this case, you need to pass down the same initialItems prop in order for React.renderComponent to pick up the server-rendered markup (by simply JSONifying the props and putting it in the call to renderComponent).

        您在指定时从 initialItems 读取的一般结构对我来说很有意义.这样做允许您制作一个带有预加载数据的组件或一个没有数据的组件.您需要将初始状态设置为什么取决于您从头开始渲染全新组件时要显示的内容.(如果你总是选择服务器渲染的标记,那么你可以简单地传递 initialNameinitialItems 道具.)

        Your general structure of reading from initialItems when specified makes sense to me. Doing so allows you to either make a component with preloaded data or one that has none. What you need to set the initial state to depends on what you want to show in cases where you're rendering a brand-new component from scratch. (If you're always picking up server-rendered markup then you can simply always pass the initialName and initialItems props.)

        希望这是有道理的.

        这篇关于Facebook React.js:你如何在服务器上渲染有状态的组件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆