问题 使用React.js时的一般结构


看着 React.js中的虚拟DOM 通过一些性能测试,我对这个库非常感兴趣。它似乎是Backbone令人敬畏的模型,路由器和集合结构的完美附加组件。

但是,由于缺乏高质量的教程和课程,我留下了一些问题,希望有人能够回答:

HTML模板

React是否完全废除了HTML模板的概念?我正在谈论将视图标记放在一个单独的HTML文件中(或者在一个单独的HTML文件中) <script type=text/template> 标签)。你知道,就像你使用underscore.js Handlebars等...

入门套件示例 所有人似乎都有JSX或 React.DOM 在你的视图类中运行,这对我来说似乎有些混乱,我可以看到这有点失控,因为你的观点变得复杂。

这是一个使用带有嵌套表的基本Twitter Bootstrap面板元素呈现2个值及其总和的示例。

var CustomView = React.createClass({
    render: function() {
        var x = this.props.x;
        var y = this.props.y;

        return (
            <div className="panel panel-primary">
                <div className="panel-heading">
                    <h1 className="panel-title">Should I put all this markup somewhere else?</h1>
                </div>
                <div className="panel-body">
                    <table className="table">
                        <thead>
                            <tr>
                                <th>X</th>
                                <th>Y</th>
                                <th>Combined val</th>
                            </tr>
                        </thead>
                        <tbody>
                            <tr>
                                <td>{x}</td>
                                <td>{y}</td>
                                <td>{x + y}</td>
                            </tr>
                        </tbody>
                    </table>
                </div>
            </div>
        );
    }
});

我不想知道是否可以将这些东西移到一个单独的文件中,而是,我试图理解在使用React时最好的做法是什么。

更新和设置数据

为什么要反应页面 声明如下:

只需表达您的应用程序在任何给定时间点应该如何查看,并且当您的基础数据发生变化时,React将自动管理所有UI更新。

我不完全理解这是如何工作的。例如,从之前获取React组件 <CustomView x="20" y="10">。最初我会像这样呈现它:

var x = 20;
var y = 10;

React.renderComponent(
    <CustomView x={x} y={y} />,
    document.getElementById('view-container')
);

现在,当我想随时更新CustomView时 x 变化,我该怎么办? React应该是您在Angular和Ember中找到的数据绑定的替代方法,而不进行双向绑定,那么我该如何实现呢?我怎么说 CustomView 要密切关注 x 并在它发生变化时自动重新渲染?

当然,只需为x分配一个新值就什么都不做。

我知道有 setState 方法,但我仍然需要手动调用,对吧?因此,如果我使用React视图和Backbone模型,代码可能如下所示:

// Data model: Backbone.js
var model = new Backbone.Model({text: "Please help! :)"});

// Create view class
var View = React.CreateClass({
    render: function() {
        return (
            <p>{this.props.text}</p>
        );
    }
});

// Instantiate new view
var view = React.renderComponent(
    <View text={model.get("text")}>,
    document.getElementById('view-container')
);

// Update view
model.on("change:text", function(model, newValue) {
    view.setState({
        text: newValue
    });
});

// Change data
model.set("text", "I do not understand this ...");

这似乎是一个非常奇怪的设置,我几乎可以肯定这不是你应该这样做的方式。

我想要一些指示来帮助我在这里朝着正确的方向前进。

提前感谢您提供任何反馈和帮助。


1082
2018-06-15 17:04


起源

我自己没有用过,但值得一看 反应的自举。它似乎是React组件中的Bootstrap组件因此,而不是使用大块的面板html CustomView,你可以使用 <Panel header="foo bar">... table ...</Panel> 代替。 - Douglas


答案:


React是否完全废除了HTML模板的概念?

是的,赞成使用JavaScript声明您的观点。它还允许Virtual DOM结构高效工作。

Starter工具包示例似乎都在您的视图类中有JSX或React.DOM函数,这对我来说似乎有点混乱,我可以看到这有点失控, 随着你的观点越来越复杂

您不应该允许您的视图增加复杂性。使用小型组件制作大型组件,您就不会遇到问题。如果您觉得它变得越来越复杂,您可以随时重新组织它。

我知道有setState方法,但我仍然需要手动调用它,对吧?所以,如果我正在使用React视图和Backbone模型[...]

你应该搜索“react backbone”,你会发现一些博客文章和代码示例。它们经常一起使用。随意添加您在这里找到的任何链接。


8
2018-06-15 21:20



Javascript也比HTML模板更易于组合。您可以使用您用来构建javascript的任何工具/库来构建组件。例如。我经常使用underscorejs中的函数从数据数组中构建我的组件数组。 - Jessta
谢谢FakeRainBrigand!这确实清楚了一点,虽然我有点难以绕过丢弃HTML模板,但我想这只是我必须习惯的东西...... :) - Ahrengot


你正走在正确的道路上,但有两件事需要解决。一个是错误,另一个是首选模式。

错误:在视图中,您正在使用 this.props.text (好!),但你正在使用 setState 在模型监听器中。这设定了 this.state.text 你没有使用的价值,所以它不会起作用。 setState 应该“仅”从组件内部使用 - 出于所有意图和目的,将其视为受保护的方法。相反,有 setProps 函数,仅用于组件外部。

首选模式:使用 setProps 很快就会被弃用,因为它会导致许多微妙的问题。更好的做法是每次重新渲染整个组件。您的案例中的正确代码是:

// Data model: Backbone.js
var model = new Backbone.Model({text: "Please help! :)"});

// Create view class
var View = React.CreateClass({
    render: function() {
        return (
            <p>{this.props.text}</p>
        );
    }
});

function rerender() {
  React.renderComponent(
    <View text={model.get("text")}>,
    document.getElementById('view-container')
  );
}

// Update view
model.on("change:text", function(model, newValue) {
    rerender();
});

rerender();

6
2018-06-15 20:23



问题:如果您有一个具有大量model.get调用的父React组件,那么每次对其中一个进行轻微更新时,您是否必须调用所有这些组件。例如,假设您是Facebook并且您删除了一位朋友,是否必须重新渲染并再次获取整个父React组件的所有数据? - Ryan


谢谢回复人员,

所以,我正确地假设如果我希望视图观察数据模型,我最终得到的实际上非常接近Backbone视图代码,在那里你连接事件监听器 intialize 方法?这是一个有效的快速示例:

var model = new Backbone.Model({
    text: "Hey there :)"
});

var TextBox = React.createClass({
    getInitialState: function() {
        return this.props.model.toJSON();
    },
    componentWillMount: function() {
        this.props.model.on("change:text", function(model, newText) {
            this.setState({
                text: newText
            });
        }, this);
    },
    render: function() {
        return (
            <p>{this.state.text}</p>
        );
    }
});

React.renderComponent(
    <TextBox model={model} />,
    document.getElementById('view-holder')
);

正如我所说,这确实按预期工作。只要模型的文本属性发生更改,视图就会重新呈现。这会被认为是“好的”React代码,还是应该以不同的方式挂钩?


1
2018-06-15 23:30



我将采用Shane的建议并在您的骨干视图代码中调用React.renderComponent。这里的数据不是组件的状态,而是骨干模型的状态。如果需要更改模型,可以将onChange道具传递给组件,这样您就可以将所有模型代码保留在骨干视图中。如果保持组件纯净,它可以使测试和重用组件更容易。 - FakeRainBrigand
@FakeRainBrigand哦,所以你实际上不会 更换 骨干视图,你会建立反应组件吗?这是一个非常有趣的方法!这样我仍然可以观察事件 this.listonTo 而不是旧的 model.on(...) 东东。我也得到了事件委托,可以转发我想要的部分React。这实际上非常棒。谢谢! - Ahrengot