To eliminate those challenges, solutions like MIXINs, High Order Components, and Render Props were introduced, but they led to other problems:
- Render Pops lead to large a size of the code, and that’s why it is hard to use
- MIXINs and components can have hidden dependencies, which may cause conflicts
- High Order Components can be multilayered and minimized into added components, which leads to increased complexity to understand
To solve the aforementioned problems, technologies like Hooks in React and Composition API in Vue were developed.
From the very beginning of React’s existence, the class components based on classes were used. Classes ensured availability of a state, allowed to subscribe to lifecycle events of the component, and many more. There were also functional components, but they were commonly used only for markup description because they didn’t have access to the state or methods of a lifecycle.
Class components looked as followed: the class was written for each component, which was inherited from the React. Component class and it was possible to implement the methods of a lifecycle in it and describe how the component should change after changes in props and state.
Since version 16.8, functional components are able to access methods of the lifecycle. It became possible thanks to hooks.
At the moment, class components still exist, are in use, and will be supported in the future. However, today, functional components are becoming more popular each day.
In Vue, before version 3, Options API was used. It allowed doing everything that React with the help of Class Component can. Options API opened numerous possibilities to the developers, but it had similar problems, as with React before the Hooks.
Sooner or later components became heavy, unreadable, or hard to read because it was hard to decompose and highlight the logic inside the component, especially the one related to the state. However, if the developers of Vue are to be believed, they were inspired by React Hooks and created the Composition API, which solves these problems.
Motivation: Separation of concerns
Currently, React doesn’t have the possibility of repeatable usage of particular logic, except in the ways we explained above. But even those ways result in multiple problems, which hooks are designed to solve. Thanks to hooks, we can isolate the logic by monitoring the state and using it in other components.
In some cases, it is necessary to divide one component into a few smaller ones, but due to logic being scattered in multiple places it becomes hard to achieve. The usage of hooks allows us to divide a big component into small functions according to their roles. Additionally, while using class components, we should understand how ‘this’ context works and how to link the context to the event handlers.
Let’s look at the small example. We will create a basic product counter. We will start with an option of the class component. At first, we need to have a variable in which we will write the number of products. This variable should have its own state, so we need to create one.
To change the state, we need to use the function setState. Methods ‘add’ and ‘remove’ will change our counter. To use methods or state of the counter, we must address it using ‘this’.
Now let’s rewrite our counter using a functional component. To write the state of the counter and the possibility to change it, we will use the hook useState. After addressing this hook, we will receive an array of two elements - the current value of the state and the function for its renewal. This hook accepts an initial value as an argument, in our case, we will set 0 as an initial value of our counter.
As you see, in the functional component, we no longer need to follow the content. We instantly use our variables and functions when we need them. This simplifies the development and testing of our components.
The rules of hooks
There are two main rules for the usage of hooks:
- Always use hooks only on a high level. Don’t call hooks in the middle of cycles, conditionals, and nested functions
- Use hooks only inside of React functions (functional component React), before receiving values from them. Don’t use hooks on ordinary functions. You can also call hooks from custom hooks (hooks that we created)
Main hooks review
- useState - is used for controlling the state. This hook returns the current value of the state and function for its renewal
- useEffect - is used for controlling side effects, such as mutations, timers, subscriptions, logging, and others
- useContext - this hook receives contexts and returns the current value of context for this context
- useReducer - this is an alternative to useState. You should use this hook when you have a complex state logic that includes multiple values, or when the next value is dependent on the previous one
- useCallback - returns a memoized callback. It helps the child component to not execute rendering without the necessity
- useMemo - returns memoized value. This hook will calculate the value repeatedly only when one of the values in dependencies changed
- useRef - returns the object of reference which includes the property ‘current’. Usually, it is used for accessing child elements in the imperative style
- useLayoutEffect - an analog of useEffect, but this hook starts in sync only after all changes in DOM. If it is possible, it is recommended to choose useEffect instead
- useDebugValue - helps to display the label in ReactDevTools for custom hooks
Also, for certain instances, when we want to separate a particular repeated logic, we have an opportunity to create our own hook. A custom hook is a JS function, that needs to begin with the word ‘use’, and a function that allows executing other hooks in it. You will find more information about hooks here.
Options API allows us to arrange our code, and make it clean and easy to read. Ultimately, it gives us a feeling that everything is in its place. However, when our codebase becomes bigger, this feeling disappears, leaving us with the mess in our components. Different parts of code in the components, which are logically connected, end up in entirely different places, which makes understanding and supporting of the code more complex than it should be.
Vue Composition API is a set of additional API interfaces which are based on functions. Composition API allows the creation of abstract, portable, and loosely connected components that can be reusable.
Let’s look at the additional API interfaces that Composition API unlocks for us:
- Reactivity API - allows the creation of a reactive computational state and observers. You can find more details about this here.
- Lifecycle Hooks - allows accessing the lifecycle of a component. More details here.
- Dependency Injection - allows us to use the dependency injection Vue system. Check out more information about this here.
In order to create a component based on Composition API, we need to add ‘setup()’ function. We can create reactive variables and functions to control them inside the component. We will need functions with Reactivity API - ref(), reactive(), computed(), etc. To make our variables and functions accessible in other parts of our components, we need to recall them from ‘setup()’ function. Let’s create a component of a counter as an example.
The advantages of React Hooks and Composition API
1. Easier to reuse stateful logic, and separate concerns
The main advantage of using React Hooks and Vue Composition API is the fact that they allow reusing stateful logic. To achieve that, React and Vue allows us to extract logic with monitoring of the state and use it again in our other custom hooks that we will be able to use in other components.
You can use logic repeatedly with monitoring the state and share custom hooks with other components without changing the hierarchy of the components. Let’s review an example in which we will create our custom React Hook.
Let's create a custom hook for Vue Composition API as well:
2. No “this” binding (for React only)
While working with React, we face controlled components and event handlers. If we want to access the component through the handler, we need to tie our function to the instance of the component. There are multiple ways to solve this:
- to tie our method with the help of bind() in the constructor of our component or in the render() method
- to use the Arrow function in the class or directly in the render() method
However, if we use React Hook we don’t need to look for our context anymore, and we can use our functions in the event handlers right from the start.
3. Easier to write unit tests
Testing is one of the principal aspects of any product or application. If we need to test a component that consists of multiple HOCs, we need to test everything together. In this scenario, test cases end up being too bulky. On the other hand, using React Hooks and Vue Composition API makes the testing process similar to any other function.
4. Optimization: Hooks might reduce your bundle size
Thanks to functional components and the usage of React Hooks and Vue Composition API, our code becomes more optimized from the size standpoint. This code has a higher tendency to optimize compared to equivalent code, which uses classes or Options API.
To calculate the size of our bundle, we will use our previous React example with a counter of products. We will begin by calculating the class component:
After that, we will calculate the functional component:
As you see, our bundle became 236B lighter, which proves that the usage of functional components really makes our code more optimized.
5. The bright future of React
Hooks will work better with the future optimizations of React, because the development team will improve this technology even further in the future. The React team will support class components, if your project has a lot of them, but recommends using hooks in the new code.
6. Improves the definition of types (for Vue only)
As we mentioned in our previous article, the popularity of TypeScript among developers is rising. But Options API was created in 2013, without the consideration of type derivation. This led to forcing developers that wanted to use TS in Vue to choose Class API instead.
The Vue team decided not to add Class API to Vue 3 due to instability and other problems with Class API. Composition API, on the other hand, use mostly simple variable and functions, which work great with types.
Don’t know where to start?
We will advise you on the best way to realize your idea, leveraging our expertise
7. Existing libraries
The main advantage of Composition API is the effective re-usage of logic. Composition API eliminates the drawbacks of MIXIN, which were used in Options API for this purpose. It opened the door for creating such projects as VueUse, a collection of utilities for Vue Composition, and for integration of third-party services and libraries for monitoring the state.
Few drawbacks of React Hooks and Composition API
1. Requires time to get into it
React Hooks and Vue Composition API are relatively nascent technologies, and proper implementation in practice requires time to figure them out, understand, and get some practice. A lot of developers just don’t want to do that and think they are saving their valuable time.
2. Possible problems with asynchronous operations (in React Hooks)
When we use asynchronous operation, we might face the problem that links to variable asynchronous callbacks are previous, i.e. obsolete. Here is an example:
When we push the button that calls setTimeout, and after that, we push the button that increases our counter, after the expiration of a timeout in a modal window we will see the old value of our counter - 0, while the actual value is 1.
The solution is simple, we need to use useRef hook. We save our value ‘count’ in ‘counterRef.current’.
3. Destructurization in Composition API
If we destructurize reactive objects, we will receive no reactive data. So, we need to use toRefs().
React Hooks and Composition API improved the possibility to reuse the code significantly, made readability better, and testing process easier. Additionally, they allowed to leverage functional components to the max.
There is no doubt, that React Hooks and Composition API have far more advantages than disadvantages. However, you should always consider the drawbacks while creating your product.
The development teams of React and Vue will evolve and improve these technologies, so, it is a great time for you to learn them and start implementing them in your projects!
Table of contents:
Want to estimate your app idea?