I've been struggling with it for hours. When i first load my component, the table is empty. When i navigate between pages and come back to my component, the table show data properly, but at the first render of the component, it seems like it consider vehicleList to be empty, even if the props vehicleList changed in the console. I even tried to force re-render with a useEffect hooks, with vehicleList dependency, but it doesnt work. I've been reading a lot of posts about immutability and reference, but even when i try to destructuring [...vehicleList] before passing it to the table, it doesnt trigger the re render with the right props.
const VehiclesList = ({loading, setLoading, vehicleList, categoryList, setActiveMenuItem, setMountVehicleDetails, highlightRow}) => {
const router = useRouter();
const { status } = router.query;
const [reloadPage, setReloadPage] = useState(false)
useEffect(()=> {
setReloadPage(!reloadPage)
}, [vehicleList])
return (
<div className={classes.VehiclesList}>
{loading ? null :
<>
<HeadCard
color="#DE5C5C"
background="#fff"
title={
<div className={classes.NavigationContainer}>
{<NavigationBtn
title={'Toutes catégories'}
width={'100px'}
height={'50px'}
category={'all'}
/>}
{categoryList && categoryList.data ? categoryList.data.map((element, index) => {
return <NavigationBtn
key={index}
title={categoryList.data[index].data.name}
category={categoryList.data[index].data.name}
width={'50px'}
height={'50px'}
/>
}
) : null}
</div>
}
icon='key'
loading={loading}
/>
<Row>
<Col md="12">
<Card className="main-card mb-3">
<CardBody>
<ReactTable data={vehicleList? vehicleList : []}
columns={[
{
Header: "Informations",
columns: [
{
Header: '',
id: 'photo',
accessor: (d) => <img src={d.pictures.length > 0 ? d.pictures[0].medium_url : 'https://static.teteamodeler.com/media/cache/thumb_400/coloriage-voitures.png'} alt = 'photo de la voiture' className={classes.Photo}/>,
},
{
Header: "Marque",
id: 'brand',
maxWidth: 80,
accessor: (d) => d.brand,
},
{
Header: "Modèle",
id: 'model',
sortable: false,
accessor: (d) => d.model,
},
{
Header: "Catégorie",
id: 'category',
accessor: (d) => d.category.name,
}
,
{
Header: "Registration",
id: 'immatriculation',
accessor: (d) => d.registration_number,
},
{
Header: "Id",
id: 'id',
maxWidth: 80,
accessor: (d) => d.id,
},
],
}
]}
defaultPageSize={vehicleList.length <=20 ? vehicleList.length : 20}
loading={loading}
loadingText="Chargement..."
nextText="Suivant"
previousText="Précédent"
noDataText="Aucune données correspondantes"
showPageSizeOptions={false}
className="-striped -highlight"
getTdProps={(state, rowInfo, column, instance) => {
if(rowInfo !== undefined) {
return {
style: {
background: rowInfo.row.id === highlightRow ? '#DE5C5C' : ''
},
onClick: (e) => {
console.log('A Td Element was clicked!')
console.log('it produced this event:', e)
console.log('It was in this column:', column)
console.log('It was in this row:', rowInfo)
console.log('It was in this table instance:', instance)
router.push(`/vehicles?status=vehicle_details&vehicle_id=${rowInfo.row.id}`)
setActiveMenuItem(status)
setMountVehicleDetails(true)
setLoading(true)
}
}
} else {
return {}
}
}}
/>
</CardBody>
</Card>
</Col>
</Row>
</>
}
</div>
)
}
export default VehiclesList;
Parent component is :
const Vehicles = () => {
//Data from route and localStorage
const router = useRouter();
const { status, category, vehicle_id } = router.query;
const [activeMenuItem, setActiveMenuItem] = useState('categories_list');
const [loading, setLoading] = useState(false);
const [reloadPage, setReloadPage] = useState(false);
const [highlightRow, setHighlightRow] = useState('');
//Constant to start fetching
const [mountVehicleList, setMountVehicleList] = useState(false);
//Data from useSwr hooks
const [vehicleList, setVehicleList] = useState([]);
const session = new SessionService();
const { dataFromFetch, error } = useSWR(mountVehicleList ? `${session.domain}/admin/vehicle/list` : null, url =>
session.fetch(url, {
method: 'POST',
body: JSON.stringify({
parametersToCheck: {limit: 0}
})
})
,
{
onSuccess: (dataFromFetch) => {
setVehicleList(dataFromFetch)
setMountVehicleList(false)
setLoading(false)
},
onError: (err, key, config) => {
console.log("error", err)
}
}
)
useEffect(()=> {
setLoading(true)
setMountVehicleList(true)
// router.push('/vehicles?status=categories_list')
}, [])
useEffect(() => {
setActiveMenuItem(category? `${status}/category/${category}` : status);
}, [status, category]);
useEffect(()=> {
console.log('passed in useEffect reload page')
setLoading(true)
setMountDataForRateManagement(true)
}, [reloadPage])
const backArrowHandler = () => {
router.back();
}
const menu = [
{
item: 'categories_list',
label: 'Liste des catégories',
route: '/vehicles?status=categories_list'
},
{
item: category ? `${status}/category/${category}` : 'vehicles_list/category/all',
label: 'Liste des voitures',
route: category ? `/vehicles?status=vehicles_list&category=${category}` : '/vehicles?status=vehicles_list&category=all'
},
{
item: 'agencies_list',
label: 'Liste des agences',
route: '/vehicles?status=agencies_list'
},
{
item: 'bookings_parameters',
label: 'Paramètres des réservations',
route: '/vehicles?status=bookings_parameters'
},
{
item: 'rate_management',
label: 'Gestion des tarifs',
route: '/vehicles?status=rate_management'
},
];
const carMenu = [
{
item: 'vehicle_details',
label: 'Détails véhicule',
route: 'vehicles?status=vehicle_details',
},
{
item: 'vehicle_calendar',
label: 'Calendrier du véhicule',
route: 'vehicles?status=vehicle_calendar'
}
]
const renderSwitch = (param) => {
const vehicleListPerCategory = vehicleList && vehicleList.vehicleList ? vehicleList.vehicleList.data.filter(element => element.zc_category.name === category) : [];
switch(param) {
case 'categories_list':
return <div style={{width: '75vw'}}>
<CategoryList
setLoading={setLoading}
categoryList={categoryList}
/>
</div>
case 'bookings_parameters':
return <BookingParameters />
case `vehicles_list/category/${category}`:
return <div style={{width: '75vw'}}>
<VehiclesList
categoryList={categoryList}
category={category}
loading={loading}
vehicleList={category === 'all' && vehicleList.vehicleList ? [...vehicleList.vehicleList.data] : [...vehicleListPerCategory]}
setActiveMenuItem={setActiveMenuItem}
setMountVehicleDetails={setMountVehicleDetails}
setLoading={setLoading}
highlightRow={highlightRow}
/>
</div>
case 'rate_management':
return <div style={{width: '75vw', overflowX: 'scroll'}}>
<RateManagement
loading={loading}
setLoading={setLoading}
degressionTimes={degressionTimes}
categoryItems={categoryItems}
reloadPage={reloadPage}
setReloadPage={setReloadPage}
/>
</div>
case 'vehicle_details':
return <div style={{width: '75vw', overflowX: 'scroll'}}>
<VehicleDetails
categoryList={categoryList}
dataForSelects={dataForSelects}
vehicleDetails={vehicleDetails}
vehicleBrandsAndModels={vehicleBrandsAndModels}
setLoading={setLoading}
setMountVehicleList={setMountVehicleList}
setHighlightRow={setHighlightRow}
/>
</div>
return
default:
return '';
}
}
return (
<Layout activeNav="vehicles">
{renderSwitch(activeMenuItem)}
</Layout>
)
}
export default protect(Vehicles)
vehicleList is a prop from the parent component, fetching it from an api. So it's basically equal to [] at the first render, but it's finally equal to an array of items. Kinda new to nextJs and React, i hope i explained my problem well.