簡體   English   中英

Facebook React.js:如何在服務器上呈現有狀態組件?

[英]Facebook React.js: how do you render stateful components on the server?

我認為我在概念上缺少使用React.js進行服務器端渲染的東西

假設我想創建一個頁面來顯示來自服務器端數據庫的項目,並使用輸入字段來過濾它們。

我想要一個頁面:

  • 響應像/items?name=foobar這樣的URL
  • 使用React輸入字段按名稱過濾項目
  • 使用React組件顯示已過濾項目的列表

假設我有一個公共REST API來查詢客戶端的項目。

從概念上講,我想在第一次請求時做的事情( GET /items?name=foobar )是:

  • 我希望我的輸入字段顯示用戶作為參數傳遞的內容,因此我需要將查詢參數('foobar')傳遞給react組件,作為'prop'(如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的“prop”傳遞(如'initialItems')

據我了解,我需要一個簡單的組件來顯示列表,將其作為“道具”接收:

 // 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
            ]
        });
    }
});

那就是我被困住的地方。 我可以使用以下內容在服務器端渲染內容:

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

但是當我嘗試編寫客戶端javascript時,我該怎么辦? 我知道我想要在哪里渲染我的dom,但是我應該將哪些初始道具傳遞給反應組件?

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,並顯示以下消息:

React嘗試在容器中使用重用標記,但校驗和無效。 這通常意味着您正在使用服務器呈現,並且在服務器上生成的標記不是客戶端所期望的。 React注入了新的標記以補償哪些有效但你已經失去了服務器渲染的許多好處。 相反,弄清楚為什么生成的標記在客戶端或服務器上是不同的。

請注意,只有我的ItemList組件的標記被刪除,所以我認為這是我的組件的實現問題,但我真的不知道從哪里開始。

我是在正確的軌道上嗎? 或者我完全錯過了什么?

使用服務器渲染時,應始終傳遞用於在服務器上呈現組件的相同道具。 在這種情況下,您需要傳遞相同的initialItems prop,以便React.renderComponent獲取服務器呈現的標記(通過簡單地JSONifying道具並將其放入對renderComponent的調用中)。

從指定的initialItems讀取的一般結構對我來說是有意義的。 這樣做允許您創建具有預加載數據的組件或不具有預加載數據的組件。 您需要將初始狀態設置為取決於您要從頭開始渲染全新組件時要顯示的內容。 (如果你總是拿起服務器渲染的標記,那么你可以簡單地傳遞initialNameinitialItems道具。)

希望有道理。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM