【问题标题】:onClick on sub <li> reactonClick on sub <li> 反应
【发布时间】:2017-09-05 17:36:35
【问题描述】:

我想在列表中添加带有反应的子类别,但是当我点击子猫时,我有两个事件:第一个在子类别上,第二个在父类别上。

我怎样才能只有子类别?

这是我的实际代码:

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});

感谢您的帮助!

【问题讨论】:

    标签: javascript list reactjs


    【解决方案1】:

    问题是click events "bubble" up 到父元素。解决办法是拨打Event.prototype.stopPropagation就可以了。

    在下面的 sn-p 中,我向组件添加了 clickHandler 方法,在 getList 中,我将事件 (evt) 和 item.id 都传递给它。在那个方法中,我在调用this.props.clickHandler 之前调用evt.stopPropagation()。但是,您也可以在父组件的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>

    附:您的代码非常好,但我是否可以推荐一种更“反应方式”来呈现嵌套项目?

    您的组件的render 方法所做的是调用一个getItems 函数,该函数又以递归方式调用自身。但是,如果您还记得大多数 React 组件本身可以被认为是函数,您可以重构您的代码,以便您的 render 方法转而呈现一个 &lt;Items&gt; 组件,该组件以递归方式呈现自身的实例。

    这种方法往往会产生更小、功能更强大的组件,这些组件更可重用且更易于测试。看看下面的sn-p。

    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>

    【讨论】:

    • 是的,你是对的!这只是测试代码,所以我的代码有点脏,但我会考虑什么时候将它变成真正的代码:) 谢谢你是代码的第一部分!我想要什么!
    【解决方案2】:

    您需要阻止事件传播:

    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>);
        })
    }
    

    这样,第一个捕获点击的项目将停止点击传播。

    【讨论】:

    • 顺便说一句,您还需要在构建元素列表时使用 key 属性
    猜你喜欢
    • 2022-11-09
    • 1970-01-01
    • 2022-12-11
    • 1970-01-01
    • 2018-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-12
    相关资源
    最近更新 更多