So, You see that UI in above image..., I'm trying to replicate some functionality of G-Mail - Selecting multiple items or All items. When I try to select all(the purple chkbox)... my child components don't re-render checkboxes even though their state variable
selectedList
gets updated. I need to check all the boxes on selectAll==true
I feel like I'm doing something wrong with .map()... it is ensured that id
in map is always unique and also it is the key
attribute for child components while mapping
My main component Table
:
export default function Table() {
const [selectAll, setSelectAll] = useState(false)
//gave a dummy id:0 beacause React is throwing Uncontrolled to controlled component error as an empty {} is nothing but undefined
const [selectedList, setSelectedList] = useState({ id: 0 })
console.log(selectedList)
useEffect(()=>{
let newSelectedList = {}
if(selectAll){
dataList.forEach(ele => newSelectedList[ele.id]=1);
}else{
dataList.forEach(ele => newSelectedList[ele.id]=0);
}
setSelectedList(newSelectedList)
},[selectAll])
return <div>
<ActionBar />
<div className="overflow-x-auto w-full">
<table className="table w-full">
{/* HEAD */}
<thead>
<TableHeadingRow select selectAll={selectAll}
setSelectAll={setSelectAll} />
</thead>
{/* BODY */}
<tbody>
{
dataList.map(data =>
<TableRow key={data.id} data={data}
selectedList={selectedList} setSelectedList={setSelectedList} />)
}
</tbody>
{/* FOOT */}
<tfoot>
<TableHeadingRow />
</tfoot>
</table>
</div>
</div>
}
In above code, selectAll
keeps track of purple checkbox and selectedList
is an object of all unique ids of child components as keys and 0 or 1 as values
I try to render checkboxes in child components when their id
in selectedList
has a value 1
selectedList
is passed as prop to child component
Child component TableRow
(the one which doesn't re-render):
function TableRow({ data, selectedList, setSelectedList }) {
const { id, name, branch, address, phone, mail } = data
function handleChange() {
setSelectedList(prev => {
return { ...prev, [id]: 1 ^ prev[id] }
})
}
return <tr>
<th>
<label>
<input type="checkbox" className="checkbox checkbox-secondary"
checked={selectedList.id} onChange={handleChange} />
</label>
</th>
<td>
<div className="flex items-center space-x-3">
<div>
<div className="font-bold">{name}</div>
<div className="text-sm opacity-50">{branch}</div>
</div>
</div>
</td>
<td>{address}</td>
<td>{phone}</td>
<td>{mail}</td>
</tr>
}
Ignore handleChange
in child component, it's for singly selecting elements and works fine... It isn't related to this question anyways
On console.log(selectedList)
, I do get updated values of all ids to 1 but state of child components remain unchanged. Please help me figuring this out and let me know what I'm doing wrong. Any help is massively appreciated!