Skip to content

Instantly share code, notes, and snippets.

@helabenkhalfallah
Created February 2, 2025 13:37
Show Gist options
  • Save helabenkhalfallah/3a773625ef0693d575460ba6c4058157 to your computer and use it in GitHub Desktop.
Save helabenkhalfallah/3a773625ef0693d575460ba6c4058157 to your computer and use it in GitHub Desktop.
Refactoring Example 3
import React, { useState, useEffect } from "react";
export default function OrderDashboardBadWay({ userId }) {
const [orders, setOrders] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const [selectedOrder, setSelectedOrder] = useState(null);
const [formattedOrders, setFormattedOrders] = useState([]);
useEffect(() => {
async function fetchOrders() {
try {
const response = await fetch(`/api/orders/${userId}`);
if (!response.ok) throw new Error("Failed to fetch orders");
const data = await response.json();
setOrders(data);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
}
fetchOrders();
}, [userId]);
useEffect(() => {
if (orders.length > 0) {
const formatted = orders.map((order) => ({
...order,
dateFormatted: new Date(order.date).toLocaleDateString(),
totalFormatted: `${order.total.toFixed(2)} USD`,
}));
setFormattedOrders(formatted);
}
}, [orders]);
const handleOrderClick = (order) => {
if (selectedOrder && selectedOrder.id === order.id) {
setSelectedOrder(null);
} else {
setSelectedOrder(order);
}
};
if (loading) return <p>Loading orders...</p>;
if (error) return <p>Error: {error}</p>;
return (
<div>
<h1>Order Dashboard</h1>
<ul>
{formattedOrders.map((order) => (
<li key={order.id} onClick={() => handleOrderClick(order)}>
<p>Order #{order.id}</p>
<p>Date: {order.dateFormatted}</p>
<p>Total: {order.totalFormatted}</p>
{selectedOrder && selectedOrder.id === order.id && (
<div>
<p>Items:</p>
<ul>
{order.items.map((item) => (
<li key={item.id}>{item.name} - {item.price} USD</li>
))}
</ul>
</div>
)}
</li>
))}
</ul>
</div>
);
}
// 1️⃣ Extract API Fetching Logic into useFetchOrders.js
import { useState, useEffect } from "react";
export function useFetchOrders(userId) {
const [orders, setOrders] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
async function fetchOrders() {
try {
const response = await fetch(`/api/orders/${userId}`);
if (!response.ok) throw new Error("Failed to fetch orders");
const data = await response.json();
setOrders(data);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
}
fetchOrders();
}, [userId]);
return { orders, loading, error };
}
// 2️⃣ Extract Formatting Logic into formatOrders.js
export function formatOrders(orders) {
return orders.map((order) => ({
...order,
dateFormatted: new Date(order.date).toLocaleDateString(),
totalFormatted: `${order.total.toFixed(2)} USD`,
}));
}
// 3️⃣ Create a Reusable OrderList Component
import React from "react";
export default function OrderList({ orders, onOrderClick, selectedOrder }) {
return (
<ul>
{orders.map((order) => (
<li key={order.id} onClick={() => onOrderClick(order)}>
<p>Order #{order.id}</p>
<p>Date: {order.dateFormatted}</p>
<p>Total: {order.totalFormatted}</p>
{selectedOrder && selectedOrder.id === order.id && <OrderDetails order={order} />}
</li>
))}
</ul>
);
}
// 4️⃣ Create a Separate OrderDetails Component
import React from "react";
export default function OrderDetails({ order }) {
return (
<div>
<p>Items:</p>
<ul>
{order.items.map((item) => (
<li key={item.id}>
{item.name} - {item.price} USD
</li>
))}
</ul>
</div>
);
}
// 5️⃣ Final Refactored OrderDashboard.jsx Component
import React, { useState } from "react";
import { useFetchOrders } from "./useFetchOrders";
import { formatOrders } from "./formatOrders";
import OrderList from "./OrderList";
export default function OrderDashboard({ userId }) {
const { orders, loading, error } = useFetchOrders(userId);
const formattedOrders = formatOrders(orders);
const [selectedOrder, setSelectedOrder] = useState(null);
const handleOrderClick = (order) => {
setSelectedOrder((prev) => (prev?.id === order.id ? null : order));
};
if (loading) return <p>Loading orders...</p>;
if (error) return <p>Error: {error}</p>;
return (
<div>
<h1>Order Dashboard</h1>
<OrderList orders={formattedOrders} onOrderClick={handleOrderClick} selectedOrder={selectedOrder} />
</div>
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment