What are React hooks?

Shivin
8 min readJun 27, 2021

React has this additional API called the Hooks. This API in react lets you use state and other feature in React without writing class. These hooks provide the developers to use the state in a functional component unlike the old days when a class component was required to pass in a state to the functional component as a prop.

  • With hooks developers can now reuse the logic between the components without changing the architecture or structure.
  • Allows the developer to use the best features of React without having to use the classes.
  • Hooks allow to separate particular single component into various smaller functions based upon what piece of this separated components are related.

Basic React hooks

There are many inbuilt hooks within React, but the most commonly used are:

  • useState()
  • useEffect()
  • useContext()
  • useReducer()
  • useRef()

Rules of using Hooks

  • The first rule when using the hooks is to make sure never use them inside the loops, conditions or nested functions. Always use hooks at the top level of your react functions, this ensures that hooks are called in the same order each time a component is rendered.
  • The second rule states only use hooks from inside react functions.

The example below would make it much more clear:

React relies on the order in which Hooks are called.

But what happens if we break/alter this order put a hook call in the conditional statement as displayed in the code below:

Bad Practice- Hooks used under condition

In the above code, when name !=` ` condition is true on the first render, so we run this hook. However, on the next render the user might clear the form, making the condition false which would led to skip this hook during rendering. Now since the hook was skipped in the second render, the running order of the hooks is different and now from that point every next hook call after the one that was skipped would also shift by one. If you want to run the effect conditionally, the conditions can be added within the hook as shown below.

Condition within the hook

Few more example of how not to use hooks:

Bad Practice- Hooks used in the loop
Bad Practice- Hooks called within nested function
Bad Practice- Using hooks inside regular JavaScript function(Should always be used inside React functions)

useState()

The useState() hook allows the react developers update, handle and manipulate the state inside the functional components without needing to use the class component.

In the code above, the useState() hook receives an initial state as an argument and then returns by making the use of array de-structuring in JS, the two variables in the array can be named whatever. The first variable is the actual state, while the second variable is the function that is meant for updating the state by providing a new state. Each time the user clicks the “Increase my age!” button, the current actual state gets 1 added to it by using the handleClick() function.

React useState and setState don’t make changes directly to the state object, they create queues to optimize performance, which is why the changes don’t update immediately.

A type of a state can also be declared, making the hook type safe. This can be done as below:

const [age, setAge] =<Number | undefined>()

What this means is, that the age can only be either a type “Number” or “undefined”.

Declaring state variable as a pair of [something, setSomething] is quite handy and useful as it allows us to set multiple state variables if needed such as:

The updater function returned from invoking useState can also take a function similar to setState. This is ideal when the state update depends upon some previous value of the states.

useEffect()

What are effects?

  • Fetching data
  • Reading from local storage
  • Registering and de-registering event listeners

The useEffect() hook accepts the function that would contain effectual code. In using the useEffect() hook, the effectual function passed into it will execute right after the render has been displayed on the screen. By default the effects are basically executed after the render is complete but can be fired on a value change. The values that the user require a change to be triggered can be specified in the dependency array list. An effect is only rerun if at least one of the values specified as part of the dependencies has changed from the last render cycle. Look at the few different examples below the way useEffect() hook can be used in react:

Runs the function after EVERY retendering
Runs the function only ONCE after retendering as no dependency were specified
Runs the function every time if there is a change in the value of any dependency specified in the array list

Context

Props so far has been easiest way to pass the data around in react when working with two connected components(passing the data from parent component to child component). But assume if the the parent component wants the data to be passed to the third component, it will need to pass it as props through second component no matter if the second components has any use or not.

Context solves this problem by providing a global state that every component can easily access without the need to pass props from parent to multiple child components.

context.CreateContext

Declaring a context without default

createContext method is used to create a context object to which components can subscribe. These context are able to get the context value from the closest matching provider above in the tree. Components are usually wrapped in a Provider in order to get their context value.

createContext will return Provider component value when its called. Providers are react components from Context objects that allow other components to access those context values. One provider can be connected to many consumers. Providers can be nested to override values deeper within the tree.

Declaring a context with default

context.Provider

However, when there is no matching Provider above a component in a tree, the component will get its context from the default argument in createContext. { color: ‘black’ } here is the default argument in the createContext. But once the Provider is available, even if its value prop is undefined, its child component will use its value. Whenever, provider value prop changes, its subscribed consumers will re-render.

context.Consumer

createContext method also returns a consumer component when its called. Consumers are React component that subscribe to context changes from Provider. The value argument passed to the function will be equal to the value prop of the closest Provider for this context above in the tree. If there is no Provider for this context above, then the value argument will be equal to the defaultValue that was passed to createContext().

context.displayName

context.displayName is a string property from the React.createContext method. The react DevTools will use whatever display name is given to context.

Example using Consumer and Provider:

A new context is created which has properties Provider and Consumer.Then we render NumberContext.Provider with some contents, and pass a value prop to it. This will make the value available to all the descendants and the whole subtree will be able to use the Consumer (or useContext) to read out the value. Look at how we read the value inside the Display component: we have to wrap our content in a NumberContext.Consumer and use the render props pattern – passing a function as a child – to retrieve the value and display it.

Whereas React useContext hook makes it easier to pass the data throughout your app without manually passing props down the tree. useContext lets you use the context without the consumer.

Example of useContext()

The only thing to watch out for is that you have to pass the whole context object to useContext – not just the Consumer!

useReducer()

React useREducer is a react hook function that accepts a reducer function and an initial state. This hook function returns an array with 2 values. The first is the current state value and the second is the dispatch function which is further used to trigger an action.

const [state, dispatch] = useReducer(reducer, initialState);

Using useReducer:

  • Define an initial state
  • Provide a function that contains actions to update the state
  • Trigger seReducer() to dispatch an update state that is calculated relative to initial state.

The example code below will generate the following UI:

where the initial state is set to 0 and the “increment” and “decrement” button uses the previous initial state and set a new state with the help of the dispatch function which triggers on action performed by the user which in this case is clicking either of those buttons.

The code below is self explanatory on how to use useReducer().

There is always a debate between which is better useState() or useReducer(). One of the scenarios that I can recall where useReducer() would be better is when working with calendar, where a button such as “Today’s date” could be used to set the focus and the value back to the initial state.

--

--