Siento que he hecho esto un millón de veces, pero posiblemente no con una función de mapeo. Tengo una colección de actividades que estoy creando, las casillas de verificación con el código son las siguientes (__map viene de Lodash por cierto):

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

Mi controlador onChange tiene este aspecto:

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

El controlador funciona bien, es principalmente para referencia. Mi problema es que la etiqueta no está disparando el controlador. He probado solo la entrada de la casilla de verificación sin etiqueta y se dispara el controlador. ¿Alguien sabe por qué la etiqueta no lo está haciendo?

Más información: he tenido este problema antes, pero generalmente resulta ser una falta de coincidencia de identificación o algo así como simple. No lo creo esta vez.


Editar Eliminé casi todo el código de mi archivo e incorporé la respuesta de Slawa a continuación y todavía no se comporta como se esperaba. Aquí está el código que incluye todas las importaciones, la estructura de clases y todo el código innecesario eliminado, incluidos los estilos:

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

Editar2 Estoy jugando y decidí reemplazar onChange con onClick y ahora puedo hacer clic en la casilla de verificación real para presionar toggleActivity. ¿Alguien tiene una idea de por qué onChange no está disparando?

4
Martavis P. 28 oct. 2017 a las 22:24

3 respuestas

La mejor respuesta

La respuesta a mi pregunta se encontró en esta publicación SO. Resulta que el evento onClick de mi etiqueta (detrás de escena de html / React, no codificado por mí mismo) estaba burbujeando hacia el padre en lugar de manejar la entrada. Necesitaba decirle a la etiqueta que dejara de propagarse haciendo onClick={ e => e.stopPropagation() }.

2
Martavis P. 30 oct. 2017 a las 01:20

Estaba teniendo este mismo problema. Me estaba volviendo loco, pero lo que descubrí mi equipo y yo es que debe haber algún error con el htmlFor que te dicen que uses en los documentos. Lo eliminamos de nuestra casilla de verificación y ahora funciona como se esperaba sin efectos secundarios extraños. Estoy abriendo un problema de GH en él. Lo editaré más tarde con el enlace / actualización

Código que no funcionó:

<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>

Código que estoy usando ahora:

<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>
0
Jenessa White 4 dic. 2017 a las 20:43

Creo que tiene un error en su función toggleActivity, las actividades son una matriz e intenta convertirlo en objeto, puede encontrar mi solución completa de este problema aquí: 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 });
  }
2
Slawa Eremkin 28 oct. 2017 a las 19:51