我想在列表中添加带有反应的子类别,但是当我点击子猫时,我有两个事件:第一个是子类,第二个是父类。
我怎样只有子类别?
有我的实际代码:
getList(myList){
return myList.map((item) => {
let subList = '';
if (item.hasSub){
subList = (<ul>{this.getList(item.sub)}</ul>)
}
return (
<li onClick={() => {this.props.clicHandler(item.id)}}>{item.title}<div>{subList}</div></li>);
})
}
我使用递归方法创建列表。 我的实际数组是这样的:
this.list.push({id: 1, title:'coucou' , hasSub: false});
this.list.push({id: 2, title:'toto' , hasSub: false});
this.list.push({id: 3, title: 'cat', sub: [{id:4, title:'titi' , hasSub: false}, {id:5, title:'tutu' , hasSub: false}] , hasSub: true});
感谢您的帮助!
答案 0 :(得分:1)
您需要阻止事件传播:
getList(myList){
return myList.map((item) => {
let subList = '';
if (item.hasSub){
subList = (<ul>{this.getList(item.sub)}</ul>)
}
return (
<li onClick={(event) => {event.preventDefault(); this.props.clicHandler(item.id)}}>{item.title}<div>{subList}</div></li>);
})
}
这样,捕获点击的第一个项目将停止点击传播。
答案 1 :(得分:0)
问题在于click events "bubble" up到父元素。解决方案是在其上调用Event.prototype.stopPropagation
。
在下面的代码段中,我为组件添加了clickHandler
方法,并在getList
中将事件(evt
)和item.id
传递给它。在该方法中,我在致电evt.stopPropagation()
之前致电this.props.clickHandler
。但是,您也可以在父组件的clickHandler
方法或getList
内执行此操作。选择最适合您用例的任何内容。
class App extends React.Component {
constructor() {
super();
this.clickHandler = this.clickHandler.bind(this);
}
render() {
return <ul>{this.getList(this.props.items)}</ul>;
}
getList(list) {
return list.map((item) => {
const subList = item.hasSub && (<ul>{this.getList(item.sub)}</ul>);
return (
<li key={item.id} onClick={evt => {this.clickHandler(evt, item.id)}}>{item.title}<div>{subList}</div></li>
);
});
}
clickHandler(evt, itemId) {
// Stop event propagatation before calling handler passed in props
evt.stopPropagation();
this.props.clickHandler(itemId);
}
}
const data = [
{ id: 'a', title: 'A', hasSub: false },
{ id: 'b', title: 'B', hasSub: true, sub: [
{ id: 'b1', title: 'B1', hasSub: true, sub: [
{ id: 'b1a', title: 'B1a', hasSub: false },
] },
{ id: 'b2', title: 'B2', hasSub: false },
] },
{ id: 'c', title: 'C', hasSub: true, sub: [
{ id: 'c1', title: 'C1', hasSub: false },
{ id: 'c2', title: 'C2', hasSub: false },
] },
];
function clickHandler(itemId) {
console.log('clicked item', itemId);
}
ReactDOM.render(<App items={data} clickHandler={clickHandler}/>, document.querySelector('div'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.js"></script>
<div></div>
P.S。您的代码非常好,但我可能会建议使用更多“React方式”来呈现嵌套项吗?
您的组件的render
方法所做的是调用 getItems
函数,然后递归调用自身。但是,如果您还记得大多数React组件本身都可以被视为函数,那么您可以重构代码,以便您的render
方法呈现递归呈现的 <Items>
组件本身的实例。
这种方法倾向于产生更小的功能组件,这些组件更易于重复使用且更易于测试。请查看下面的代码段。
const Items = ({items, onClick}) => (
<ul>
{items.map(item => (
<li key={item.id} onClick={evt => onClick(evt, item.id)}>
{item.title}
{item.hasSub && <Items items={item.sub} onClick={onClick}/>}
</li>
))}
</ul>
);
const data = [
{ id: 'a', title: 'A', hasSub: false },
{ id: 'b', title: 'B', hasSub: true, sub: [
{ id: 'b1', title: 'B1', hasSub: true, sub: [
{ id: 'b1a', title: 'B1a', hasSub: false },
] },
] },
];
function clickHandler(evt, itemId) {
evt.stopPropagation();
console.log('clicked item', itemId);
}
ReactDOM.render(<Items items={data} onClick={clickHandler}/>, document.querySelector('div'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.js"></script>
<div></div>