I have been reading up on React for a few days nows. I can understand most of what I'm looking at, but I'm not entirely confident in my ability to write it. I have been working on a small web app that does all of its html generation through jQuery and appending elements to each other. I'd like to try and rebuild this with React because I believe that it would be faster. This JSFiddle is a small example of the sort of thing I am working on. How would you write it with React?

JS:

function remove() {
    this.remove();
}

function timed_append_new_element() {
    setTimeout(function () {
        var added_content = $("<span />", {
            class: "added_content",
            text: "Click to close",
            click: remove
        });
        container.append(added_content);
    }, 3000);
}

function append_new_element() {
    var added_content = $("<span />", {
        class: "timed_added_content",
        text: "Click to close",
        click: remove
    });
    container.append(added_content);
}


var container = $("<div />", {
    class: "container"
});
var header = $("<span />", {
    class: "header",
    text: "jQuery to React.js Header"
});
var add_button = $("<button />", {
    class: "add_button",
    text: "Add Element",
    click: append_new_element
});
var timed_add_button = $("<button />", {
    class: "add_button",
    text: "Add Element in 3 seconds",
    click: timed_append_new_element
});
container.append(header);
container.append(add_button);
container.append(timed_add_button);
$("body").append(container);

推荐答案

There are a few basic tenets to keep in mind that may help you build a good React application:

Your UI should be a function of the data

In many "jQuery soup" style applications, the business logic for the application, the app's data, and the UI interaction code are all intermingled. This makes these sorts of applications difficult to debug and, especially, difficult to grow. React, like many modern client-side application frameworks, enforce the idea that the UI is just a representation of your data. If you want your UI to change, you should change a piece of data and allow whatever binding system the framework uses to update the UI for you.

在Reaction中,每个组件(理想情况下)都是两条数据的函数-传递给组件实例的properties条数据和组件内部管理的state条数据.给定相同的属性(或"props ")和状态,组件应该以相同的方式呈现.

This can be a bit of an abstract idea without concrete examples, so keep it in mind as we move on for now.

Don't touch the DOM

In React, even more so than other data-bound frameworks, you should try not to manipulate the DOM directly if at all possible. A lot of React's performance and complexity characteristics are only possible because React uses a virtual DOM with diffing algorithms internally to operate on the real DOM. Any time you build a component that reaches out and does its own DOM manipulation, you should ask yourself if you could build the same feature more idiomatically with React's virtual DOM features.

Of course, sometimes you'll need to access the DOM, or you'll want to incorporate some jQuery plugin without rebuilding it in React. For times like these, React gives you good component lifecycle hooks that you can use to ensure that React's performance doesn't suffer too much (or, in some cases, to keep your component from plain breaking).

Not manipulating the DOM goes hand-in-hand with "UI as a function of the data," above.

Invert the data flow

In a large React application, it can be difficult to keep track of which sub-component is managing a certain piece of application data. For this reason, the React team recommends keeping data manipulation logic in a central location. The most straightforward way to do this is to pass callbacks into child components; there's also an architecture developed at Facebook called Flux which has its own website.

Create composable components

A lot of times, it can be tempting to write a large component that manages several pieces of state or several pieces of UI logic. Where possible (and within reason), you should consider breaking larger components into smaller ones that operate on a single piece of data or UI logic. This makes it much easier to extend and move around pieces of your application.

Beware mutable data

由于组件状态只能通过从组件内部调用this.setState来更新,因此对可变数据保持警惕是有帮助的.当有多个功能(或组件!)时,情况更是如此可能会在同一时间更新可变对象;React可能会try 批量更改状态,您可能会丢失更新!正如Eliseu Monar的 comments 中提到的,在变异之前先考虑克隆可变对象.React有immutability helpers个可以提供帮助.

Another option is to forgo keeping mutable data structures directly in state at all; the Flux pattern, mentioned above, is an interesting take on this idea.


There's a great article on the React site called Thinking in React which goes over how you might take an idea or a mockup and turn it into a React application, and I strongly encourage going over it. As a concrete example, let's take a look at the code you provided. You essentially have one piece of data to manage: a list of content that exists inside the container element. All the changes to your UI can be represented by additions, removals, and changes to that data.

通过应用上述原则,您的最终应用程序可能如下所示:

/** @jsx React.DOM */

var Application = React.createClass({
  getInitialState: function() {
    return {
      content: []
    };
  },

  render: function() {
    return (
      <div className="container">
        <span className="header">jQuery to React.js Header</span>
        <button className="add_button"
                onClick={this.addContent}>Add Element</button>
        <button className="add_button"
                onClick={this.timedAddContent}>Add Element in 3 Seconds</button>
        {this.state.content.map(function(content) {
          return <ContentItem content={content} removeItem={this.removeItem} />;
        }.bind(this))}
      </div>
    );
  },

  addContent: function() {
    var newItem = {className: "added_content", text: "Click to close"},
        content = this.state.content,
        newContent = React.addons.update(content, {$push: [newItem]});
    this.setState({content: newContent});
  },

  timedAddContent: function() {
    setTimeout(function() {
      var newItem = {className: "timed_added_content", text: "Click to close"},
          content = this.state.content,
          newContent = React.addons.update(content, {$push: [newItem]});
      this.setState({content: newContent});
    }.bind(this), 3000);
  },

  removeItem: function(item) {
    var content = this.state.content,
        index = content.indexOf(item);
    if (index > -1) {
      var newContent = React.addons.update(content, {$splice: [[index, 1]]});
      this.setState({content: newContent});
    }
  }
});

var ContentItem = React.createClass({
  propTypes: {
    content: React.PropTypes.object.isRequired,
    removeItem: React.PropTypes.func.isRequired
  },

  render: function() {
    return <span className={this.props.content.className}
                 onClick={this.onRemove}>{this.props.content.text}</span>;
  },

  onRemove: function() {
    this.props.removeItem(this.props.content);
  }
});

React.renderComponent(<Application />, document.body);

You can see the code in action in this JSFiddle: http://jsfiddle.net/BinaryMuse/D59yP/

该应用程序由两个组件组成:一个名为Application的顶级组件(在其状态下)管理一个名为content的数组;另一个名为ContentItem的组件,表示该数组中单个项的UI和行为.Applicationrender方法为内容数组中的每个项目返回ContentItem元素.

One thing to notice is that all of the logic for managing the values inside the content array are handled in the Application component; the ContentItem components are passed a reference to Application's removeItem method, which the ContentItem delegates to when clicked. This keeps all the logic for manipulating state inside the top-level component.

Jquery相关问答推荐

如果文本框内容在 X 秒内没有更改,则进行 post 调用

如何在外部JS文件中使用带有参数的laravel路由

如何从 jQuery 转到 React.js?

在 jQuery 事件中控制this的值

jQuery 动画滚动

找到下一个匹配的sibling 姐妹的有效,简洁的方法?

使用 JavaScript 和 jQuery,跨浏览器处理按键事件 (F1-F12)

使用 jQuery DataTables 时禁用最后一列的排序

jQuery getJSON 将结果保存到变量中

如何在 JavaScript 或 jQuery 中规范化 HTML?

如何将数组传递给 jQuery .data() 属性

使用 Jquery 更改页面标题

隐藏 div 但保留空白

如何使用 jQuery 停止默认链接点击行为

!!~(不是波浪号/bang bang 波浪号)如何改变包含/包含数组方法调用的结果?

在 jQuery 中 Select 后代元素的最快方法是什么?

如何将键和值都推送到 Jquery 中的数组中

添加到数组 jQuery

使用 moment.js 将日期转换为字符串MM/dd/yyyy

如何使用新的 JSON 数据手动更新数据表