【问题标题】:React, Why label not firing onChange for checkbox?反应,为什么标签不为复选框触发 onChange?
【发布时间】:2018-04-10 03:42:02
【问题描述】:

我觉得我已经做过一百万次了,但可能没有使用映射功能。我有一组活动,我正在创建复选框,代码如下(顺便说一下,__map 来自 Lodash):

<div className="activity-blocks">
{
    __map(this.state.activities, (activity, i) => {
        return (
            <div key={ i } className="single-activity">
                <input id={ `register-activity-${ i }` } 
                    type="checkbox" className="register-multiselect" 
                    name="main_activity" checked={ !!activity.checked } 
                    onChange={ (e) => this.toggleActivity(e, activity.id) }
                />
                <label htmlFor={ `register-activity-${ i }` }>{ activity.name }</label>
            </div>
         )
    })
 }

我的onChange 处理程序如下所示:

toggleActivity(e, activityId) {
    let activities = { ...this.state.activities };

    __forEach(this.state.activities, (activity) => {
        if (activityId === activity.id) {
            activity = __assign(activity, { checked: e.target.checked });
            return false;
        }
    });

    this.setState({ activities: activities });
}

处理程序工作得很好,主要是供参考。我的问题是标签没有触发处理程序。我只测试了没有标签的复选框输入,它触发了处理程序。有谁知道为什么标签不这样做?

更多信息:我以前遇到过这个问题,但通常结果是 id 不匹配或类似的简单问题。这次我不相信。


编辑 我已经从我的文件中删除了几乎所有的代码,并在下面合并了 Slawa 的答案,但它仍然没有按预期运行。这是包含所有导入、类结构和所有不必要的代码的代码,包括样式:

import React from 'react';
import __forEach from 'lodash/forEach';
import __assign from 'lodash/assign';
import __map from 'lodash/map';

export default class RegisterActivities extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            activities: [
                {
                    id: 1,
                    name: 'label-1'
                },
                {
                    id: 2,
                    name: 'label-2'
                },
                {
                    id: 3,
                    name: 'label-3'
                }
            ],
        }
    }

    toggleActivity(e, activityId) {
        const { activities } = this.state;

        const updated = activities.map((activity) => {
            if (activity.id === activityId){
                return {
                    ...activity,
                    checked: e.target.checked
                }
            }

            return activity;
        });
    }

    render() {
        return (
            <div>
                <p>what do you do?</p>
                <div>
                {
                    __map(this.state.activities, (activity, i) => {
                        return (
                            <div key={ i }>
                                <input id={ `register-activity-${ i }` } 
                                    type="checkbox" 
                                    name="main_activity" checked={ !!activity.checked } 
                                    onChange={ (e) => this.toggleActivity(e, activity.id) }
                                />
                                <label htmlFor={ `register-activity-${ i }` }>{ activity.name }</label>
                            </div>
                        )
                    })
                }
                </div>
            </div>
        );
    }
}

编辑2 我在玩,决定用onClick 替换onChange,现在我可以点击实际的复选框来点击toggleActivity。有人知道为什么 onChange 没有触发吗?

【问题讨论】:

    标签: javascript html reactjs checkbox


    【解决方案1】:

    找到了我的问题的答案on this SO post。事实证明,我的标签的 onClick 事件(在 html/React 的幕后,不是我自己编码的)正在冒泡到父级而不是处理输入。我需要通过 onClick={ e =&gt; e.stopPropagation() } 告诉标签停止传播。

    【讨论】:

    • 好吧,你忽略了 React 对复选框更改的处理实际上是基于点击的 hack,“以规范浏览器差异”,所以如果你有任何无害点击 preventDefault 的祖先,它干扰 React 的复选框更改黑客。
    【解决方案2】:

    我认为,您的 toggleActivity 函数有错误,活动是数组并尝试将其转换为对象,您可以在这里找到我的完整解决方案:https://codesandbox.io/s/wqyolw50vl

      toggleActivity(e, activityId) {
        const { activities } = this.state;
    
        const updated = activities.map( activity => {
          if (activity.id === activityId){
            return {
              ...activity,
              checked: !activity.checked
            }
          }
    
          return activity;
        })
    
        this.setState({ activities: updated });
      }
    

    【讨论】:

    • 感谢您的收获。出于某种原因,我仍然无法弄清楚是什么阻止了我的标签单击输入。 toggleActivity 根本不会触发。将调试器放在函数的顶部不会做任何事情。
    • 在您的示例中,您没有正确更新本地状态,因此您的复选框没有新的选中值,codesandbox.io/s/wqyolw50vl - 工作示例
    • 我刚刚在我的文件中使用您的示例进行了编辑,删除了所有其他代码,但它仍然不适合我。 编辑同样出于绝望,我将您在 App 类中的解决方案完全复制到我的解决方案中,但仍然没有触发任何点击。
    【解决方案3】:

    我遇到了同样的问题。这让我发疯,但我和我的团队发现他们告诉你在文档中使用的htmlFor 一定有一些错误。我们从我们的复选框属性中删除了它,现在它按预期运行,没有奇怪的副作用。我正在打开一个GH问题。稍后我将使用链接/更新进行编辑

    无效的代码:

    <label htmlFor={`${label}-checkbox`} className={checked ? "checked data-filter-checkbox" : "data-filter-checkbox"} >
      <input id={`${label}-checkbox`} type="checkbox" onChange={(event) => handleCheck(event)} value={label} name={label} checked={checked} />
      {label}
      <span>{count}</span>
    </label>
    

    我现在使用的代码:

    <label className={checked ? "checked data-filter-checkbox" : "data-filter-checkbox"} >
      <input id={`${label}-checkbox`} type="checkbox" onChange={(event) => handleCheck(event)} value={label} name={label} checked={checked} />
      {label}
      <span>{count}</span>
    </label>
    

    【讨论】:

    • 太棒了。我正在处理的项目是唯一需要动态创建复选框的项目,所以我很想知道它的进展。谁知道呢,也许这只是 React 15 的错误,在 16 中修复了。
    猜你喜欢
    • 2014-12-24
    • 2021-12-29
    • 2018-10-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-23
    相关资源
    最近更新 更多