如何在React.js中处理子组件上的点击事件,是否存在React"方式"?

时间:2014-05-06 02:54:53

标签: reactjs

我尝试创建/原型化具有搜索过滤器的小部件和具有键值/父子关系的2小组。右侧面板包含类别,左侧面板具有与单个类别相关联的兴趣。可以选择类别行以显示关联的兴趣复选框。我还没有尝试理解如何使用复选框更新表单提交,首先我需要了解有关正确的数据流方式的更多信息。

这是我第一次涉足React,我知道React鼓励单向数据流。我觉得我通过使用jQuery处理事件错误地更新了兴趣小组。我想知道更新兴趣小组的一些替代方法。

根据我的阅读,为了更新父级(我相信它在React docs中称为所有者)组件,您需要在子/ ownee组件上定义回调。我很欣赏对此的解释,如果我错误地使用了州与道具的兴趣。我试图只有搜索过滤器&复选框是小部件状态的一部分,因为我读到可过滤的数据应属于道具。

更新:我在getDefaultProps中更改了要初始化的兴趣,所以现在我将它们用作道具。我认为这更像是React方式,我是否正确?我还通过更改handleCategoryRowClick函数来更改兴趣更新的方式。我觉得我现在做的事情反应更多,但是仍然会喜欢任何有更多使用React经验的人给出的建议,谢谢。

非常感谢任何帮助!

/** @jsx React.DOM */

var InterestRow = React.createClass({
    render: function() {
        return (
            <div>
                <label>{this.props.interest.name}</label>
                <input type="checkbox" ref={this.props.key} value={this.props.key} />
            </div>
        )
   }
});

var InterestPanel = React.createClass({
    var interestPanel = this;
    var rows = [];

    render: function() {
        var rows = [];
        var i = 0;

        _(this.props.interests).each(function (interest) {
            rows.push(<InterestRow interest={interest} key={interest.value} />);
        });

        return (
            <form>{rows}</form>
        )
    }
});

var CategoryRow = React.createClass({
    render: function() {
        return (
            <li onClick={this.props.handleClick.bind(null, this.props.interests)}>{this.props.category}</li>
        )
    }
});

var CategoriesPanel = React.createClass({
render: function() {
    var categoriesPanel = this;
    var rows = [];
    var categories = [];
    var interests = [];
    var interestSet = [];
    var missedSet = [];
    var lastCategory = null;
    var category;
    var interest;
    var i = 0;

    _.each(categoriesPanel.props.data, function (datum) {
        name = datum.name;
        value = datum.targeting_value;
        category = name.split('/')[0];
        interest = {name: name.split('/')[1], value: value}

        if (_.contains(interest.name.toLowerCase(), categoriesPanel.props.searchText.toLowerCase())) {
            if (category !== lastCategory) {
                if (interestSet.length > 0) {
                    interests.push(interestSet.concat(missedSet));
                }

                lastCategory = category;
                categories.push(category);
                interestSet = [];
                interestSet.push(interest);
                missedSet = [];
            } else {
                if (!_.contains(categories, category)) {
                    categories.push(category);
                    interestSet.push(interest);
                } else {
                    interestSet.push(interest);
                }
            }
        } else {
            if (category !== lastCategory) {
                if (interestSet.length > 0) {
                    interests.push(interestSet.concat(missedSet));
                }

                lastCategory = category;
                interestSet = [];
                missedSet = [];
                missedSet.push(interest);
            } else {
                missedSet.push(interest);
            }
        }
    });

    if (interestSet.length > 0) {
        interests.push(interestSet.concat(missedSet));
    }

    var interestsObject = _.zipObject(categories, interests);

    _.each(interestsObject, function (interestSet, category) {
        i++;
        rows.push(<CategoryRow category={category} key={i} interests={interestSet} handleClick={categoriesPanel.props.handleClick} />)
    });

    return (
        <div>
            <ul>{rows}</ul>
        </div>
    )
}
});

var SearchBar = React.createClass({
    handleChange: function() {
        this.props.onUserInput(
            this.refs.searchTextInput.getDOMNode().value
        )
    },
    render: function() {
        return (
            <form onSubmit={this.handleSubmit}>
                <input
                    type="text"
                    placeholder="Search Interests..."
                    value={this.props.searchText}
                    ref="searchTextInput"
                    onChange={this.handleChange}
                />
            </form>
        );
     }
});

var InterestsTable = React.createClass({
loadDataFromTwitter: function() {
    $.ajax({
        url: this.props.url,
        dataType: 'json',
        success: function(data) {
            this.setProps({data: data});
        }.bind(this)
    });
},
getInitialState: function() {
   return {
       searchText: ''
   }
},
getDefaultProps: function() {
   return {
       data: [],
       interests: []
   }
},
componentWillMount: function() {
    this.loadDataFromTwitter();
},
handleUserInput: function(searchText) {
   this.setState({
       searchText: searchText
   });
},
handleCategoryRowClick: function(interests) {
    this.setProps({
        interests: interests
    });
},
render: function() {
    return (
        <div>
            <SearchBar
                searchText={this.state.searchText}
                onUserInput={this.handleUserInput}
            />
            <CategoriesPanel
                data={this.props.data}
                searchText={this.state.searchText}
                handleClick={this.handleCategoryRowClick}
            />
            <InterestsPanel
                interests={this.props.interests}
                searchText={this.state.searchText}
            />
        </div>
    );
}
});

React.renderComponent(
     <InterestsTable url="/api/interests" />,
    document.getElementById('content')
);

1 个答案:

答案 0 :(得分:9)

  • 可以删除一些挥之不去的jQuery:
   
    componentDidMount: function() {
      $(document).on("handleCategoryRowClick", this.handleCategoryRowClick);
    },
  • 尽可能经常地将props视为不可变的并且反应生命 循环方法将按预期工作。在这种情况下,interests应该是 state代替props,因为InterestsTable组件拥有 并修改它;它没有被组件的父母传递:
  
    getInitialState: function() {
      return {
        interests: [],
        searchText: ""
      };
    },
    handleCategoryRowClick: function(e, interests) {
      this.setState({
        interests: interests
      });
    },