React.js, one of the most popular JavaScript libraries around, has released version 16.8.0, which includes official support for Hooks.
React now has over 100 releases, more than 130,000 GitHub stars, 2 million-plus projects, and a host of dedicated community members making life easier for developers building amazing user interfaces.
Stable support for Hooks
Hooks are functions that let you “hook into” React state and lifecycle features from function components. Hooks let you use state and other React features without writing a class, as they do not work inside classes. A simple example of the use state hook looks like this:
import React, { useState } from 'react';
function Example() {
// Declare a new state variable, which we'll call "count"
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
In this article, Hooks will not be treated in earnest, but instead you will be shown the motivation behind Hooks, demystifying Hooks, and their advantages.
Why Hooks?
React’s core team hinted at a few problems people tend to face over time while building applications with React. Most of them seem unconnected at first but are all valid:
Difficulty of reusing stateful logic
By default, there was previously no clear way to attach attach a reusable behavior to a React component. You have patterns like using render props and higher-order components to try and hack this, of course, but you end up changing the component’s structure any time they are used.
This almost always leads to clumsy code presentation and, by inheritance, causes the code to become borderline illegible. A typical React application will contain wrappers of components containing providers, consumers, HOCs, and many other concepts that are mostly abstract.
DevTools and linting can help break most of it down, but React needs a kind of root-level concept for sharing stateful logic. Hooks fit in perfectly here, and you can extract stateful logic from a component so it can be tested independently and reused. You can learn more about building your own Hooks here.
Complex components become hard to understand
A good illustration is the use of lifecycle methods: you know how logic can be passed from one method to another, or how only computations can be done in a method only to be used in another method.
In the process of consuming these methods, a lot of unrelated logic, from little things like console.log
messages to larger things like event listeners, can be introduced. This makes it more likely that the next developer to work on the code — or even the original author — will become confused at some point.
Imagine maintaining components that started out simple but grew into an unmanageable mess of stateful logic, side effects, and, of course, bugs. In many cases, it’s not possible to break these components into smaller ones because the stateful logic is all over the place, making unit testing hard.
Hooks also helps to solve this exact problem because you can split one component into smaller functions based on what pieces are related to what.
Classes are sometimes confusing
Remember how unintuitive it was for you to understand classes in React when you first started to use it? A lot of developers just starting out still do not fully grasp how this
works in JavaScript; it does not help that it differs from language to language.
Other good examples are the differences between and when to use what arguments for functional and class components in React, which further shows just how confusing classes can sometimes be.
It gets worse: even machines (i.e., compilers) find classes confusing most times. Take minifiers, for example. The React team reports that classes do not minify well and sometimes even make hot reloading flaky and unreliable. Hooks as a solution provides a platform to let you use React features, but without classes this time.
Getting started with React v16.8
To get started, you have to install the new version 16.8 with your favorite registry. To install React 16 with Yarn, run:
yarn add react@^16.8.0 react-dom@^16.8.0
To install React 16 with npm, run:
npm install --save react@^16.8.0 react-dom@^16.8.0
UMD builds of React are also accessible through a CDN:
<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
Refer to the documentation for detailed installation instructions.
Now that you have been inspired to try out React Hooks, here are some resources to get you started on trying it them:
- Introducing Hooks, from the official docs
- A video introduction by Dan Abramov
- useHooks.com, which showcases Hooks recipes and demos from React community members
Important to note
- Hooks do not yet cover all the use cases for classes, although the React team is working towards that eventually. There are no Hook equivalents to the
getSnapshotBeforeUpdate
andcomponentDidCatch
lifecycle methods yet. - Popular APIs like redux-connect and react-router will continue to work, but there are plans in place for custom Hooks like
useRedux()
oruseRouter()
that will not require wrapper components. - Static typing works with Hooks because they were designed with them in mind.
Linting rules for Hooks
React now has an ESLint plugin that enforces the rules of Hooks to avoid bugs and makes you, the developer, follow the convention. First, the plugin flags any function that starts with “use” and a capital letter following it as a Hook. These rules are:
- Hooks cannot be called from regular function; only from functional components.
- Hooks are to be used only at the top level of your functional component and not inside nested functions or even conditional statement blocks.
The popular create-react-app boilerplate already integrates this plugin in all the React applications bootstrapped with it.
Can I use Hooks right away?
Yes! Starting with 16.8.0, React includes a stable implementation of React Hooks for React DOM, React DOM Server, React Test Renderer, and React Shallow Renderer. React Native will support Hooks in the 0.59 release.
Testing Hooks
The React team added a new API called ReactTestUtils.act()
in this release. It ensures that the behavior in your tests matches what happens in the browser more closely. It is recommended to wrap any code rendering and triggering updates to your components into act()
calls. Testing libraries can also wrap their APIs with it.
For example, the counter-example from this page can be tested like this:
import React from 'react';
import ReactDOM from 'react-dom';
import { act } from 'react-dom/test-utils';
import Counter from './Counter';
let container;
beforeEach(() => {
container = document.createElement('div');
document.body.appendChild(container);
});
afterEach(() => {
document.body.removeChild(container);
container = null;
});
it('can render and update a counter', () => {
// Test first render and effect
act(() => {
ReactDOM.render(<Counter />, container);
});
const button = container.querySelector('button');
const label = container.querySelector('p');
expect(label.textContent).toBe('You clicked 0 times');
expect(document.title).toBe('You clicked 0 times');
// Test second render and effect
act(() => {
button.dispatchEvent(new MouseEvent('click', {bubbles: true}));
});
expect(label.textContent).toBe('You clicked 1 times');
expect(document.title).toBe('You clicked 1 times');
});
The calls to act()
will also flush the effects inside of them. If you need to test a custom Hook, you can do so by creating a component in your test and using your Hook from it.
Also, to reduce boilerplate code, it is recommended to use react-testing-library
, which is designed to encourage writing tests that use your components as the end users do. You can view the complete changelog for this new version here.
Conclusion
You have now been introduced to the new version of React.js, which shipped with stable support for React Hooks. The motivation that led to the adoption of this new way of approaching writing React code has also been illustrated. Give Hooks a try today — happy hacking!
Plug: LogRocket, a DVR for web apps
LogRocket is a frontend logging tool that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.
In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page apps.
The post Introducing React 16.8, featuring official support for Hooks appeared first on LogRocket Blog.
Top comments (0)