在根组件

时间:2016-04-04 15:43:07

标签: javascript data-structures reactjs functional-programming reactive-programming

假设我有一个大型HTML文档,其中部分嵌入了大量的React组件。

例如:

<body>

    <h1 id="react-component-1">...</h1>
    <p>Static Content</p>

    <h2> id="react-component-2">...</h2>
    <img src="static-img" />
    <p id="react-component-3">...</h3>

</body>

如您所见,我的动态元素之间存在静态元素。我想象这种情况在网站中很常见,这些网站正在慢慢地将React带入工具链。

现在我的应用程序就像这样:

function renderPage(data) {
    ReactDOM.render(<Component {...data} />, document.getElementById("react-component-1"));
    ReactDOM.render(<Component {...data} />, document.getElementById("react-component-2"));
    ReactDOM.render(<Component {...data} />, document.getElementById("react-component-3"));
}
在ajax请求成功时调用

renderPage()。这使我的组件按预期更新,并且看起来非常高效。

但是,如果我有一个处理应用程序状态的根React组件,并将更改推送到data作为道具,那就更好了。

我无法创建根组件,因为我的页面上的所有内容都不是动态的,我需要保留React组件之间的静态内容。

我希望能够做到这样的事情:

class Root extends React.Component {

    constructor(props) {
        super(props);
        this.data = {...};
     }

    render() {
        ReactDOM.render(<Component {...this.state.data} />, document.getElementById("react-component-1"));
        ReactDOM.render(<Component {...this.state.data} />, document.getElementById("react-component-2"));
        ReactDOM.render(<Component {...this.state.data} />, document.getElementById("react-component-3"));        
    }

    return false;
}

可以这样使用React吗?起初我不确定它是如何可能的,因为ReactDOM期望一个元素将组件呈现到,这将在我渲染我的根组件时清除我的静态内容。现在我想我可以做new Root(),但我还没有测试过。

我刚想到的另一个选项是保持renderPage()函数并将其调用为ONCE而不是每次加载AJAX时。然后,每个组件将侦听在AJAX成功时触发的自定义事件,该事件包含新数据。这看起来似乎很慢......我不妨将Redux用于应用程序状态。

1 个答案:

答案 0 :(得分:3)

You shouldn't use the render method of a React component to call ReactDOM.render the way you do it in your example Root component. The render method of a component can return either a valid React element (for example, <div />) or null and is not supposed to do any mutations, such as modifying the DOM, etc. If a React component needs to do some DOM mutations, it should do it from lifecycle hooks such as ComponentDidMount or ComponentDidUpdate.

To answer you question, it depends whether your static content, can be included in a React component or not.

If you can, which would be ideal, you can refactor your code to have a Root component like so :

class Root extends React.Component {
    render() {
        return (
            <Component data={ this.props.data } />
            <p>Static Content</p>
            <Component data={ this.props.data } />
            <img src="static-img" />
            <Component data={ this.props.data } />
        );
    }
}

and to have one call to ReactDOM.render :

ReactDOM.render(<Root data={ data } />, document.getElementById('my-react-mounting-point'));

If you cannot, that is if you need to have different React render trees, your current approach is fine. If you do this, though, be careful to call ReactDOM.unmountComponentAtNode when you do not need the component anymore, or you might face memory leak issues. This article from React's blog has several nice tips about the precautions to use when having various render trees + a ReactComponentRenderer boilerplate to avoid common pitfalls.