What are React Hooks? An Intro to Reusing Logic in React
In this lesson, we discuss the motivation behind React Hooks and see a few examples of how React Hooks can help share logic between our React components.
Get the project source code below, and follow along with the lesson material.
Download Project Source CodeTo set up the project on your local machine, please follow the directions provided in the README.md
file. If you run into any issues with running the project source code, then feel free to reach out to the author in the course's Discord channel.
This lesson preview is part of the TinyHouse: A Fullstack React Masterclass with TypeScript and GraphQL course and can be unlocked immediately with a single-time purchase. Already have access to this course? Log in here.
Get unlimited access to TinyHouse: A Fullstack React Masterclass with TypeScript and GraphQL with a single-time purchase.
[00:00 - 00:23] In our React introduction lesson, one note we made was how components in React can be created with either a class or a function. Traditionally, React required us to create components with classes to use state within a component, or to be able to use other certain React features like lifecycle methods.
[00:24 - 00:37] Container components were often stateful and responsible in defining and providing data to presentational components. Presentational components rarely had its own state and were more concerned with how the UI was to look.
[00:38 - 00:53] Container components were more often class components while presentational components were more often functional components. And from this, a popular pattern emerged for having components be divided into these two categories, container and presentational.
[00:54 - 01:10] There were variations to this approach, but as of late, Dan Abramov, one of the core React team members, doesn't suggest splitting components with the container and presentational pattern anymore. And this is in large part due to the presence of a new React feature called Hooks.
[01:11 - 01:28] Now before we talk about Hooks, let's address and discuss some other advanced patterns that also emerged to handle state logic reuse between components. Some of these patterns were the higher order component pattern and the render props pattern.
[01:29 - 01:49] Higher order components were functions that take a component and return a new component with additional data or functionality. Render props basically involves having props whose value is a function where the component calls the prop function to return the React element instead of implementing its own logic.
[01:50 - 02:09] Both higher order components and render props emerged within the React community to handle components of logic reuse. Though both of these patterns do help abstract shared logic, they tend to make components and underlying components a lot more complex and difficult to understand.
[02:10 - 02:27] So Dan Abramov summarized the above issues to be symptoms of a certain particular problem. Lastly coded, React doesn't provide a simpler, smaller primitive to adding states or lifecycle than a class component.
[02:28 - 02:44] Class components are difficult to split up unless more complicated patterns are used, which can then lead to something often labeled as "Rapper Hell" where component declarations are wrapped over one another multiple levels deep. This is where Hooks come in.
[02:45 - 03:05] React Hooks aims to solve the difficulties of logic reuse by enabling us to write functional components that have access to features like state, context, lifecycle methods, the ref without writing a class component. Let's see an example of a React Hook.
[03:06 - 03:14] We'll use the simplest Hook responsible in allowing function components to contain state. We'll use the use state hook.
[03:15 - 03:38] In traditional class-based React components with the stable JavaScript syntax, creating a class component that keeps track of states will look something like the following. Here we have a count state property be created with an initial value of zero, and we have component methods that call the component setState function to update the count property.
[03:39 - 03:59] This component here renders two buttons where each button when clicked either increments or decrements the count state property where the count state property is being rendered and shown in the UI. The equivalent of this with the useState hook in a function component will look something like the following.
[04:00 - 04:23] We declare the useState hook at the top of the function components and we pass in the initial value of zero, we destruct the count and setCount properties, count is rendered as part of the component template, and the component functions use the setCount function property to update the count state property. Notice how much easier and more legible this is?
[04:24 - 04:39] This is compounded even further when we introduce other hooks for other specific features we'd want in a component. Hooks essentially allow us to split a component into smaller functions that can easily be reused between components.
[04:40 - 04:48] The ability to create custom hooks makes sharing logic between components incredibly intuitive. Here's an example.
[04:49 - 05:03] Let's take a look at the counter function component we had before that facilitated the capability to increment and decrement a number counter. Assume we had another component that also wanted to implement a very similar counter.
[05:04 - 05:27] We could replicate the imported bits of code such as the initialization of the state property and the functions to increment or decrement the count state property or what we could do instead is create a custom hook that consolidates the logic responsible for the counter. We can call this custom hook the useCounter hook.
[05:28 - 05:54] It can accept an initial state value and it can use that value in a useState hook. It can then set up increment and decrement functions responsible in updating the count state property and at the end of the useCounter hook it can simply return the information a component may need such as the count state value itself and the increment and decrement functions responsible in increasing or decreasing the count value.
[05:55 - 06:12] All a component needs to do is declare the useCounter hook at the very beginning, pass in the initial value of the count property and destruct and use the properties given to it by the useCounter hook. These properties here are actually part of the counter component.
[06:13 - 06:26] The useCounter hook simply abstracts the setup away so the counter or any other component doesn't explicitly have to define the state property and the functions again. That was pretty easy right?
[06:27 - 06:47] Though the useCounter hook is a simple example it goes to show how effective hooks are when it comes to reusing a logic between components. We'll be taking a better deep dive as we start to introduce hooks in the next coming lessons but here's a few pointers and good to knows of using hooks.
[06:48 - 07:02] Custom hooks are essentially functions that call other hooks. As a best practice custom hooks should always be denoted with the term use before the hook name, example useCounter.
[07:03 - 07:17] When a component declares the hook it's good to think of the component using the hook. We should only call hooks at the top level of components and we should only call hooks from react functions not native JavaScript functions.
[07:18 - 07:28] There are no breaking changes with the emergence of hooks. Hooks are entirely opt in and the React team has no plans of removing the class based syntax.
[07:29 - 07:38] We're simply encouraged by the React team to start to introduce hooks in new components that we plan on creating. And this is what we're going to be doing in the course.
[07:39 - 07:55] Throughout the course we're going to use function components and we're going to use hooks to achieve the outcome we intend to have. In the next lesson we'll take a deeper dive into the use state hook and see how we can use it in our application to keep component states.