PART3 React Hooks Tutorial for Beginners: can I use render props with React hooks?
Of course! But there’s no point in doing that. Our DataLoader component becomes:
- import React, { useState, useEffect } from "react";
- export default function DataLoader(props) {
- const [data, setData] = useState([]);
- useEffect(() => {
- fetch("http://localhost:3001/links/")
- .then(response => response.json())
- .then(data => setData(data));
- }, []); // << super important array
- return props.render(data)
- }
And you would consume the component by providing a render prop from the outside as we did in the previous example.
But again, there’s no point in this refactoring because React hooks were born for a reason: sharing logic between components, and we’ll see an example in the next section.
React Hooks Tutorial for Beginners: your first custom React hook
Instead of HOCs and render props, we can encapsulate our logic in a React hook and then import that hook whenever we feel the need. In our example we can create a custom hooks for fetching data.
A custom hook is a JavaScript function whose name starts with “use”, according to the React documentation. Easier done than said. Let’s make a useFetch hook then:
- // useFetch.js
- import { useState, useEffect } from "react";
- export default function useFetch(url) {
- const [data, setData] = useState([]);
- useEffect(() => {
- fetch(url)
- .then(response => response.json())
- .then(data => setData(data));
- }, []);
- return data;
- }
And this is how you would use the custom hook:
- import React from "react";
- import useFetch from "./useFetch";
- export default function DataLoader(props) {
- const data = useFetch("http://localhost:3001/links/");
- return (
- <div>
- <ul>
- {data.map(el => (
- <li key={el.id}>{el.title}</li>
- ))}
- </ul>
- </div>
- );
- }
This is what make hooks so appealing: finally we have a nice, standardized, and clean way for encapsulating and sharing logic.
NOTE: I didn’t account for fetch errors in the code above, do your homeworks!
React Hooks Tutorial for Beginners: can I use async/await with useEffect?
When playing with useEffect I wanted to try async/await inside the hook. Let’s see our custom hook for a moment:
- // useFetch.js
- import { useState, useEffect } from "react";
- export default function useFetch(url) {
- const [data, setData] = useState([]);
- useEffect(() => {
- fetch(url)
- .then(response => response.json())
- .then(data => setData(data));
- }, []);
- return data;
- }
For refactoring to async/await the most natural thing you would do is probably:
- // useFetch.js
- import { useState, useEffect } from "react";
- export default function useFetch(url) {
- const [data, setData] = useState([]);
- useEffect(async () => {
- const response = await fetch(url);
- const data = await response.json();
- setData(data);
- }, []);
- return data;
- }
Makes sense right? Then I opened the console and React was screaming at me:

“Warning: An Effect function must not return anything besides a function, which is used for clean-up.” Followed by a complete explanation of what I was doing wrong. How nice!
Turns out you cannot return a Promise from useEffect. JavaScript async functions always return a promise and useEffect should exclusively return another function, which is used for cleaning up the effect. That is, if you were to start setInterval in useEffect you would return a function (we have a closure there) for clearing up the interval.
So for making React happy we could rewrite our asynchronous logic like so:
- // useFetch.js
- import { useState, useEffect } from "react";
- export default function useFetch(url) {
- const [data, setData] = useState([]);
- async function getData() {
- const response = await fetch(url);
- const data = await response.json();
- setData(data);
- }
- useEffect(() => {
- getData();
- }, []);
- return data;
- }
and your custom hook will work again.
React Hooks Tutorial for Beginners: wrapping up
React hooks are a nice addition to the library. Born as an RFC in October 2018 they caught up quickly and landed in React 16.8. Think of React hooks as encapsulated states living outside your React components.
React hooks make render props and HOCs almost obsolete and provide a nicer ergonomics for sharing logic. With React hooks you can reuse common pieces of logic between React components.
React ships with a bunch of pre-defined hooks. The most important are useState and useEffect. useState makes possible to use local state inside React components, without resorting to ES6 classes.
useEffect replaces componentDidMount, componentDidUpdate, and componentWillUnmount providing a unified API. There are a lot of other hooks and I suggest reading through the official documentation for learning more.
It’s easy to foresee where React is going: functional components all over the place! But even then we will have 3 ways for expressing components in React:
- functional components
- class components
- functional components with hooks
I can see a lot of convenience in hooks and I’m happy with the API they provide. It’s amazing how React is evolving, the community seems to find always a clever way out of problems.
React Hooks Tutorial for Beginners: resources for learning React hooks
There are a lot of resources out there for learning about React hooks and admittedly some are better than this post. So here are my suggestions.
The React documentation is your first stop for learning hooks: Introducing Hooks is an high level overview of how and why hooks are here. Hooks at a glance goes a bit deeper and it’s the starting point for understanding hooks in depth.
Dan Abramov came up with a stunning post: a complete guide to useEffect.
Tania Rascia has a nice introduction on hooks with Build a CRUD App in React with Hooks. Speaking of more advanced use cases Matt Hamlin as a nice write up on useReducer, another React hooks for managing state changes.
Funnily enough the way you’ll use useReducer resembles a lot Redux reducers. That’s a proof of how influential Redux is in the React community (that shouldn’t be a surprise since Dan Abramov is behind both Redux and React). I highly suggest learning Redux if you haven’t done yet, it will help a lot before studying useReducer.
React Hooks Tutorial for Beginners: appendix
At the beginning of the article I said: “With jQuery it’s almost impossible to clearly structure a project, let alone defining how the data should flow across the UI”.
And:
“The same applies to plain JavaScript: even if with self-disclipine and practice it’s possibile to come up with a well structured project, good luck tracking application’s state.”
But you might not need React for building user interfaces. Sometimes I build projects with vanilla JavaScript and here I am, doing fine. I use to create a simple prototype without any JavaScript library when I’m not sure what shape the project will take.
In these kind of projects I rely on the module pattern for organizing the code.
Being able to properly organise and document your code, even with vanilla JavaScript is a valuable asset for every JavaScript developer. For learning more about the module pattern in JavaScript I suggest reading Mastering the module pattern by Todd Motto and JavaScript design patterns by Addy Osmani.
Tracking state changes in the UI is really hard on the other hand. And for this kind of job a lot of libraries had born and die. One of my favorite is Redux and it can be used even with vanilla JavaScript.
Thanks for reading! See you next time!