4

React Hooks: Mastering the useState Hook in React

 1 year ago
source link: https://blog.bitsrc.io/mastering-the-usestate-hook-in-react-de5e42782a32
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.
neoserver,ios ssh client

React Hooks: Mastering the useState Hook in React

1*cXQRKwqZT_pU5cD5gL4v3Q.jpeg

Intro

Hooks were introduced in React 16.8 version. This magical React update made classes nearly obsolete and thus many developers have been using hooks since and are not looking back.

In this article, you will learn:

  • What are hooks
  • Basics of useState Hook
  • Storing functions and using the previous state
  • Lazy initial state
  • Bailing out of a state update
  • Prop Drilling state setters
  • Using useState Hook with TypeScript
0*-imohODXdYQt5Xev.gif

Follow to see future articles

What are Hooks?

A Hook is a special function that lets you add some state to a functional component.

A few bullet points to get started. Hooks:

  • are functions
  • are imported from React package e.g. import { useState } from “react”;
  • let you use React state and lifecycle features from function components.
  • do not work inside classes

If you or your company developed an app in React and used only classes, it is not a big concern as React team has no plans to remove classes from React, especially because they are still using classes to this day in their projects.

Hooks let you extract stateful logic from a component. You can reuse stateful logic without changing your component hierarchy. This means you can create hooks and share them among multiple components.

Hooks do not reinvent React concepts as It is just a powerful way to combine props, state, lifecycle, refs, and context concepts and reimagine them.

A colossal mistake for junior developers is writing huge components full of code, which will make the code base harder to read and understand for a new team member. Hooks let you split those components into smaller functions e.g. fetching data.

The Rules of React Hooks

  • Call Hooks only from React function components and your custom Hooks
  • Call Hooks only at the top level. Calling them from inside loops, conditions or nested functions will break your web application. This is because Hooks must be predictable and conditions break those predictions

A good linter plugin recommended by React team is here linter plugin.

useState Hook Basics

It Is probably the most used Hook in React. This Hook allows us to track the state in a function component.

A state refers to data or properties that need to be tracked in an application. It could be a simple integer, string, array of objects, etc. A simple use case is shown below:

import React, { useState } from "react";

const UseStateHookExample = () => {
const [count, setCount] = useState(0);

return (
<div>
<p>You clicked this button {count} times</p>
<button onClick={() => setCount(count + 1)}>Click me for magic</button>
</div>
);
};

This component creates a button that tracks how many times a user clicked this button and displays It.

In line 4, we declare our Hook. A few things to know are:

  • By calling useState Hook, we declare a “state variable”. It can be named in any word you want, not just “count”.
  • We only need to give one argument to useState Hook. In this case, we gave it a zero. This will be our starting variable.
  • useState hook returns “count” and “setCount” values. “Count” is our reactive variable which we can render in our return function. “setCount” is a function that updates “count” variable in an instant.
  • When the setState function is used, our component re-renders.
  • The returned values are in “[ ]” brackets because we are using “array destructuring”. You could also do this, but shouldn’t:
const UseStateHookExample = () => {
const count = useState(0);

return (
<div>
<p>You clicked this button {count[0]} times</p>
<button onClick={() => count[1](count[0] + 1)}>Click me for magic</button>
</div>
);
};

However, the best way to update a state is shown in the next section.

Storing Functions and Using Previous State

This Hook is so good at storing values that it remembers a previous value too. If the new state is computed using the previous state, we can pass a function to useState Hook like this:

const CounterExample = ({initialCount}) => {
const [count, setCount] = useState(initialCount);
return (
<>
Count: {count}
<button onClick={() => setCount(initialCount)}>Set count to initialCount</button>
<button onClick={() => setCount(prevCount => prevCount - 1)}>-</button>
<button onClick={() => setCount(prevCount => prevCount + 1)}>+</button>
</>
);
}

Another example would be if we had an object as the initial state and wanted to update only one parameter in it. We can use the JavaScript spread operator to help us like this:

const UserInformation = () => {
const [user, setUser] = useState({
name: "Julia Roberts",
age: 35,
gender: "female",
eyeColor: "blue",
});

return (
<>
<h1>User {user.name}</h1>
<p>
Age is {user.age}, gender is {user.gender}, eyeColor {user.eyeColor}.
</p>
<button
type="button"
onClick={() =>
setUser((previousState) => {
return { ...previousState, age: 39 };
})
}
>
39
</button>
</>
);
};

When the state is updated, the entire state gets overwritten, but in this case, we only update the age.

Lazy Initial State

The initialState argument is the state used during the initial render. In subsequent renders, it is disregarded. If your initial state is a result of complex logic, then you can provide a function that returns a result. Imagine the following situation:

const Component = () => { 
const [state, setState] = useState(getInitialHundredItems())
}

Imagine this being called on each render needlessly (remember even though the initial value is disregarded upon the next renders, the function which initializes it still gets called).

For use cases like this instead of just providing a value you can pass a function that returns the initial state, this function will only be executed once (initial render) and not on each render. A fix would look like this:

const Component = () => { 
const [state, setState] = useState(getInitialHundredItems)
}
const Component = () => {
const [state, setState] = useState(() => {
const initialState = someExpensiveComputation(props);
return initialState;
});
}

Bailing out of a state update

What would happen if you updated the state to the same value as the current state? React uses Object.is() comparison algorithm, which determines whether two values are the same value. That means React will not render components’ children or fire any effects.

However, React may update that component which useState is in, without going deeper into the component tree.

Prop Drilling State Setters

Imagine a situation where you create multiple components and you want to forward state setters to children’s components.

The example below has two components: the root App component and the Count component.

import React, { useEffect, useState } from "react";

const Count = ({ count }) => {
const [num, setNum] = useState(count);
useEffect(() => {
setNum(count);
}, [count]);
return <p>{num}</p>;
};
export default function App() {
const [count, setCount] = useState(0);
return (
<div className="App">
<button onClick={() => setCount((c) => c + 1)}>increment</button>
<Count count={count} />
</div>
);
}

UseState Hook and TypeScript

Many developers nowadays use Typescript in their applications. The argument for using Typescript is its ability to find obvious yet frequently occurring errors. This makes it easier to manage your code.

React useState Hook usually infers the implicit type of the returned state from the initial state automatically. In an example below, Typescript knows that the type of “count” is a number:

const [ count, setCount ] = useState(0)

However, when working with complex types like objects or union types, we have to use interfaces or type objects as shown below:

interface UserFormState {
email: string;
password: string;
}

const App = () => {
const [userForm, setUserForm] = useState<UserFormState>({
email: “”,
password: “”,
});
};

Naturally, not giving any initial value will make the value undefined:

Const [count, setCount] = useState();

If type is declared, but the initial state is empty, count will be number | undefined:

const [count, setCount] = useState<number>();

If the initial value is an empty array without inferring the type, the type will be never[].

const [arrayOfString, setArrayOfStrings] = useState([]);

Thus setting type is crucial:

const [arrayOfStrings, setArrayOfStrings] = useState<string[]>([]);

Passing setCount to children props

Passing props down to children components is a common way to share states. However what type does setState have? Answer is

React.Dispatch<React.SetStateAction<number>>

Thus an example of two components would be:

function Parent() {
const [count, setCount] = useState(0);
return <Child count={count} setCount={setCount} />;
}

interface ChildProps {
count: number;
setCount: React.Dispatch<React.SetStateAction<number>>;
}
function Child({ count, setCount }: ChildProps) {
return (
<>
<div>{count}</div>
<button onClick={() => setCount(prevCount => prevCount + 1)}>
+
</button>
</>
);
}
0*TIGFvrlNPeSaK5lf.gif

Clap clap clap! It means a lot to me :)

Conclusion

In this article, you found the needed information on how to master the useState Hook in React. It is recommended that you use these examples in your future projects to better memorize the different aspects of this article.

Build React apps with reusable components like Lego

1*mutURvkHDCCgCzhHe-lC5Q.png

Bit’s open-source tool help 250,000+ devs to build apps with components.

Turn any UI, feature, or page into a reusable component — and share it across your applications. It’s easier to collaborate and build faster.

Learn more

Split apps into components to make app development easier, and enjoy the best experience for the workflows you want:

Micro-Frontends

Design System

Code-Sharing and reuse

Monorepo


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK