← all posts

React is not your application

·2 min read ·React · Frontend · Architecture

React is a rendering library. Its job is to take state and produce UI. That's it. The moment your business logic lives inside components, you've given a rendering library responsibilities it was never designed to have.

The Component That Does Too Much

function OrderList() {
    const [orders, setOrders] = useState([]);

    useEffect(() => {
        fetch('/api/orders')
            .then(r => r.json())
            .then(data => {
                const processed = data
                    .filter(o => o.status !== 'cancelled')
                    .sort((a, b) => new Date(b.date) - new Date(a.date))
                    .map(o => ({ ...o, total: calculateTotal(o.items) }));
                setOrders(processed);
            });
    }, []);

    // 80 more lines of rendering...
}

Business logic, data fetching, transformation, and rendering—all in one place. Good luck testing any of it.

Where Logic Should Actually Live

Custom hooks handle data fetching and local state. Service functions handle transformation and business rules. Components handle rendering.

// Component is now just rendering:
function OrderList() {
    const { orders, loading } = useOrders();
    if (loading) return <Spinner />;
    return orders.map(order => <OrderCard key={order.id} order={order} />);
}

useOrders is a custom hook. The filtering and sorting logic lives in a pure processOrders() function you can test without a browser.

The Payoff

When your business logic is decoupled from React, you can unit test it without rendering anything, reuse it across components, and swap out React without rewriting your application logic.

React is not your application. It's your view layer. Treat it accordingly.