1

I am trying to build a product list with selectAll functionality but when I'm clicking on selectAll checkBox the state[checkBoxes Array] isn't reflecting the other checkboxes after calling handleCheck() method. I have also used useEffect() with chkAll as a dependency, but the problem didn't resolve. Please help me to resolve this problem

enter image description here

Whole Code...

import React, { useEffect, useState } from 'react'
import { Card,Container, Row, Col,Button,Media,Form,Tooltip } from "react-bootstrap";
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faSearch,faFilter, faTimes,faEdit } from '@fortawesome/free-solid-svg-icons';
import Checkbox from '../CustomCheckbox/CustomCheckbox';
import './ProductListData.css'

const styles = {
    mediaItem: {
    //   margin:'1rem',
    //   border: "1px solid gray",
      backgroundColor: "#f5f5f5",
 
    },
    mediaItemButtons: {
      paddingTop: "5px",
      paddingBottom: "5px"
    }
  };

export default function P2({products,allCheck,setAllCheck}) {
    var f=0;
    const [state,setState]=useState({
        checkedBoxes:[],
        
    })
    const [chkBox,setChkBox]=useState(false)
    const [q,setQ]=useState("")

    const Search=(products)=>{
        return products.filter(product=>
         product.name.toLowerCase().indexOf(q.toLowerCase())!==-1 || //str.includes(PATTERN)
         product.price.toLowerCase().indexOf(q.toLowerCase())!==-1 ||
         product.manufacturer.toLowerCase().indexOf(q.toLowerCase())!==-1
         );
     
       // return products.filter(product=>product.name.toLowerCase()===q.toLowerCase())
        }

    const handleCheck=(e,product)=>{
        let itemName=e.target.name;
        let checked=e.target.checked;
        if(itemName==='checkAll'){
            if(checked){
            setChkBox(true)
                setState(prevState=>{
                   let  {checkedBoxes}=prevState;

                    let categories = new Set(checkedBoxes)
                    
                    

                    for(var i=0;i<products.length;i++)
                    categories.add(products[i].id)
                    checkedBoxes=Array.from(categories)
                    return {...prevState.checkedBoxes,  checkedBoxes: checkedBoxes }

                })
           console.log("Checked",state.checkedBoxes);
        }
        else{
            setChkBox(false);

           setState(prevState=>{
                let {checkedBoxes}=prevState;
               checkedBoxes.splice(0, checkedBoxes.length)
               return {...prevState.checkedBoxes, checkedBoxes: checkedBoxes };
           });
           console.log("UnChecked",state.checkedBoxes);
        }
        }

        else if(checked) {
            var arr = state.checkedBoxes;
            arr.push(product.id);
            
            setState(state=>({...state,checkedBoxes:arr}));
        } else {            
            let products = state.checkedBoxes.splice(state.checkedBoxes.indexOf(product.id), 1);
            
            setState(state=>({...state,checkedBoxes:products}));
        }   
    }
   

    return (
        <>
          <div className='products'>
                 <Card  className='cardpl'>
                 <Card.Header className='header'>
                     <div className='header-filter'>
                     <input
                          // id={id}
                          name='checkAll'
                          type="checkbox"
                          checked={chkBox}
                          onChange={(e)=>handleCheck(e)}
                          
                      />
                        {/* <Checkbox 
                          number={1000}  
                          isChecked={false} lebal={'Chk'}/> */}

                        <div className='search-bar' >
                          <FontAwesomeIcon icon={faSearch} />

                          <input type="text" value={q} placeholder="Search Products" onChange={(e)=>{setQ(e.target.value)}}/>
                          
                          </div>
                          <div className='filter-icon'>
                          <Button className='filter-button' style={{background:'transparent',color:'#3c44b1',border:'none',boxShadow:'none'}}> <FontAwesomeIcon icon={faFilter} /></Button>
                          </div>
                          {/* <FontAwesomeIcon icon={f}/> */}
                   </div>
                  </Card.Header>
                 <Card.Body className='productListBody overflow-auto custom-scrollbar-css '>



                 
            <p>{products.length!==0?Search(products).map((product,id)=>(
                <div style={{display:'flex',alignItems:'center',border:'1px solid #dee2e6',margin:'.5rem'}}>
             {/* <Checkbox
             number={id}
             isChecked={false}
             /> */}
             
             <input
                id={id}
                type="checkbox"
                name={product.id}
                value={product.id}
                checked={state.checkedBoxes.find((p) => p.id === product.id)}
                onChange={(e) => handleCheck(e, product)}

        />
            <Media key={product.id} 
                    style={{padding:'.5rem',flex:'1'}} className={styles.mediaItem}>
                            <img
                                width={100}
                                height={100}
                                className="align-self-center mr-3"
                                src="https://i5.walmartimages.com/asr/e73e1252-642c-4473-93ea-fd3b564a7027_1.3e81ea58fa3042452fe185129a4a865f.jpeg?odnWidth=undefined&odnHeight=undefined&odnBg=ffffff"
                                alt="Generic placeholder"
                            />
                            
                            <Media.Body className={styles.mediaBody}>
                                <p><b>{product.name}</b></p>
                                <Row  className='product-row'>
                                <Col className='product-col' xs={2}>
                                    <strong>By:</strong>{product.manufacturer}
                                </Col>
                                <Col className='product-col' xs={2}><b>4.5</b>/5</Col>
                                <Col className='product-col' xs={2}>
                                    <strong>${product.price}</strong>
                                </Col>
                                <Col className='product-col' xs={2}><strong>Stock</strong>{product.stock}</Col>
                                <Col xs={2} style={{minWidth:'10rem'}}>
                                    <div className='action-button'>
                                    <Button variant="primary" size="sm">
                                    <FontAwesomeIcon icon={faEdit}/>
                                    </Button>
                                    <Button variant="danger" size="sm">
                                    <FontAwesomeIcon icon={faTimes}/>
                                    </Button>
                                    </div>
                                </Col>
                                </Row>


                               
                            </Media.Body>
                            </Media></div>)):null}
                            
                </p>    
                </Card.Body>   
                           
                         
                           </Card>
                           </div>
        </>
    )
}
b3hr4d
  • 4,012
  • 1
  • 11
  • 24
  • Welcome! Please take a moment and consider improving your question: [How to create a Minimal, Reproducible Example](https://stackoverflow.com/help/minimal-reproducible-example). Most of your code is likely unrelated and it contains all kinds of unused imports, commented out blocks, inconsistent formatting and redundant whitespace, which make unnecessarily difficult to identify the problem at hand. – hotpink Jan 17 '21 at 08:46

1 Answers1

1

Issue

It seems your checkedBoxes state is an array of ids.

setState((prevState) => {
  let { checkedBoxes } = prevState;

  let categories = new Set(checkedBoxes);

  for (var i = 0; i < products.length; i++) {
    categories.add(products[i].id); // <-- product ids into set
  }
  checkedBoxes = Array.from(categories); // <-- set -> array
  return {
    ...prevState.checkedBoxes,
    checkedBoxes: checkedBoxes, // <-- array of ids into state
  };
});

but your render code is searching this array as if they were objects with an id property.

checked={state.checkedBoxes.find((p) => p.id === product.id)}

Solution

Just check if the checkedBoxes array includes the product id

checked={state.checkedBoxes.includes(product.id)}

Side Note: Console logging state right after an enqueued update (i.e. console.log("Checked",state.checkedBoxes); will only log the state from the current render cycle, not what you are updating it to for the next render cycle. You can use an useEffect hook with a dependency on the chunk of state you want to log after it's updated.

useEffect(
  () => console.log("Checked", state.checkedBoxes),
  [state.checkedBoxes],
);
Drew Reese
  • 165,259
  • 14
  • 153
  • 181