Avoid high-order components hell in React

Hello everyone. In this article I will focus on what the best way is, in my opinion, to handle “components cascade” in React. Using this approach, your application will be well organized and you’ll make it more readable and easier to maintain.

impor…


This content originally appeared on DEV Community and was authored by Elias Júnior

Hello everyone. In this article I will focus on what the best way is, in my opinion, to handle “components cascade” in React. Using this approach, your application will be well organized and you’ll make it more readable and easier to maintain.

import AppRoutes from 'src/components/AppRoutes';
import store from 'src/store/store';
import theme from 'src/styles/theme';

import { ChakraProvider } from '@chakra-ui/react';
import { QueryClient, QueryClientProvider } from 'react-query';
import { Provider } from 'react-redux';
import { BrowserRouter } from 'react-router-dom';

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      cacheTime: 0,
      retry: false,
      refetchInterval: false,
      refetchOnMount: false,
      refetchOnReconnect: false,
      refetchOnWindowFocus: false,
    },
  },
});

const App = () => {
  return (
    <ChakraProvider theme={theme}>
      <QueryClientProvider client={queryClient}>
        <Provider store={store}>
          <BrowserRouter>
            <AppRoutes />
          </BrowserRouter>
        </Provider>
      </QueryClientProvider>
    </ChakraProvider>
  );
};

export default App;

Looks like hell, doesn't it? But imagine that you have even more providers, or these providers have many properties that you need to include.

But, what is the problem? I have some points here:

  1. You can’t use the useLocation() hook in the App component, because you’re including the BrowserRouter on the same component, so you can only use the hook in a child component.
  2. You may face some conflicts when importing multiple providers from many libraries (or even your own code). So you will need to rename import { Provider as ReduxProvider } from 'react-redux’ for example.
  3. When you want to remove a provider, your commit will have many changed lines in your code, because your editor will reindent all child components at least 1 column to the left.

I could point out other problems here, but I think that’s enough.

The solution

We have a technique in React for reusing component logic. It’s called high-order component (the HOC). It’s basically a function what will wrap your component with any other component that you want.

Create a generic type for HOCs

So if we are looking to make reusable components, we need to create a type definition for our HOCs (only if you’re using Typescript):

export interface ReactHoc {
  <P>(WrappedComponent: React.ComponentType<P>): React.FC<P>;
}

Don’t panic! Let me explain what is happening here:

  • Line 1: we are declaring the interface ReactHoc;
  • Line 2: <P> declares that we will receive some param of type P (any type) - this is because we don’t know what property the React component will have;
  • Line 2: (WrappedComponent: React.ComponentType<P>) we are receiving a param WrappedComponent that has the type React.ComponentType<P>, a React Component with the P params.
  • Line 2: React.FC<P> we are returning a new React functional component with the same params as our WrappedComponent.

Yes, it’s a little difficult, but you will get used to working with Typescript typing. If you don't understand that now, you will later, don’t worry.

Create your first HOC

Now for the easy part! Let’s create our React Redux HOC:

import store from 'src/store/store';
import { ReactHoc } from 'src/types/hocs';

import { Provider } from 'react-redux';

const withRedux: ReactHoc = (Component) => (props) =>
  (
    <Provider store={store}>
      <Component {...props} />
    </Provider>
  );

export default withRedux;
  • Line 6: we are declaring the function name. It will have the type of the ReactHoc, a function that will receive a component and will return another React component.
  • Line 8: we add the Redux provider, as we did before;
  • Line 9: now we need to render the component we want to wrap, passing all parameters to it.

You will need to create other HOCs for the other providers: withChakraUi, withReactQuery, withReactRouter ...

And in the end, you will need to compose your app with all that HOCs. For that, I like to use the Recompose library. It has other powerful uses, but for now we will use only the compose.

import AppRoutes from 'src/components/AppRoutes';
import withChakraUI from 'src/hocs/with-chakra-ui';
import withReactQuery from 'src/hocs/with-react-query';
import withReactRouter from 'src/hocs/with-react-router';
import withReactSuspense from 'src/hocs/with-react-suspense';
import withRedux from 'src/hocs/with-redux';

import { compose } from 'recompose';

const App = () => {
  return <AppRoutes />;
};

export default compose(
  withChakraUI,
  withReactSuspense,
  withReactRouter,
  withReactQuery,
  withRedux,
)(App);

Your App component is now clean and beautiful! If you need to remove the redux, you just need to remove the withRedux and it’s done! One line in your commit (actually two, as you will need to remove the import line 😁)

Make good use of what you have just learned and leave your comment or question below. And if you liked, please like and share.


This content originally appeared on DEV Community and was authored by Elias Júnior


Print Share Comment Cite Upload Translate Updates
APA

Elias Júnior | Sciencx (2021-10-09T03:21:49+00:00) Avoid high-order components hell in React. Retrieved from https://www.scien.cx/2021/10/09/avoid-high-order-components-hell-in-react/

MLA
" » Avoid high-order components hell in React." Elias Júnior | Sciencx - Saturday October 9, 2021, https://www.scien.cx/2021/10/09/avoid-high-order-components-hell-in-react/
HARVARD
Elias Júnior | Sciencx Saturday October 9, 2021 » Avoid high-order components hell in React., viewed ,<https://www.scien.cx/2021/10/09/avoid-high-order-components-hell-in-react/>
VANCOUVER
Elias Júnior | Sciencx - » Avoid high-order components hell in React. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2021/10/09/avoid-high-order-components-hell-in-react/
CHICAGO
" » Avoid high-order components hell in React." Elias Júnior | Sciencx - Accessed . https://www.scien.cx/2021/10/09/avoid-high-order-components-hell-in-react/
IEEE
" » Avoid high-order components hell in React." Elias Júnior | Sciencx [Online]. Available: https://www.scien.cx/2021/10/09/avoid-high-order-components-hell-in-react/. [Accessed: ]
rf:citation
» Avoid high-order components hell in React | Elias Júnior | Sciencx | https://www.scien.cx/2021/10/09/avoid-high-order-components-hell-in-react/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.