I have a table that the content need to be filtered by status tabs ('new', 'on process', 'delivered', etc) usually i'm using useEffect to catch this status tabs selection, and useState to update the table data, but now i have issues where the state is updating (by logging the 'tableData' content just after i call setTableData) but the table still on previous 'tableData' state.. can you guys tell me where is the problem?
export const OrdersTab = (tabsData : any) => {
// console.log(tabsData);
const [activeTab, setActiveTab] : any = useState(null);
const [activeStatusTab, setActiveStatusTab] : any = useState();
const [tableData, setTableData]:any[] = useState([]);
const [loading, setLoading] = useState(false);
// console.log(tabsData);
useEffect(() => {
if (activeStatusTab) {
let filteredOrderes = tabsData.initTableData;
// console.log(filteredOrderes);
if (activeStatusTab == 'all') {
filteredOrderes = tabsData.initTableData;
} else {
filteredOrderes = filteredOrderes.filter((orders:any) =>
orders.status.toString().toLowerCase().includes(activeStatusTab.toLowerCase())
);
}
// console.log(filteredOrderes.length);
setTableData(filteredOrderes);
console.log(tableData.length); /* <<-- checking if state updating/not */
}
}, [activeStatusTab]);
let statusTabs = [
{
id: "all",
label: "All"
},
{
id: "new",
label: "New"
},
{
id: "process",
label: "On Process"
},
{
id: "delivery",
label: "Delivery"
},
{
id: "completed",
label: "Completed"
},
{
id: "canceled",
label: "Canceled"
},
{
id: "failed",
label: "Failed"
},
];
return (
<Card>
<CardBody>
<div className="flex w-full flex-col">
<Tabs aria-label="Dynamic tabs"
onSelectionChange={(tabKey) => setActiveTab(tabKey)}
fullWidth={true}
items={tabsData.tabsData} >
{(item:any) => (
<Tab key={item.id} title={item.name}>
<Tabs aria-label="Options" onSelectionChange={(statusKey) => setActiveStatusTab(statusKey)} fullWidth={true} items={statusTabs}>
{(item) => (
<Tab key={item.id} title={item.label}>
<Table id="tablexxx" aria-label="Example empty table">
<TableHeader>
<TableColumn>Product(s)</TableColumn>
<TableColumn>Date</TableColumn>
<TableColumn>Store</TableColumn>
<TableColumn>Status</TableColumn>
<TableColumn>Total Amount</TableColumn>
<TableColumn>Courier</TableColumn>
<TableColumn>Action</TableColumn>
</TableHeader>
{(tableData.length > 0) ? (
<TableBody>
{tableData.map((item:any) => (
<TableRow key={item.invoice}>
<TableCell>
<Link href={'/orders/' + item.id}>
{item.products[0].main_product.name}
<p className="text-default-400">SKU: {item.products[0].main_product.sku} x {item.products[0].qty}</p>
<p className="text-default-400">Invoice: {item.invoice}</p>
</Link>
</TableCell>
<TableCell>{item.createdAt.split('T')[0]}</TableCell>
<TableCell>{item.store.name}</TableCell>
<TableCell>{item.status}</TableCell>
<TableCell>{item.total_amount}</TableCell>
<TableCell>{item.logistic.name}</TableCell>
<TableCell>
{<Dropdown>
<DropdownTrigger>
<Button
variant="bordered"
isIconOnly
>
<svg className="bi bi-three-dots-vertical" fill="currentColor" height="16" viewBox="0 0 16 16" width="16" xmlns=";><path d="M9.5 13a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0zm0-5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0zm0-5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0z"/></svg>
</Button>
</DropdownTrigger>
<DropdownMenu aria-label="Static Actions">
<DropdownItem key="new">View</DropdownItem>
<DropdownItem key="copy"><Link href={"/orders/" + item.id}>Process</Link></DropdownItem>
<DropdownItem key="delete" className="text-danger" color="danger">
Reject
</DropdownItem>
</DropdownMenu>
</Dropdown>}
</TableCell>
</TableRow>
))}
</TableBody>
) : (
<TableBody emptyContent={"No rows to display."}>{[]}</TableBody>
)}
</Table>
</Tab>
)}
</Tabs>
</Tab>
)}
</Tabs>
</div>
</CardBody>
</Card>
)}
I have a table that the content need to be filtered by status tabs ('new', 'on process', 'delivered', etc) usually i'm using useEffect to catch this status tabs selection, and useState to update the table data, but now i have issues where the state is updating (by logging the 'tableData' content just after i call setTableData) but the table still on previous 'tableData' state.. can you guys tell me where is the problem?
export const OrdersTab = (tabsData : any) => {
// console.log(tabsData);
const [activeTab, setActiveTab] : any = useState(null);
const [activeStatusTab, setActiveStatusTab] : any = useState();
const [tableData, setTableData]:any[] = useState([]);
const [loading, setLoading] = useState(false);
// console.log(tabsData);
useEffect(() => {
if (activeStatusTab) {
let filteredOrderes = tabsData.initTableData;
// console.log(filteredOrderes);
if (activeStatusTab == 'all') {
filteredOrderes = tabsData.initTableData;
} else {
filteredOrderes = filteredOrderes.filter((orders:any) =>
orders.status.toString().toLowerCase().includes(activeStatusTab.toLowerCase())
);
}
// console.log(filteredOrderes.length);
setTableData(filteredOrderes);
console.log(tableData.length); /* <<-- checking if state updating/not */
}
}, [activeStatusTab]);
let statusTabs = [
{
id: "all",
label: "All"
},
{
id: "new",
label: "New"
},
{
id: "process",
label: "On Process"
},
{
id: "delivery",
label: "Delivery"
},
{
id: "completed",
label: "Completed"
},
{
id: "canceled",
label: "Canceled"
},
{
id: "failed",
label: "Failed"
},
];
return (
<Card>
<CardBody>
<div className="flex w-full flex-col">
<Tabs aria-label="Dynamic tabs"
onSelectionChange={(tabKey) => setActiveTab(tabKey)}
fullWidth={true}
items={tabsData.tabsData} >
{(item:any) => (
<Tab key={item.id} title={item.name}>
<Tabs aria-label="Options" onSelectionChange={(statusKey) => setActiveStatusTab(statusKey)} fullWidth={true} items={statusTabs}>
{(item) => (
<Tab key={item.id} title={item.label}>
<Table id="tablexxx" aria-label="Example empty table">
<TableHeader>
<TableColumn>Product(s)</TableColumn>
<TableColumn>Date</TableColumn>
<TableColumn>Store</TableColumn>
<TableColumn>Status</TableColumn>
<TableColumn>Total Amount</TableColumn>
<TableColumn>Courier</TableColumn>
<TableColumn>Action</TableColumn>
</TableHeader>
{(tableData.length > 0) ? (
<TableBody>
{tableData.map((item:any) => (
<TableRow key={item.invoice}>
<TableCell>
<Link href={'/orders/' + item.id}>
{item.products[0].main_product.name}
<p className="text-default-400">SKU: {item.products[0].main_product.sku} x {item.products[0].qty}</p>
<p className="text-default-400">Invoice: {item.invoice}</p>
</Link>
</TableCell>
<TableCell>{item.createdAt.split('T')[0]}</TableCell>
<TableCell>{item.store.name}</TableCell>
<TableCell>{item.status}</TableCell>
<TableCell>{item.total_amount}</TableCell>
<TableCell>{item.logistic.name}</TableCell>
<TableCell>
{<Dropdown>
<DropdownTrigger>
<Button
variant="bordered"
isIconOnly
>
<svg className="bi bi-three-dots-vertical" fill="currentColor" height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3./2000/svg"><path d="M9.5 13a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0zm0-5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0zm0-5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0z"/></svg>
</Button>
</DropdownTrigger>
<DropdownMenu aria-label="Static Actions">
<DropdownItem key="new">View</DropdownItem>
<DropdownItem key="copy"><Link href={"/orders/" + item.id}>Process</Link></DropdownItem>
<DropdownItem key="delete" className="text-danger" color="danger">
Reject
</DropdownItem>
</DropdownMenu>
</Dropdown>}
</TableCell>
</TableRow>
))}
</TableBody>
) : (
<TableBody emptyContent={"No rows to display."}>{[]}</TableBody>
)}
</Table>
</Tab>
)}
</Tabs>
</Tab>
)}
</Tabs>
</div>
</CardBody>
</Card>
)}
Share
Improve this question
edited Nov 20, 2024 at 7:23
DarkBee
15.5k8 gold badges72 silver badges117 bronze badges
asked Nov 20, 2024 at 3:52
didiadas29didiadas29
421 silver badge10 bronze badges
1
- nevermind, i already fixed this issue.. if anyone has same problem, comment here if you need my solutions – didiadas29 Commented Nov 20, 2024 at 8:36
1 Answer
Reset to default -1Issue: setTableData(filteredOrderes) is called, but React updates the state asynchronously. So, console.log(tableData.length) right after setTableData is still showing the old value of tableData since the state update hasn't been applied yet.
Fix:
- Remove the console.log(tableData.length) from directly after setTableData.
- Add a separate useEffect that runs when tableData changes and log its value there.
<script src="https://cdnjs.cloudflare/ajax/libs/react/18.3.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare/ajax/libs/react-dom/18.3.1/umd/react-dom.production.min.js"></script>
import { useEffect, useState } from 'react';
export const OrdersTab = (tabsData: any) => {
const [activeTab, setActiveTab] = useState(null);
const [activeStatusTab, setActiveStatusTab] = useState();
const [tableData, setTableData] = useState<any[]>([]);
const [loading, setLoading] = useState(false);
// Effect to filter table data based on selected status tab
useEffect(() => {
if (activeStatusTab) {
let filteredOrders = tabsData.initTableData;
if (activeStatusTab === 'all') {
filteredOrders = tabsData.initTableData;
} else {
filteredOrders = filteredOrders.filter((orders: any) =>
orders.status.toString().toLowerCase().includes(activeStatusTab.toLowerCase())
);
}
// Update tableData state with filtered orders
setTableData(filteredOrders);
}
}, [activeStatusTab, tabsData.initTableData]);
// Effect to log the updated tableData when it changes
useEffect(() => {
console.log('Updated tableData length:', tableData.length);
}, [tableData]); // This effect runs whenever tableData is updated
let statusTabs = [
{ id: "all", label: "All" },
{ id: "new", label: "New" },
{ id: "process", label: "On Process" },
{ id: "delivery", label: "Delivery" },
{ id: "completed", label: "Completed" },
{ id: "canceled", label: "Canceled" },
{ id: "failed", label: "Failed" },
];
return (
<Card>
<CardBody>
<div className="flex w-full flex-col">
<Tabs
aria-label="Dynamic tabs"
onSelectionChange={(tabKey) => setActiveTab(tabKey)}
fullWidth={true}
items={tabsData.tabsData}
>
{(item: any) => (
<Tab key={item.id} title={item.name}>
<Tabs
aria-label="Options"
onSelectionChange={(statusKey) => setActiveStatusTab(statusKey)}
fullWidth={true}
items={statusTabs}
>
{(item) => (
<Tab key={item.id} title={item.label}>
<Table id="tablexxx" aria-label="Example empty table">
<TableHeader>
<TableColumn>Product(s)</TableColumn>
<TableColumn>Date</TableColumn>
<TableColumn>Store</TableColumn>
<TableColumn>Status</TableColumn>
<TableColumn>Total Amount</TableColumn>
<TableColumn>Courier</TableColumn>
<TableColumn>Action</TableColumn>
</TableHeader>
{tableData.length > 0 ? (
<TableBody>
{tableData.map((item: any) => (
<TableRow key={item.invoice}>
<TableCell>
<Link href={'/orders/' + item.id}>
{item.products[0].main_product.name}
<p className="text-default-400">
SKU: {item.products[0].main_product.sku} x {item.products[0].qty}
</p>
<p className="text-default-400">Invoice: {item.invoice}</p>
</Link>
</TableCell>
<TableCell>{item.createdAt.split('T')[0]}</TableCell>
<TableCell>{item.store.name}</TableCell>
<TableCell>{item.status}</TableCell>
<TableCell>{item.total_amount}</TableCell>
<TableCell>{item.logistic.name}</TableCell>
<TableCell>
<Dropdown>
<DropdownTrigger>
<Button variant="bordered" isIconOnly>
<svg
className="bi bi-three-dots-vertical"
fill="currentColor"
height="16"
viewBox="0 0 16 16"
width="16"
xmlns="http://www.w3./2000/svg"
>
<path d="M9.5 13a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0zm0-5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0zm0-5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0z" />
</svg>
</Button>
</DropdownTrigger>
<DropdownMenu aria-label="Static Actions">
<DropdownItem key="new">View</DropdownItem>
<DropdownItem key="copy">
<Link href={"/orders/" + item.id}>Process</Link>
</DropdownItem>
<DropdownItem key="delete" className="text-danger" color="danger">
Reject
</DropdownItem>
</DropdownMenu>
</Dropdown>
</TableCell>
</TableRow>
))}
</TableBody>
) : (
<TableBody emptyContent={"No rows to display."}>{[]}</TableBody>
)}
</Table>
</Tab>
)}
</Tabs>
</Tab>
)}
</Tabs>
</div>
</CardBody>
</Card>
);
};