5 Advanced React Patterns
source link: https://javascript.plainenglish.io/5-advanced-react-patterns-a6b7624267a6
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
5 Advanced React Patterns
An overview of 5 modern advanced React patterns, including integration codes, pros and cons, and concrete usage within public libraries.
Photo by Ferenc Almasi on UnsplashLike every React developer, you’ve probably already asked yourself one of the following questions :
- How do I build a reusable component to fit with different use cases?
- How do I build a component with a simple API, making it easy to use?
- How do I build an extensible component in terms of UI and functionality?
These recurring questions led to some advanced patterns throughout the React community.
In this article, we will see an overview of 5 different patterns. In order to facilitate the comparison, we will use an identical structure for all these patterns :
We will start with a small introduction, following by a real code example (Based on the same simple Counter
component).
All the source code is accessible on this github repository : https://github.com/alex83130/advanced-react-patterns.
We will list the Pros & Cons, then define two factors within a section called “Criteria” :
- Inversion of control: Level of flexibility and control given to the users of your component.
- Implementation complexity: Difficulty for both you and users to implement that pattern.
And finally, we will discover some examples of public libraries using the pattern in production.
During this article we will consider the situation of a React developer (You) building a Component for other developers. Therefore, the actor “users” refers directly to these developers (And not the final user which will use your website/application).
1. Compound Components Pattern
This pattern allows creating expressive and declarative components, without unnecessary prop drilling. You should consider using this pattern if you want to make yourcomponent more customizable, with a better separation of concern and an understandable API.
Example
Github: https://github.com/alex83130/advanced-react-patterns/tree/main/src/patterns/compound-component
Pros
- Reduced API Complexity: Instead of jamming all props in one giant parent component and drilling those down to child UI components, here each prop is attached to the SubComponent that makes the most sense.
- Flexible Markup Structure: Your component has great UI flexibility, allowing the creations of various cases from a single component. For example, the user can change the SubComponents’ order or define which one should be displayed.
- Separation of Concerns: Most of the logic is contained in the main
Counter
component, aReact.Context
is then used to sharestates
andhandlers
all across children. We get a clear division of responsibility.
Cons
- Too much UI flexibility: Having flexibility comes along with the possibility to provoke unexpected behavior (putting an unwanted Component’s child, making out of order the Component’s children, forgetting to include a mandatory child).
Depending on how you want the user to use your component, you might not want to allow that much flexibility.
- Heavier JSX: Applying this pattern will increase the number of JSX rows, especially if you use a linter such
EsLint
or acode formatter asPrettier
.
It seems not a big deal at a single component scale, but could definitely make a huge difference when you look at the big picture.
Criteria
- Inversion of control: 1/4
- Implementation complexity: 1/4
Public libraries using this pattern
2. Control Props Pattern
This pattern transforms your component into a controlled component. An external state is consumed as a “single source of truth” allowing the user to insert custom logic that will modify the default component behavior.
Example
Github: https://github.com/alex83130/advanced-react-patterns/tree/main/src/patterns/control-props
Pros
- Give more control: Since the main state is exposed outside your component, the user controls it and can therefore directly influence your component.
Cons
- Implementation complexity: Before, one integration at a single place (
JSX
) was enough to make your component working. Now it will be spread over 3 different places (JSX
/useState
/handleChange
).
Criteria
- Inversion of control: 2/4
- Implementation complexity: 1/4
Public libraries using this pattern
3. Custom Hook Pattern
Let’s go further in “inversion of control”: the main logic is now transferred into a custom hook. This hook is accessible by the user and exposes several internal logics (States
, Handlers
), allowing him to have better control over your component.
Example
Github: https://github.com/alex83130/advanced-react-patterns/tree/main/src/patterns/custom-hooks
Pros
- Give more control: The user can insert his own logic between the hook and the JSX element, allowing him to modify the default component behavior.
Cons
- Implementation complexity: Since the logic part is separated from the rendering part, it is the user who must link both. A good understanding of how your component work is required to correctly implement it.
Criteria
- Inversion of control: 2/4
- Implementation complexity: 2/4
Public libraries using this pattern
4. Props Getters Pattern
Custom hook pattern
gives great control, but makes also your component harder to integrate because the user has to deal with a lot of native hook’s props and recreate the logic on his side. The Props Getters Pattern
pattern attempts to mask this complexity. Instead of exposing native props, we provide a shortlist of props getters
. A getter
is a function that returns many props, it has a meaningful name allowing the user to naturally link it to the right JSX element.
Example
Github: https://github.com/alex83130/advanced-react-patterns/tree/main/src/patterns/props-getters
Pros:
- Ease of use: Provide an easy way to integrate your component, the complexity is hidden, the user just has to connect the correct
getter
to the right JSX element.
- Flexibility: The user still has the possibility of overloading the props contained in the
getters
to adapt to his specific cases.
Cons:
- Lack of visibility: The abstraction brought by the
getters
makes your component easier to integrate, but also more opaque and “magic”. To correctly override your component, the user has to know the list of props exposed by thegetters
and the internal logic impact if one of them is changed.
Criteria
- Inversion of control: 3/4
- Integration complexity: 3/4
Public libraries using this pattern
5. State reducer pattern
The most advanced pattern in terms of inversion of control. It gives an advanced way for the user to change how your component operates internally.
The code is similar to Custom Hook Pattern
, but in addition the user defines a reducer
which is passed to the hook. This reducer
will overload any internal action of your component.
Example
Github: https://github.com/alex83130/advanced-react-patterns/tree/main/src/patterns/state-reducer
In this example we have assocated the
State reducer pattern
and theCustom hook pattern
but you could also use it with theCompound components pattern
and pass thereducer
directly to the main componentCounter
.
Pros
- Give more control: In the most complicated cases, using
state reducers
is the best way to leave control to the user. All your internal component’s actions are now accessible from the outside and can be overridden.
Cons:
- Implementation complexity: This pattern is surely the most complex to implement, both for you and for the user.
- Lack of visibility: Since any reducer’s action can be changed, a good understanding of the Component’s internal logic is required.
Criteria
- Inversion of control: 4/4
- Integration complexity: 4/4
Public libraries using this pattern
Conclusion
Through these 5 advanced React patterns, we have seen different ways to take advantage of the concept of “inversion of control”. They give you a powerful way to create flexible and adaptable Components.
However, we all know this famous proverb “With great power comes great responsibility” and the more you transfer control to the user, the more your component moves away from the “plug and play” mindset. It is your role as a developer to choose the correct pattern corresponding to the right need.
To help you in this task, the following diagram classifies all these patterns according to the two factors “Integration complexity” and “Inversion of control”:
This article was mainly inspired by the amazing work of
. Take a look at his blog if you are interested in knowing more about each of the patterns. I hope you have found this useful.Thank you for reading.
More content at plainenglish.io
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK