Horje
How to Create Memoized Selectors Using Reselect Library?

Memoization optimizes costly function calls by caching results for future identical inputs. Reselect, a library for Redux applications, provides the creation of memoized selectors. In this article, we will learn how to create memoized selectors using the Reselect library.

What is Reselect?

Reselect is a simple selector library for Redux that allows you to create memoized selectors. A selector is a function that takes the state as an argument and returns a derived piece of state. By memoizing these selectors, Reselect ensures that they are only recalculated when their input arguments change, preventing unnecessary re-renders.

Approaches

Reselect offers a few different ways to create selectors. The most common approach involves using the createSelector function.

  • Basic Selector: A basic selector is a simple function that extracts a specific piece of state:
  • Memoized Selector: A memoized selector uses createSelector to memoize the result of a computation:
  • Complex Memoized Selector: You can combine multiple selectors to create more complex memoized selectors:

Basic Selector

A basic selector directly extracts a portion of the state from the Redux store

Example: This function takes the state as an argument and returns the userList array.

const getUsers = (state) => state.users.userList;

Memoized Selector

A memoized selector uses the createSelector function to cache the results of a computation. This function takes an array of input selectors and a transform function:

Example: This Illustrates getUserNames is a memoized selector that maps over the userList and extracts user names.

import { createSelector } from 'reselect';

const getUserNames = createSelector(
[getUsers],
(userList) => userList.map(user => ({ id: user.id, name: user.name, isActive: user.isActive }))
);

Complex Memoized Selector

More complex memoized selectors can combine multiple input selectors.

Example: This selector counts the number of active users by filtering the userList.

const getActiveUsersCount = createSelector(
[getUsers],
(userList) => userList.filter(user => user.isActive).length
);

Steps to Create Application (Install Required Modules) .

To create a React application that uses Reselect, follow these steps:

Step 1: Create a React Application named ‘memoized’ and navigate to it using this command.

npx create-react-app memoized
cd memoized

Step 2: Install required packages and dependencies.

 npm install redux react-redux reselect

Project Structure:

Screenshot-2024-06-19-191213

Project Structure

Updated Dependencies in package.json File.


"dependencies": {
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-redux": "^8.1.3",
"react-scripts": "5.0.1",
"redux": "^4.2.1",
"reselect": "^4.1.5",
"web-vitals": "^2.1.4"
}


Example: This example shows the implementation of the above-explained approach

CSS
/* src/App.css */
body {
  font-family: Arial, sans-serif;
  margin: 0;
  padding: 20px;
}

h1 {
  color: #333;
}

h2 {
  color: #555;
}

ul {
  list-style-type: none;
  padding: 0;
}

li {
  background-color: #f0f0f0;
  margin: 5px 0;
  padding: 10px;
  border-radius: 4px;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

button {
  padding: 5px 10px;
  background-color: #007bff;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}

button:hover {
  background-color: #0056b3;
}

p {
  font-weight: bold;
}
JavaScript
//src/components/UserList.js

import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { getUserNames, getActiveUsersCount } from '../selectors/userSelectors';
import { toggleUserActive } from '../actions/userActions';

const UserList = () => {
  const userNames = useSelector(getUserNames);
  const activeUsersCount = useSelector(getActiveUsersCount);
  const dispatch = useDispatch();

  const handleToggleActive = (userId) => {
    dispatch(toggleUserActive(userId));
  };

  return (
    <div>
      <h2>User List</h2>
      <ul>
        {userNames.map(user => (
          <li key={user.id}>
            {user.name}
            <button onClick={() => handleToggleActive(user.id)}>
              {user.isActive ? 'Deactivate' : 'Activate'}
            </button>
          </li>
        ))}
      </ul>
      <p>Active Users Count: {activeUsersCount}</p>
    </div>
  );
};

export default UserList;
JavaScript
//src/store.js

import { createStore } from 'redux';
import rootReducer from './reducers';

const store = createStore(rootReducer);

export default store;
JavaScript
//src/actions/userActions.js

export const setUserList = (users) => ({
    type: 'SET_USER_LIST',
    payload: users
  });
  
  export const toggleUserActive = (userId) => ({
    type: 'TOGGLE_USER_ACTIVE',
    payload: userId
  });
JavaScript
//src/reducers/index.js

import { combineReducers } from 'redux';
import usersReducer from './userReducer';

const rootReducer = combineReducers({
  users: usersReducer,
  // Add other reducers as needed
});

export default rootReducer;
JavaScript
//src/reducers/userReducer.js

const initialState = {
  userList: []
};

const usersReducer = (state = initialState, action) => {
  switch (action.type) {
    case 'SET_USER_LIST':
      return {
        ...state,
        userList: action.payload.map(user => ({
          ...user,
          isActive: false  // Initialize isActive status as false
        }))
      };
    case 'TOGGLE_USER_ACTIVE':
      return {
        ...state,
        userList: state.userList.map(user =>
          user.id === action.payload ? { ...user, isActive: !user.isActive } : user
        )
      };
    default:
      return state;
  }
};

export default usersReducer;
JavaScript
//src/selectors/userSelectors.js

import { createSelector } from 'reselect';

const getUsers = (state) => state.users.userList;

export const getUserNames = createSelector(
  getUsers,
  (userList) => userList.map(user => 
      ({ id: user.id, name: user.name, isActive: user.isActive }))
);

export const getActiveUsersCount = createSelector(
  getUsers,
  (userList) => userList.filter(user => user.isActive).length
);
JavaScript
//src/index.js

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import store from './store';
import App from './App';
import './App.css';

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
);
JavaScript
//src/App.js

import React, { useEffect } from 'react';
import { useDispatch } from 'react-redux';
import { setUserList } from './actions/userActions';
import UserList from './components/UserList';
import './App.css';

const App = () => {
  const dispatch = useDispatch();

  useEffect(() => {
    const fetchUsers = async () => {
      const response = await fetch('https://jsonplaceholder.typicode.com/users');
      const data = await response.json();
      dispatch(setUserList(data));
    };

    fetchUsers();
  }, [dispatch]);

  return (
    <div className="App">
      <h1>Redux App with Reselect</h1>
      <UserList />
    </div>
  );
};

export default App;

Output :

Here’s a demonstrating the output of the above application:




Reffered: https://www.geeksforgeeks.org


ReactJS

Related
How to Add Analytics in Next.js with Plausible How to Add Analytics in Next.js with Plausible
How To Get And Process A Stream Response With Axios in NextJS ? How To Get And Process A Stream Response With Axios in NextJS ?
How To Create A Custom Image Loader In NextJS? How To Create A Custom Image Loader In NextJS?
How To Create React Multiple File Upload Using NextJS And Typescript? How To Create React Multiple File Upload Using NextJS And Typescript?
How To Set Up Mongoose With Typescript In NextJS ? How To Set Up Mongoose With Typescript In NextJS ?

Type:
Geek
Category:
Coding
Sub Category:
Tutorial
Uploaded by:
Admin
Views:
20