Почему мои флажки не отображаются, когда я дважды нажимаю на один и тот же элемент?

#reactjs #checkbox #react-hooks

Вопрос:

У меня возникла проблема с созданием списка флажков для правильной работы.

Я визуализирую свой флажок из массива объектов и отображаю его правильно. Когда я нажимаю на флажок, он отображается правильно, и если я затем нажимаю на другой, он работает нормально.

Проблема возникает, когда я устанавливаю флажок, а затем снова нажимаю на тот же самый. Даже если состояние меняется, оно не повторяется. Поэтому, когда я нажимаю на другой флажок, все повторяется, и предыдущий, который был нажат дважды, также обновляется.

Мой products.js файл:

 const products = [
    {name: "CZ15B29XTD", img: "", checked: false},
    {name: "CZ16B17IPRO", img: "", checked: false},
    {name: "CZ26B47I2X", img: "", checked: false},
    {name: "CZ36B96I2X", img: "", checked: false},
    {name: "CZ37B39I2X", img: "", checked: false},
    {name: "CZ37B60IPRO", img: "", checked: false},
    {name: "CZ48B18IPRO", img: "", checked: false},
    {name: "CZ58B23I2X", img: "", checked: false},
    {name: "2607XTD", img: "", checked: false},
]

export default products
 

Мой файл Forms.jsx (который отображается внутри App.js, и получает данные и наборы в качестве реквизитов — они не имеют отношения к делу, так как они не используются для флажка)

 import React, { useState } from 'react'
import Select from 'react-select'
import axios from 'axios'
import products from '../products'

function Form({ data, setThanks }) {
    // Configure states
    const [state, setState] = useState('')
    const [city, setCity] = useState('')
    const [customer, setCustomer] = useState('')
    const [name, setName] = useState('')
    const [email, setEmail] = useState('')
    const [errMessage, setErrMessage] = useState(null)
    const [productsState, setProductsState] = useState(products)
    const [selectedValue, setSelectedValue] = useState(null);

    // Configure options
    let statesArr = []
    let citiesArr = []
    let customersArr = []

    // Populate the stateArr with all the possible states
    data.forEach(item => {
        statesArr.push(item.state)
        citiesArr.push(item.city)
        customersArr.push(item.customer)
    })
    // Remove duplicates
    const states = [...new Set(statesArr)].sort()

    const filteredCities = data.filter(item => item.state === state)
    // Add all cities to the citiesArr
    citiesArr = filteredCities.map(function(obj){
        return obj.city;
    })
    // Remove duplicates and sort
    const singleCities = filteredCities.filter(function (el, i, arr) {
        return citiesArr.indexOf(el.city) === i;
    });
    const sortedCities = singleCities.sort((a, b) => a.city < b.city? -1 : 1)

    
    const filteredCustomers = data.filter(item => item.state === state amp;amp; item.city === city)
    // Add all cities to the customersArr
    customersArr = filteredCustomers.map(function(obj){
        return obj.city;
    })
    // Remove duplicates and sort
    const singlesCustomer = filteredCustomers.filter(function (el, i, arr) {
        return customersArr.indexOf(el.city) === i;
    });
    const sortedCustomers = singlesCustomer.sort((a, b) => a.city < b.city? -1 : 1)


    // HANDLER functions
    // ***********************************

    const handleStateChange = (e) => {
        setState(e.value)
        setCity(null)
        setCustomer(null)
    }

    const handleCityChange = (e) => {
        setCity(e.value)
        setCustomer(null)
    }

    const handleCustomerChange = (e) => {
        setCustomer(e.value)
    }

    const handleChangeName = e => {
        setName(e.target.value)
    }

    const handleChangeEmail = e => {
        setEmail(e.target.value)
    }

    const handleCheckboxChange = (e, product) => {
        setSelectedValue(e.target.value)

        let checkboxList = productsState
        checkboxList.forEach(chkItem=>{
            if(chkItem === product){
              chkItem['checked'] = !chkItem['checked'];
            }
        })
        setProductsState(checkboxList)
        console.log(productsState)
    }

    console.log(selectedValue)

    const handleSubmit = e => {
        e.preventDefault()

        if(name amp;amp; state amp;amp; city amp;amp; customer) {
            axios.post('removed',{
                "data": {
                    "Nome": name, 
                    "Email": email, 
                    "Estado": state, 
                    "Cidade": city, 
                    "Distribuidor": customer,
                    "Email Sent": "false",
                    "Customer Email Sent": "false"
                }
            }).then( response => {
                console.log(response.data);
                setThanks(true)
            });
        }
        else {
            setErrMessage('Por favor preencher todos os campos acima')
        }
        
    }

    // Log all the values
    console.log(state, city, customer, name, email)

    return (
        <div className="form-container">
            <h4>Nome Completo</h4>
            <input type="text" id="client-name" name="client-name" placeholder="Digite seu nome" onChange={handleChangeName} required/>
            
            <h4>Email</h4>
            <input type="text" id="client-email" name="client-email" placeholder="Digite seu email" onChange={handleChangeEmail} required/>
            
            <h4>Selecione o Estado</h4>
            <Select 
                name="form-name"
                value={{label: state, key:'state-key'}}
                options={states.map((state) => {
                    return {value: state, label: state}
                })} 
                onChange={handleStateChange}
                />

            {state amp;amp; 
            <div className="city-select">
                <h4>Selecione a Cidade</h4>
                <Select
                    name="form-city" 
                    value={{label: city, key:'city-key'}}
                    options={sortedCities.map((item) => {
                        return {value: item.city, label: item.city}
                    })} 
                    onChange={handleCityChange}
                    /> 
            </div> }

            {state amp;amp; city amp;amp;
            <div className="customer-select">
                <h4>Selecione o Canal</h4>
                <Select 
                    name="form-customer"
                    value={{label: customer, key:'customer-key'}}
                    options={sortedCustomers.map((item) => {
                        return {value: item.customer, label: item.customer}
                    })} 
                    onChange={handleCustomerChange}    
                    />
            </div> }
            
            <h4>Selecione os Produtos</h4>
            {productsState.map(product => {
                return (
                <div key={product.name}>    
                    <input type="checkbox" 
                        id={product.name} 
                        name={product.name} 
                        value={product.name} 
                        checked={product.checked}
                        onChange={(e) => handleCheckboxChange(e, product)}
                        />
                    <label htmlFor={product.name}> {product.name}</label><br/>
                </div>
            )})}

            <button onClick={handleSubmit}> Enviar </button>
            <h4 className="error-message">{errMessage}</h4>
        </div>
    )
}

export default Form
 

Я удалил URL-адрес, по которому размещаю данные, а также по-прежнему не отправляю данные флажка, потому что он не работает.

handleCheckboxChange-это имя функции, которая вызывается всякий раз, когда установлен флажок (onChange).

Это мой первый вопрос здесь, так что извините, если формат не самый лучший или требуется дополнительная информация.

Кто-нибудь может мне помочь? Заранее спасибо!

Ответ №1:

Мне любопытно посмотреть, сработает ли создание нового массива из текущего состояния. В настоящее время doing let checkboxList = productsState является прямой ссылкой на состояние и не должен мутировать напрямую. У меня была похожая проблема с этим не так давно, React не выдает предупреждений о том, что вы напрямую изменяете состояние, и это приводит к странному поведению.

 let checkboxList = [...productsState]

checkboxList.forEach(chkItem=>{
    if(chkItem === product){
        chkItem['checked'] = !chkItem['checked'];
    }
})
 

Комментарии:

1. Спасибо за ответ, это действительно сработало. Я не думал, что меняю состояние напрямую, но ваш ответ имеет полный смысл. Спасибо за помощь 🙂