S.Kraus
S.Kraus

Reputation: 389

When and how to choose between React Hooks and old HOC props passing?

Until now we were used to Flux flow where data entered into the component through props. So you could look at the Props signature and see what is the component requirements.

Hooks are an amazing feature, but as we transition to them I find that they provide another entrance for dependencies which is harder to manage since you have to look at the actual component code to see it.

Of course, we can use Hooks only in container components, but I feel that some of their main selling points are their ability to reduce nesting and HOC.

What are the best practices (currently) for deciding which component should use a hook and which should use render props?

Upvotes: 17

Views: 6391

Answers (4)

Lin Du
Lin Du

Reputation: 102407

HOC is some kind of AOP, AOP can solve cross-cutting concerns.

React Hooks is not AOP, from Rules of Hooks, hooks can only be used in the following ways:

  • Call Hooks from React function components.
  • Call Hooks from custom Hooks

Both of them follow the separation of concerns design pattern.

react hooks provide a component lifecycle hook useEffect, so you can create reused custom hooks based on the component lifecycle hook useEffect and other built-in hooks.

HOC is more flexible, from the doc:

You may have noticed similarities between HOCs and a pattern called container components. Container components are part of a strategy of separating responsibility between high-level and low-level concerns. Containers manage things like subscriptions and state, and pass props to components that handle things like rendering UI. HOCs use containers as part of their implementation. You can think of HOCs as parameterized container component definitions.

And let's use an example to explain cross-cutting concerns.

If you have a reused react custom hook called useGetEnumsQuery(), and you have ten components will use it. You need to import and call the hook ten times.

Now, you create a HOC named withEnums() you can call the useGetEnumsQuery() hook in the HOC once and pass the enums to the wrapped components via props.

HOC is react component as well. If we put too much code logic in HOC, it doesn't follow the separation of concerns design pattern. So we can create several react custom hooks to encapsulate different logic.

So in my opinion, If there are more than 3 components using the same logic, I will use HOC + react custom hook.

HOC helps me solve the repeated import and call hook in each component issue mentioned above. React custom hook helps me separate components and logic.

HOC and react hooks are not conflicting, they should be used in combination.

An example:

import React, { useCallback, useMemo, useState } from 'react';

const MaskContext = React.createContext({ visible: false, show: () => {}, hide: () => {} });

// Abstract a "mask" view model using a react custom hook.
const useMask = () => {
  const [state, setState] = useState(false);
  const hide = useCallback(() => setState(false), [setState]);
  const show = useCallback(() => setState(true), [setState]);
  return useMemo(() => ({ visible: state, show, hide }), [state, show, hide]);
};

// HOC, pass the context value to the wrapped component without modifying it.
const WithMask = (WrappedComponent) => {
  const mask = useMask();
  return () => (
    <MaskContext.Provider value={mask}>
      <MaskContext.Consumer>{(value) => <WrappedComponent mask={value} />}</MaskContext.Consumer>
    </MaskContext.Provider>
  );
};

const MyComp = ({ mask }) => {
  return <button onClick={mask.show}>click me!</button>;
};

const MyCompWithMask = WithMask(MyComp);

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

Upvotes: 1

DerMambo
DerMambo

Reputation: 678

One thing I see often is to use hooks with side effects in a component. That makes your component harder to test and is not a good use case for hooks imho.

For example you create a component with some custom const {data, loading, error} = useFetch(endpointUrl) and then directly use it in the render part return <>{data.name}</> of the same component.

This, for me, is still a use case for a HOC. Load the data in a HOC, provide it as properties to your still dump component. This way you can test the component easier and you still separate concerns.

Upvotes: 1

Edan Chetrit
Edan Chetrit

Reputation: 5081

Hooks and HOCs are different programmings models, and comparing them will seem to be as comparing oranges and apples.

TL;DR

As a rule of thumb, I use HOCs when I want a conditional rendering of components (if condition: render A, else render B), otherwise, I use hooks. That's only my opinion.

Pros & Cons:

HOCs Pros

  • Easily separate all logic from the UI component (see recompose).
  • Easy to compose.
  • Manipulate component before any render.

HOCs Cons

  • Name clashes - 2 HOCs can use and set a prop with the same name.
  • React dom is gigantic.
  • Every change in the parent props caused the children to rerender - which is the default behavior in React but when we have many HOCs we need to be very careful.
  • Types - From the component point of view, it is difficult to understand which props and types we are getting.
  • Using a HOC will pass all the props to the child, even if the child needs from that specific HOC only the prop x.
  • The process of using an argument that depends on a component's props for the HOC can be complicated

HOCs Pro & Con both

  • No need to define variables, just wrap with a HOC and you'll get the props the HOC supplying - which makes our UI component "guess" the names of the props.

Hooks Pros

  • Readable & declarative.
  • Performance - updates only when specific props are changed.
  • Growing community.

Hooks Cons

  • Only within the component - which means cannot render component by a condition of props that are passed.
  • Giant component files which contain UI & logic altogether.

Upvotes: 9

Shubham Khatri
Shubham Khatri

Reputation: 281834

And according to the React FAQs hooks can be used as an alternative to renderProps and HOCs, but can coexist with them

Often, render props and higher-order components render only a single child. We think Hooks are a simpler way to serve this use case. There is still a place for both patterns (for example, a virtual scroller component might have a renderItem prop, or a visual container component might have its own DOM structure). But in most cases, Hooks will be sufficient and can help reduce nesting in your tree.

Hooks allow stateful logic in functional components and would be similar to class components in React.

Hooks are harder to manage since you have to look at the actual component code to see it.

Not really, since you can pull out the custom logic that you have in your HOCs or renderProps in a custom hook and look for its implementation instead of understanding what actually is going on in the actual component.

Upvotes: 6

Related Questions