事件没有触发,React组件之间的通信问题
Event Not Firing, Issues Communicating Between React Components
请原谅我的幼稚,但我对React相当陌生,并且我遇到了一些障碍。我需要在两个相关组件之间进行通信。我有一个"下拉"组件,它代表一个选项元素(实际上是一个div),我需要它的值来导致不同组件的状态改变。该下拉菜单基本上应该将类别设置为第二个组件的状态,该组件将根据类别显示不同的内容。我尝试了几种方法来处理这个问题,但收效甚微。目前,我正试图使用EventListeners来处理此问题,但这似乎也不起作用。
下面是我当前的代码,现在设置的方式,我得到一个错误说:
如果有人能帮我解决这个问题并继续前进,我将非常感激。或者,如果这是一个不好的处理方法,我非常愿意接受建议。"。
dispatchEvent不是函数。
var GridView = React.createClass({
getInitialState: function() {
window.addEventListener("scroll", this.handleScroll);
return {
data: [],
page: 0, //for pagination
loadingFlag: false,
};
},
getMainFeed: function() {
...
}, //end function
getMoreItems: function() {
...
}, //end function
getFilteredItems: function() {
...
}, //end function
componentWillMount: function() {
},
listenForEmailChange: function() {
window.addEventListener("selectedFilterChange", this.handleFilterChange, false);
},
componentWillUnmount: function() {
window.removeEventListener("selectedFilterChange", this.handleFilterChange, false);
},
handleFilterChange: function(filter) {
//Convert Data for getFilteredItems
switch (filter.detail.filterType) {
case 'category':
this.setState({
itemCategory: filter.detail.filterSelected,
});
break;
case 'event':
this.setState({
eventType: filter.detail.filterSelected,
});
break;
case 'type':
if (0){
this.setState({
filterBuy: 1,
filterInspiration: 0,
});
}
if (1){
this.setState({
filterBuy: 0,
filterInspiration: 1,
});
}
if (2){
this.setState({
filterBuy: 1,
filterInspiration: 1,
});
}
break;
case 'trending':
this.setState({
itemCategory: filter.detail.filterSelected,
});
break;
}
// this.getFilteredItems();
},
componentDidMount: function() {
//loading("on");
this.getMainFeed();
MasonryInit();
this.listenForEmailChange();
},
handleScroll:function(e){
//this function will be triggered if user scrolls
...
},
componentDidUpdate: function() {
$('#grid-container').imagesLoaded( function() {
$('#grid-container').masonry('reloadItems');
$('#grid-container').masonry('layout');
});
},
render: function() {
return (
<div id="feed-container-inner">
<GridMain data={this.state.data} />
</div>
);
}
});
var Dropdown = React.createClass({
sendFilter: function(item) {
dropdownChange = new CustomEvent("selectedFilterChange", {
detail: {
filterType: this.props.filterSelector,
filterSelected: item.id,
}
});
window.dispatchEvent(dropdownChange);
},
getInitialState: function() {
return {
listVisible: false,
display: ""
};
},
select: function(item) {
this.props.selected = item;
this.sendFilter(item);
},
show: function() {
this.setState({ listVisible: true });
document.addEventListener("click", this.hide);
},
hide: function() {
this.setState({ listVisible: false });
document.removeEventListener("click", this.hide);
},
render: function() {
return <div className={"dropdown-container" + (this.state.listVisible ? " show" : "")}>
<div className={"dropdown-display" + (this.state.listVisible ? " clicked": "")} onClick={this.show}>
<span>{this.props.selected.name}</span>
<i className="fa fa-angle-down"></i>
</div>
<div className="dropdown-list">
<div>
{this.renderListItems()}
</div>
</div>
</div>;
},
renderListItems: function() {
var categories = [];
for (var i = 0; i < this.props.list.length; i++) {
var category = this.props.list[i];
categories.push(<div onClick={this.select.bind(null, category)}>
<span>{category.name}</span>
<i className="fa fa-check"></i>
</div>);
}
return categories;
}
});
var GridFilter = React.createClass({
getInitialState: function() {
return {
categoryList: [{
name: "Loading Categories"
}],
eventList: [{
name: "Loading Events"
}],
typeList: [{name: "Inspiration + Shoppable", id: 0}, {name: "Inspiration", id: 1}, {name: "Shoppable", id: 2}
],
trendingList: [{
name: "Loading Trending"
}]
};
},
getCategories: function() {
...
}, //end function
getEvents: function() {
...
}, //end function
getTrending: function() {
...
}, //end function
componentDidMount: function() {
this.getCategories();
this.getEvents();
this.getTrending();
},
render: function() {
return (
<div id="filter-bar" className="stamp">
<Dropdown filterSelector={'category'} list={this.state.categoryList} selected={this.state.categoryList[0]} />
<Dropdown filterSelector={'event'} list={this.state.eventList} selected={this.state.eventList[0]} />
<Dropdown filterSelector={'type'} list={this.state.typeList} selected={this.state.typeList[0]} />
<Dropdown filterSelector={'trending'} list={this.state.trendingList} selected={this.state.trendingList[0]} />
<p className="filter-text">Filters:</p>
</div>
);
}
});
几点建议:
首先,this.dispatchEvent
在React中不存在。"调度事件"的方式是通过传递一个function
作为道具,然后调用它。您的dropdown
组件应该有一个onSelect
prop,它是一个函数。当用户选择某项内容时,只需调用this.props.onSelect
并传递相应的参数即可。
第二,你不应该像在你的select
方法上那样设置prop
。如果你想在组件中存储所选项的值,你应该使用state.
你的select
方法的重构版本应该是这样的:
select: function(item) {
this.setState({selected: item });
if(this.onSelect) {
this.onSelect(/* pass args here */);
}
}
由于上面的变化,其余的代码可能应该重构,这只是为了清晰。
额外提示:注意controlled
和uncontrolled
组件的概念。
受控组件:存储很少或不存储状态的组件。它们只是在发生变化时触发事件,父组件有责任通过适当的props
来呈现它。在你的例子中,如果你的组件作为controlled
,它不会保持所选项目的状态,它只会触发onSelect
事件,父组件会将它作为一个道具传递给新选中的项目。
非受控组件:组件将自己工作,不附加处理程序。在您的例子中,如果您的组件充当uncontrolled
,即使它可以具有onSelect
事件,它也会以不附加任何事件处理程序的方式保持所选项的状态。当某些东西发生变化时,它会呈现自己。
通常组件被设计为controlled
或uncontrolled
,但也有可能混合使用它们。
- 是否有任何JavaScript UI组件可以显示字符串之间的差异
- 设置两个反应组件之间状态的正确方式
- Ember.js:接受的子组件和父组件之间通信的最佳实践
- angular2@组件和类之间的关系
- Angular 2,在没有直接关系的两个组件之间共享一个对象
- 在 React/Redux 中管理同级组件之间的滚动状态
- 如何更新angular2中组件之间的事件数据
- Aurelia中HTML组件和普通组件之间的区别
- Vuejs中同级组件之间的通信
- 尝试在组件之间传递数据时未定义
- React组件之间共享属性
- 如何在不让web组件的原型进入全局命名空间的情况下维护它们之间的依赖关系
- 在页面之间共享组件,而无需重新加载
- Reactjs:如何在组件之间共享 websocket
- 在两个组件之间传输状态
- Reactjs 组件之间的通信
- AngularJS:在组件之间进行通信的最佳实践是什么?
- 如何管理独立反应组件之间的通信
- 响应组件之间的交互
- 两个网络组件之间的绑定:谷歌地图+地理定位