Skip to main content

Component Structure Best Practices

This guide outlines best practices for structuring components in your application, focusing on the proper placement of network requests and separation of concerns.

Don't: Place Network Requests in Subcomponents

Avoid placing GraphQL queries or other network requests directly in subcomponents. This practice can lead to performance issues and makes it harder to manage data flow.

Example of What Not to Do

// SubComponent.js
import { gql, useQuery } from '@apollo/client';

const GET_USERS = gql`
query GetUsers {
users {
id
name
email
}
}
`;

function SubComponent() {
const { data, loading, error } = useQuery(GET_USERS);

if (loading) return <p>Loading...</p>;
if (error) return <p>Error: {error.message}</p>;

return (
<div>
<h1>Users</h1>
<ul>
{data.users.map(user => (
<li key={user.id}>
{user.name} ({user.email})
</li>
))}
</ul>
</div>
);
}

export default SubComponent;

Do: Centralize Data Fetching in Main Components

Instead, centralize data fetching in the main routed components and pass data down to subcomponents as props.

Step-by-Step Refactor

  1. Define the GraphQL Query in the Main Page
// mainPage.js
import { gql } from '@apollo/client';

const GET_USERS = gql`
query GetUsers {
users {
id
name
email
}
}
`;
  1. Set Up the Loader Function
// mainPage.js
import { json, LoaderFunction } from '@remix-run/node';
import { useLoaderData } from '@remix-run/react';
import { initializeApollo } from '~/utils/apolloClient';
import SubComponent from './SubComponent';

export let loader: LoaderFunction = async () => {
const client = initializeApollo();
try {
const { data } = await client.query({ query: GET_USERS });
return json(data);
} catch (error) {
console.error('Error fetching users:', error);
throw new Response('Error fetching users', { status: 500 });
}
};
  1. Create the SubComponent as a Pure Component
// SubComponent.js
function SubComponent({ users }) {
return (
<div>
<h1>Users</h1>
<ul>
{users.map(user => (
<li key={user.id}>
{user.name} ({user.email})
</li>
))}
</ul>
</div>
);
}

export default SubComponent;
  1. Use the SubComponent in the Main Page
// mainPage.js
import { useLoaderData } from '@remix-run/react';
import SubComponent from './SubComponent';

export default function MainPage() {
const { users } = useLoaderData();

return (
<div>
<SubComponent users={users} />
</div>
);
}

Benefits of This Approach

  1. Improved Performance: Data fetching is handled during server-side rendering.
  2. Better Separation of Concerns: Subcomponents are pure and focused on presentation.
  3. Easier Testing: Pure components are simpler to unit test.
  4. Enhanced Reusability: Subcomponents can be used in different contexts with different data.

By following these best practices, you can create more maintainable, performant, and scalable components in your application.

Back to Index | Previous: CSS Import and Stylesheets | Next: Configuration Management