I have a View All page. The page has a table with user data with actions that can be performed. The button has two different icons. Spinner icon and a default icon. I want to change the icon of the button until the task executes.
Ex: Showing spinner icon until M_1's disabling/deleting process works and showing back the lock/trash icon.
I know how to update one button icon by putting useState. When 1 row has 2 buttons that mean 2 useStates. So 2 rows mean 4 useStates. But that's not practical noh. I want to know how to do it the correct way.
View All Page:
import React, { useEffect, useState } from 'react'
import {
CButton,
CCard,
CCardBody,
CCardHeader,
CCol,
CRow,
CSpinner,
CTable,
CTableBody,
CTableDataCell,
CTableHead,
CTableHeaderCell,
CTableRow,
} from '@coreui/react'
import CIcon from '@coreui/icons-react'
import { cilTrash, cilLockLocked } from '@coreui/icons'
const ViewAll = () => {
const [usersData, setUsersData] = useState({})
const [disabled, setDisabled] = useState(false)
const handleLoadMembers = async () => {
try {
const _data = await fetch('http://localhost:4000/api/v1/member/list', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
Authorization: 'Bearer ' localStorage.getItem('token'),
},
})
if (_data.status !== 200) {
throw new Error()
}
const data = await _data.json()
setUsersData(data.members)
} catch (err) {
console.error(err)
}
}
const handleDelete = async (id) => {
alert('clicked')
try {
const _data = await fetch('http://localhost:4000/api/v1/member/remove/' id, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
Authorization: 'Bearer ' localStorage.getItem('token'),
},
})
window.location.reload()
console.log(_data)
} catch (err) {
console.error(err)
}
}
useEffect(() => {
handleLoadMembers()
}, [])
return (
<CRow>
<CCol xs={12}>
<CCard className="mb-4">
<CCardHeader>
<strong>All Members</strong>
</CCardHeader>
{usersData.length > 0 ? (
<CCardBody>
<p className="text-medium-emphasis small">Here the all members of your community.</p>
<CTable hover bordered>
<CTableHead color="dark">
<CTableRow>
<CTableHeaderCell scope="col">Member ID</CTableHeaderCell>
<CTableHeaderCell scope="col">Name</CTableHeaderCell>
<CTableHeaderCell scope="col">Email</CTableHeaderCell>
<CTableHeaderCell scope="col">Actions</CTableHeaderCell>
</CTableRow>
</CTableHead>
<CTableBody>
{usersData.map((item, index) => {
return (
<CTableRow key={index}>
<CTableHeaderCell scope="row">M_{item.index}</CTableHeaderCell>
<CTableDataCell>{item.name}</CTableDataCell>
<CTableDataCell>{item.email}</CTableDataCell>
<CTableDataCell >
<CButton
color="danger"
size="sm"
disabled={disabled}
onClick={() => handleDelete(item._id)}
>
{disabled ? (
<CSpinner
component="span"
className="me-2"
size="sm"
aria-hidden="true"
/>
) : (
<CIcon icon={cilTrash} className="me-2" />
)}
Delete
</CButton>
<CButton
color="warning"
size="sm"
disabled={disabled}
onClick={() => handleDelete(item._id)}
>
{disabled ? (
<CSpinner
component="span"
className="me-2"
size="sm"
aria-hidden="true"
/>
) : (
<CIcon icon={cilLockLocked} className="me-2" />
)}
Disable
</CButton>
</CTableDataCell>
</CTableRow>
)
})}
</CTableBody>
</CTable>
</CCardBody>
) : (
'No data'
)}
</CCard>
</CCol>
</CRow>
)
}
export default ViewAll
CodePudding user response:
A better idea is to use react with redux for state management.
Steps to solve the problem:
- Make 3 action types (request, success, failure).
- Integrate the API calls on the actions/sagas file.
- Whenever you delete a particular data from the table, the request action will dispatch to the store at that time you could set particular data/ item id and the loading flag to true in the request reducer type.
- Once the action dispatches the success at that time make sure to set the loading to false in success reducer type and similarly in failure.
- Get the id and loading value in props and display the actions whatever you want to show(spinner on deleting/disabling).
Hope you could understand the steps. All the best!!!!
CodePudding user response:
how about make CButton to components and hand over props false, true