• Что бы вступить в ряды "Принятый кодер" Вам нужно:
    Написать 10 полезных сообщений или тем и Получить 10 симпатий.
    Для того кто не хочет терять время,может пожертвовать средства для поддержки сервеса, и вступить в ряды VIP на месяц, дополнительная информация в лс.

  • Пользаватели которые будут спамить, уходят в бан без предупреждения. Спам сообщения определяется администрацией и модератором.

  • Гость, Что бы Вы хотели увидеть на нашем Форуме? Изложить свои идеи и пожелания по улучшению форума Вы можете поделиться с нами здесь. ----> Перейдите сюда
  • Все пользователи не прошедшие проверку электронной почты будут заблокированы. Все вопросы с разблокировкой обращайтесь по адресу электронной почте : info@guardianelinks.com . Не пришло сообщение о проверке или о сбросе также сообщите нам.

Breaking Up with Our Monolithic Table: A React Refactoring Journey

Lomanu4 Оффлайн

Lomanu4

Команда форума
Администратор
Регистрация
1 Мар 2015
Сообщения
1,481
Баллы
155
Refactoring a React Table Component: From Monolith to Compound Pattern

The Challenge



We had a complex business table component that started simple but grew unwieldy over time. Built on top of a basic table, it handled API integration, filtering, sorting, row selection, custom rendering, and more - all in a single monolithic component.


// Before: A monolithic approach with numerous props and internal state
<BusinessTable
apiId="api-identifier"
apiEndpoint="GET /resources"
customRef={tableRef}
apiParams={params}
additionalActions={<>/* Action buttons */}</>}
selectable="single"
columns={resourceColumns}
pageSize={10}
additionalFilters={<>/* Custom filters */}</>}
// ...many more props
/>

This approach led to several problems:

  • TypeScript errors: Implicit any types and improper generics
  • Prop drilling nightmare: Dozens of props passed through multiple layers
  • Limited customization: Hard to customize just part of the table
  • Maintenance headaches: Changes in one feature affected others
The Solution: Compound Component Pattern


After analyzing the issues, we decided to refactor using the compound component pattern:


// After: A composable approach with specialized components sharing context
<BusinessTable.Provider
apiId="api-identifier"
apiEndpoint="GET /resources"
apiParams={params}
columns={resourceColumns}
>
<BusinessTable.Structure ref={tableRef}>
<BusinessTable.Toolbar>
<BusinessTable.RefreshButton />
<BusinessTable.Filter />
<BusinessTable.Settings />
</BusinessTable.Toolbar>
<BusinessTable.Header />
<BusinessTable.Body />
<BusinessTable.Footer>
<BusinessTable.Pagination />
</BusinessTable.Footer>
</BusinessTable.Structure>
</BusinessTable.Provider>
Key Implementation Steps

  1. Create a Context System: We built a context to share state between components

// Simplified TableContext
export const TableContext = createContext({
state: { rows: [], columns: [], loading: false },
actions: { refresh: () => {}, toggleRowSelection: () => {} },
});

// Type-safe hook
export const useTableContext = <T, K, R>() => {
return useContext(TableContext);
};
  1. Split the Monolith: We broke down the component into specialized parts

BusinessTable/
├── components/ // Specialized components
├── contexts/ // Context system
├── hooks/ // Custom hooks
├── utils/ // Helper functions
└── BusinessTable.tsx // Main entry point
  1. Ensure Backward Compatibility: We maintained the original API while adding the new pattern

// Original monolithic API still works
export const BusinessTable = (props) => {
// Internally uses the compound components
return (
<TableProvider {...props}>
<TableStructure {...props}>{/* Default structure */}</TableStructure>
</TableProvider>
);
};

// Attach compound components
Object.assign(BusinessTable, BusinessTableCompound);
  1. Fix TypeScript Issues: We solved circular dependencies and improved type safety

// Barrel pattern to avoid circular imports
export * from './TableProvider';
export * from './TableStructure';

// Generic types for API integration
export interface TableColumn<T, K, R> extends BaseColumn {
// Type-safe column definition
}
Benefits We've Gained

  1. Better Developer Experience
  • Clear component hierarchy and improved TypeScript support
  • Specialized hooks for API integration
  1. Enhanced Customization
  • Replace only the parts you need
  • Insert custom components anywhere in the structure
  • Style individual components without affecting others
  1. Improved Maintainability
  • Isolated changes don't affect the entire table
  • Easier testing of individual components
  • Better separation of concerns
  1. Type Safety
    • Proper generic types for API integration
    • Eliminated implicit any types
    • Better IDE support with accurate type hints
Key Takeaways for Your Next Refactoring


  1. Context is powerful for sharing state between components without prop drilling


  2. Compound components excel for complex UI elements with many configuration options


  3. Backward compatibility is crucial - don't break existing code


  4. TypeScript generics require careful planning but provide excellent type safety


  5. Barrel pattern helps avoid circular dependencies in a component library

This refactoring pattern can be applied to many complex React components beyond tables - modals, forms, or any component that has grown too large and difficult to maintain.

Have you refactored complex React components? What patterns have you found helpful? Share your experiences in the comments!


Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

 
Вверх Снизу