React Hooks/ Redux Store

Mahmood Nalim
13 min readJun 1, 2023

React.js is an open-source JavaScript-based user interface library. It is hugely popular for web 🖥 and mobile app📱 development.

React follows the principle of component-based architecture. A component in React is an isolated and reusable piece of code. The components can be of two types – class components and functional components.

Before React version 16.8, developers 🧑‍💻could handle state and other React features only using class components. But with version 16.8, React introduced a new pattern called Hooks.

If you write 🖥 a function component, and then you want to add some state to it, previously you do this by converting it to a class. But, now you can do it by using a Hook inside the existing function component.

Hooks allow function components to have access to state and other React features. Because of this, class components are generally no longer needed.

Hooks are functions that let you “hook into” React state and lifecycle features from function components.

With React Hooks, we can use state, and other React features, in a functional component. It empowers devs 🧑‍💻🧑‍💻🧑‍💻 to do functional programming in React.

React provides a bunch of standard in-built hooks:

  • useState: To manage states. Returns a stateful value and an updater function to update it.
  • useEffect: To manage side effects like API calls, subscriptions, timers, mutations, and more.
  • useContext: To return the current value for a context.
  • useReducer: A useState alternative to help with complex state management.
  • useCallback: It returns a memorized version of a callback to help a child component not re-render unnecessarily.
  • useMemo: It returns a memoized value that helps in performance optimizations.
  • useRef: It returns a ref object with a .current property. The ref object is mutable. It is mainly used to access a child component imperatively.

State Hooks

State lets a component “remember” information like user input. For example, a form component can use state to store the input value.

To add state to a component, use one of these Hooks:

  • useState declares a state variable that you can update directly.
  • useReducer declares a state variable with the update logic inside a reducer function.

1) useState

useState is a React Hook that lets you add a state variable to your component.

Call useState at the top level of your component to declare a state variable.

useState returns an array with exactly two values:

  1. The current state. During the first render, it will match the initialState you have passed.
  2. The set function that lets you update the state to a different value and trigger a re-render. Calling the set function does not change the current state in the already executing code.It only affects what useState will return starting from the next render.

Updating state based on the previous state — updater function

you may pass an updater function to resolve this. if you do multiple updates within the same event, updaters can be helpful.

In most cases, there is no difference between these two approaches. React always makes sure that for intentional user actions, like clicks, the age state variable would be updated before the next click.

Updating objects and arrays in state

Storing information from previous renders — {prop}

You might want to change a state variable when a prop changes.

Add the prevCount state variable to track it. Add another state variable called trend to hold whether the count has increased or decreased. Compare prevCount with count, and if they’re not equal, update both prevCount and trend. Now you can show both the current count prop and how it has changed since the last render.

I’m getting an error: “Too many re-renders”

React limits the number of renders to prevent an infinite loop. Typically, this means that you’re unconditionally setting state during render, so your component enters a loop: render, set state (which causes a render), render, set state (which causes a render), and so on. Very often, this is caused by a mistake in specifying an event handler:

2) useReducer

Parameters

  • reducer: The reducer function that specifies how the state gets updated. It must be pure, should take the state and action as arguments, and should return the next state. State and action can be of any types.
  • initialArg: The value from which the initial state is calculated. It can be a value of any type. How the initial state is calculated from it depends on the next init argument.

useReducer returns an array with exactly two values:

  1. The current state. During the first render, it’s set to init(initialArg) or initialArg (if there’s no init).
  2. The dispatch function that lets you update the state to a different value and trigger a re-render.

Comparing useState and useReducer

Code size: Generally, with useState you have to write less code upfront.

Readability: useState is very easy to read when the state updates are simple.

Debugging: When you have a bug with useState, it can be difficult to tell where the state was set incorrectly, and why. With useReducer, you can add a console log into your reducer to see every state update.

3) useEffect

useEffect(setup, dependencies?)-

setup: The function with your Effect’s logic.

dependencies: The list of all reactive values referenced inside of the setup code

Some components need to stay connected to the network, some browser API, or a third-party library, while they are displayed on the page. These systems aren’t controlled by React, so they are called external.

Don’t rush to add Effects to your components. Keep in mind that Effects are typically used to “step out” of your React code and synchronize with some external system.

An Effect lets you keep your component synchronized with some external system (like a chat service).

Connecting to a chat server

uses an Effect to stay connected to an external system

Fetching data with Effects

You can use an Effect to fetch data for your component.

map widget or a video player

When you change the zoomLevel prop of the Map component, the Effect calls the setZoom() on the class instance to keep it synchronized:

Usage -Connecting to an external system

Some components need to stay connected to the network, some browser API, or a third-party library, while they are displayed on the page. These systems aren’t controlled by React, so they are called external.

To connect your component to some external system, call useEffect at the top level of your component:

Avoid below scenarios

  1. Updating state based on props or state

2. Adjusting some state when a prop changes

Every time the items change, the List and its child components will render with a stale selection value at first. Then React will update the DOM and run the Effects. Finally, the setSelection(null) call will cause another re-render of the List and its child components, restarting this whole process again.

Below code is the solution for this :

4) useRef

useRef is a React Hook that lets you reference a value that’s not needed for rendering.

Parameters

  • initialValue: The value you want the ref object’s current property to be initially. It can be a value of any type. This argument is ignored after the initial render.

Do not write or read ref.current during rendering.

Returns

useRef returns an object with a single property:

  • current: Initially, it’s set to the initialValue you have passed. You can later set it to something else. If you pass the ref object to React as a ref attribute to a JSX node, React will set its current property.

By using a ref, you ensure that:

  • You can store information between re-renders (unlike regular variables, which reset on every render).
  • Changing it does not trigger a re-render (unlike state variables, which trigger a re-render).so refs are not appropriate for storing information you want to display on the screen. Use state for that instead. If you show {ref.current} in the JSX, the number won’t update on click. This is because setting ref.current does not trigger a re-render. Information that’s used for rendering should be state instead.
  • The information is local to each copy of your component (unlike the variables outside, which are shared).

Manipulating the DOM with a ref

sometimes you might need access to the DOM elements managed by React — for example, to focus a node, scroll to it, or measure its size and position. There is no built-in way to do those things in React, so you will need a ref to the DOM node.

Example: Focusing a text input

Example: Scrolling to an element

Example: Play and pause the video

5) useContext

useContext is a React Hook that lets you read and subscribe to context from your component.

React Context is a way to manage state globally.

const value = useContext(SomeContext)

Passing Data Deeply with Context

Usually, you will pass information from a parent component to a child component via props.

But passing props can become verbose and inconvenient if you have to pass them through many components in the middle, or if many components in your app need the same information.

Context

Context lets a parent component provide data to the entire tree below it.

Step 1: Create the context

Step 2: Use the context

Next we’ll use the Context Provider to wrap the tree of components that need the state Context.

Wrap child components in the Context Provider and supply the state value. Now, all components in this tree will have access to the user Context.

Step 3: Use the useContext Hook

In order to use the Context in a child component, we need to access it using the useContext Hook.

First, include the useContext in the import statement:

6) useCallback

The React useCallback Hook returns a memoized callback function.

useCallback is a React Hook that lets you cache a function definition between re-renders.

Think of memoization as caching a value so that it does not need to be recalculated.

The useCallback and useMemo Hooks are similar. The main difference is that useMemo returns a memoized value and useCallback returns a memoized function.

Returns

On the initial render, useCallback returns the fn function you have passed.

During subsequent renders, it will either return an already stored fn function from the last render (if the dependencies haven’t changed), or return the fn function you have passed during this render.

Skipping re-rendering of components

In other words, useCallback caches a function between re-renders until its dependencies change.

Without useCallback and with memo

In JavaScript, a function () {} or () => {} always creates a different function, similar to how the {} object literal always creates a new object. Normally, this wouldn’t be a problem, but it means that ShippingForm props will never be the same, and your memo optimization won’t work. This is where useCallback comes in handy:

By wrapping handleSubmit in useCallback, you ensure that it’s the same function between the re-renders

You will often see useMemo alongside useCallback. They are both useful when you’re trying to optimize a child component. They let you memoize (or, in other words, cache) something you’re passing down:

useMemo caches the result of calling your function. In this example, it caches the result of calling computeRequirements(product) so that it doesn’t change unless product has changed.

useCallback caches the function itself. Unlike useMemo, it does not call the function you provide. Instead, it caches the function you provided so that handleSubmit

7) useMemo

useMemo is a React Hook that lets you cache the result of a calculation between re-renders.

The React useMemo Hook returns a memoized value.

Think of memoization as caching a value so that it does not need to be recalculated.

Parameters

You need to pass two things to useMemo:

  1. A calculation function that takes no arguments, like () =>, and returns what you wanted to calculate.
  2. A list of dependencies including every value within your component that’s used inside your calculation.

Returns

On the initial render, useMemo returns the result of calling calculateValue with no arguments.

During next renders, it will either return an already stored value from the last render (if the dependencies haven’t changed), or call calculateValue again, and return the result that calculateValue has returned.

Usage

Skipping expensive recalculations

Skipping re-rendering of components

In some cases, useMemo can also help you optimize performance of re-rendering child components.

How to tell if a calculation is expensive?

8) Custom Hooks

A custom Hook is a JavaScript function. The name of the custom Hook starts with “use” which can call other Hooks. A custom Hook is just like a regular function, and the word “use” in the beginning tells that this function follows the rules of Hooks. Building custom Hooks allows you to extract component logic into reusable functions.

When you have component logic that needs to be used by multiple components, we can extract that logic to a custom Hook.

Keeping Components Pure

Pure functions only perform a calculation and nothing more.

By strictly only writing your components as pure functions, you can avoid an entire class of baffling bugs and unpredictable behavior as your codebase grows.

  • It minds its own business. It does not change any objects or variables that existed before it was called.
  • Same inputs, same output. Given the same inputs, a pure function should always return the same result.

You could think of your components as recipes: if you follow them and don’t introduce new ingredients during the cooking process, you will get the same dish every time.

Pure functions don’t mutate variables outside of the function’s scope or objects that were created before the call — that makes them impure!

However, it’s completely fine to change variables and objects that you’ve just created while rendering.

How does React keep track of your app’s component structure?

React, and many other UI libraries, model UI as a tree. Thinking of your app as a tree is useful for understanding the relationship between components.

React uses tree structures to manage and model the relationship between components in a React app.

What is the DOM?

The Document Object Model (DOM) is a programming interface for web documents.

The DOM is not a programming language, but without it, the JavaScript language wouldn’t have any model or notion of web pages, HTML documents, SVG documents, and their component parts.

What is a DOM tree?

A DOM tree is a tree structure whose nodes represent an HTML or XML document’s contents.

The Render Tree

we have the concept of parent and child components, where each parent component may itself be a child of another component.

When we render a React app, we can model component relationships in a tree, known as the render tree.

See you soon with my next article. Until then, please take care of yourself, and stay happy.

REDUX

Redux is really:

  • A single store containing a “global” state
  • Dispatching plain object actions to the store when something happens in the app
  • Pure reducer functions look at those actions and return an immutably updated state.

1) Create a Redux Store

2) Provide the Redux Store to React

3) Create a Redux State Slice

Redux Toolkit’s createSlice API was designed to eliminate all the "boilerplate" with writing reducers, actions, and immutable updates!

Redux Toolkit’s createSlice and createReducer APIs use Immer inside to allow us to write "mutating" update logic that becomes correct immutable updates.

Redux and Side Effects

By itself, a Redux store doesn’t know anything about async logic. It only knows how to synchronously dispatch actions, update the state by calling the root reducer function, and notify the UI that something has changed.

Redux middleware was designed to enable writing logic that has side effects.

In practice, the single most common use case for side effects in a typical Redux app is fetching and caching data from the server.

Data Fetching

  • Use RTK Query as the default approach for data fetching and caching
  • If RTKQ doesn’t fully fit for some reason, use createAsyncThunk

What is a “thunk”?

The word “thunk” is a programming term that means “a piece of code that does some delayed work”.

Thunks are best used for complex sync logic that needs access to dispatch and getState, or moderate async logic such as one-shot "fetch some async data and dispatch an action with the result" requests.

The most common use cases are:

  • Moving complex logic out of components
  • Making async requests or other async logic
  • Writing logic that needs to dispatch multiple actions in a row or over time
  • Writing logic that needs access to getState to make decisions or include other state values in an action

Why RTK Query for Data Fetching

Rdux intentionally designed the RTK listener middleware to be straightforward to use. It uses standard async/await syntax.

It manages all the fetching, caching, and loading status logic for you.

RTK Query replaces the need to write any actions, thunks, reducers, selectors, or effects to manage data fetching. (In fact, it actually uses all those same tools internally.)

--

--