Concepts and Knowledge

The Redux store is a fundamental concept in Redux, and it serves as a centralized place to store and manage the state of your application. It helps you manage the data and the application's behavior in a predictable and organized manner. This has several advantages which include better communication between components, a single source of truth for the whole application, it's easier to debug since the data flows in one single direction and redux offers a Chrome extension that can be used to visualize states in the browser during the development of the application.

Here's an explanation of what a Redux store is and how it works:

  1. State Container: The Redux store is essentially a TypeScript object that holds the entire state of your application. This state can include data like user profiles, application settings, and any other information that needs to be shared across different parts of your application.

  2. Single Source of Truth: In Redux, there is a core principle known as "single source of truth." This means that all the application's state is stored in a single object (the store), making it easier to maintain and manage the state consistently throughout your application.

  3. Immutability: The state stored in the Redux store is immutable. This means that you cannot directly modify the state. Instead, when you want to make changes to the state, you create a new state object with the desired changes. This helps ensure the predictability of state changes.

  4. Actions and Reducers: To update the state in the Redux store, you dispatch actions. Actions are plain JavaScript objects that describe the type of action to be performed and may include additional data. Reducers are functions that specify how the state should change in response to actions. They take the current state and the action as input and return a new state.

  5. Store Methods: The Redux store provides a set of methods for interacting with the state, including getSelector to access the current state, dispatch to dispatch actions.

Redux Toolkit

Redux Toolkit is an official set of tools and utilities provided by the Redux team to simplify and streamline the process of working with Redux in a React application. It's designed to help you write Redux code more efficiently, reduce boilerplate, and make it easier to manage and maintain your Redux store and associated code.

Redux Toolkit includes several key features and benefits:

  1. Simplified Redux Configuration: Redux Toolkit simplifies the setup of a Redux store by providing the configureStore function. This function combines the following Redux setup steps into a single call:

    • Creating a Redux store
    • Configuring middleware, including the popular redux-thunk middleware for handling asynchronous actions
    • Setting up development tools, such as Redux DevTools, for debugging
    • Optimizing performance by enabling the Immer library for immutable state updates
  2. Reducer and Action Creation: Redux Toolkit offers functions like createSlice and createAsyncThunk that make it easier to define reducers and create actions. createSlice generates action creators and reducers with less boilerplate code, and createAsyncThunk simplifies handling asynchronous actions.

  3. Immutability with Immer: Redux Toolkit promotes immutability and automatically uses the Immer library under the hood. This makes it much easier to work with immutable state updates in reducers, as it allows you to write code that looks like you're modifying the state directly.

  4. Reduced Boilerplate: By providing utilities like createSlice, Redux Toolkit reduces the amount of boilerplate code you need to write for Redux. You can define actions, reducers, and initial state in a more concise and readable manner.

  5. Better Development Experience: Redux Toolkit helps improve the development experience by enabling Redux DevTools and providing better defaults for debugging and performance optimizations.

Initial State

The initial state represents the application's state before any actions have been dispatched. It's a plain TypeScript object that defines the initial values of different parts of your application's state. It's provided when creating the Redux store using createStore or, in the case of Redux Toolkit, when defining a slice.

Action

An action in Redux is a plain TypeScript object that describes an event or an intention to change the state of the application. Actions have a mandatory type property, which is a string that describes the action's type. It typically follows a naming convention like "ACTION_TYPE" in uppercase. Actions may also include optional data in their payload property, providing additional information required for the state change. Actions are dispatched using the dispatch function and serve as the input for reducers to determine how the state should be updated.

In Redux Toolkit, you often use the createSlice function to define reducers and action creators together in a more compact way. createSlice generates action creators for each reducer case, eliminating the need to write action types and action creator functions separately. The generated action creators are automatically named based on the reducer's case names, which reduces naming inconsistencies and errors. These action types are stored as properties so you don't need to define and manage action type constants separately.

Reducer

A reducer is a pure function in Redux that specifies how the application's state should change in response to dispatched actions. It takes the current state and an action as input and returns a new state. Reducers are responsible for immutably updating the state, meaning they create a new state object with the desired changes instead of modifying the existing state. The state changes made by reducers are predictable and based on the action type.

Slices

In Redux Toolkit, a "slice" is a concept that encompasses a collection of related Redux functionality: it includes a reducer, action creators, and the initial state. Slices are used to organize and encapsulate the state management logic for a specific part of your application's state. They make it easier to modularize your Redux store and simplify the process of defining reducers and actions.

To create a slice, you use the createSlice function provided by Redux Toolkit. It takes an object as an argument with the following properties:

  • name: A string that represents the name of the slice. It's used to generate action types.
  • initialState: The initial state for this slice.
  • reducers: An object that defines reducer functions. Each key-value pair in the reducers object represents a specific action type and the reducer function that handles it.

Here's how to access the reducer and action creators:

// counterSlice.ts

import { createSlice, PayloadAction } from '@reduxjs/toolkit';

interface CounterState {
  value: number;
}

const initialState: CounterState = {
  value: 0,
};

const counterSlice = createSlice({
  name: 'counter',
  initialState,
  reducers: {
    increment: (state) => {
      state.value += 1;
    },
    decrement: (state) => {
      state.value -= 1;
    },
  },
});

export const { increment, decrement } = counterSlice.actions;
export default counterSlice.reducer;

Accessing the Reducer and Action Creators: After creating the slice, you can access the generated reducer and action creators through the counterSlice object:

  • reducer: The reducer function that manages the state for this slice.
  • Action creators: Action creators are automatically generated for each reducer function defined in the reducers object. They can be accessed as properties of the slice.

Thunks

A Thunk refers to a special kind of function that allows you to perform asynchronous actions in Redux. Thunks are often used to handle side effects such as making API requests, performing asynchronous operations, and dispatching multiple actions in response to the result of those operations.

Here's a breakdown of what a thunk is and how it is used with Redux Toolkit:

  1. Asynchronous Actions: Redux's standard action dispatching mechanism is synchronous. However, in real-world applications, you often need to perform asynchronous operations, like fetching data from an API. Thunks allow you to handle these asynchronous actions within the Redux workflow.

  2. Middleware: Thunks are typically used with Redux middleware, such as redux-thunk or built-in middleware provided by Redux Toolkit. Middleware allows you to intercept dispatched actions and add custom behavior, like handling asynchronous operations, before they reach the reducers.

  3. Definition: A thunk is a function that, when dispatched, can perform side effects and dispatch regular Redux actions. This function receives two arguments: dispatch and getState, which can be used to dispatch actions and access the current state of the Redux store.

  4. Redux Toolkit's createAsyncThunk: Redux Toolkit provides a utility called createAsyncThunk that simplifies the process of creating thunks for handling asynchronous actions. It generates a set of actions and reducers for handling common asynchronous operations like data fetching. You specify the async operation and how it should affect your Redux state, and Redux Toolkit does the heavy lifting for you.

Models

Auth Models

AuthState Class

PropertyTypeDefaultDescription
statusstring''Authentication status.
errorMessagestring | nullnullError message, if any.
tokenToken | nullnullAuthentication token (if available).

AuthAction Class

PropertyTypeDescription
tokenToken | nullAuthentication token (if available).
errorMessagestring | nullError message, if any.

Token Interface

PropertyTypeDescription
access_tokenstringAccess token.
token_typestringToken type.
redirectstring | nullRedirect information (if available).

TokenContent Interface

PropertyTypeDescription
sub{ ... }Sub-properties for the token content.
authstringAuthentication information (if available).
expnumberExpiration time.

sub Property

PropertyTypeDescription
idstringIdentifier.
accountstringAccount information.
displayNamestringDisplay name.

Config Model

AuthData Interface

PropertyTypeDescription
authenticatestringAuthentication type.
methodstringAuthentication method.
redirectstring | undefinedRedirect information (if available).

SapiConfig Interface

PropertyTypeDescription
baseUrlstringBase URL configuration.

AppConfig Interface

PropertyTypeDescription
protocolstringProtocol.
portstringPort configuration.
domainstringDomain configuration.
searchAPISapiConfigSearch API configuration.

Configuration Interface

PropertyTypeDescription
typestringConfiguration type.
display_namestringDisplay name.
url_ui_pathstringUI path.
rolesstring[]Array of roles.
groupsstring[]Array of groups.
pipelinesany[]Pipelines.
fieldsany[]Fields.
authenticationAuthData | nullAuthentication data (if available).
appConfigAppConfig | nullApplication configuration (if available).

Search Result Models

Hit Interface

PropertyTypeDescription
idstringIdentifier.
headerFieldData[]Array of header data.
bodyFieldData[][]Grid of body data.
metadata{ [key: string]: FieldData[] }Metadata associated with keys.
sub_titleFieldDataSubtitle data.
titleFieldDataTitle data.

SearchResultModel Class

PropertyTypeDefaultDescription
hitsHit[]-Array of hit data.
aggregationsAggregation[]-Array of aggregation data.
totalnumber0Total number of results.

Theme Models

ThemeMode Enum

NameValue
LIGHT'light'
DARK'dark'

ThemeModel Class

PropertyTypeDefaultDescription
modeThemeMode'dark'Theme mode (Enum value).

Toolbar Models

Toolbar Interface

PropertyTypeDescription
totalPagesnumberTotal number of pages.
pagenumberCurrent page number.
sortSortOptionSort option selected.
sortOptionsSortOption[]Array of available sort options.

SortOption Interface

PropertyTypeDescription
fieldstringField to sort by.
display_namestringDisplay name for sorting.
orderstringSorting order (e.g., 'asc' or 'desc').

Store

Here at the store script is where the reducers are set and divided in the state object. We have implemented an special object called persistReducer and its function is to keep the state data stored in this object even after refreshing the browser which is not a default behavior of React. Here we store authentication and configuration data that must remain the same at all times in the application. Then we have auth, config and theme reducers in a persisted object, and the state contains also search (which stores the search results), toolbar (state for pages and sort) and loader (which controls the state for the spinner screen) states. All of this can be appreciated with the Redux DevTools extension for Google Chrome:

Slices

Slice Name: auth

Initial State Type: AuthState

Description:

The auth slice is responsible for managing user authentication-related data in the application state. It defines actions and reducers for handling user authentication, errors, and token management.

Actions and Reducers:

Action/Reducer NameState Element ModifiedValue SetDescription
loginstatus, token, errorMessage'authenticated', AuthAction.token, AuthAction.errorMessageUpdates the authentication status to 'authenticated,' sets the user token, and stores an error message if any.
logoutstatus, errorMessage, tokenReset to initial valuesLogs the user out by resetting the authentication status, error message, and user token to their initial values.
setErrorMessagestatus, token, errorMessage'not authenticated', AuthState.token, PayloadAction<string>Sets the error message and changes the authentication status to 'not authenticated.'
checkingCredentialsstatus, errorMessage, token'checking', Reset token, Reset errorMessageIndicates that the application is currently checking user credentials. It sets the status to 'checking' and clears the user token and error message.
Action/Thunk Name: userLocalAuth
Element ModifiedValue SetDescription
Start loading indicatorNoneStarts the loading indicator.
Authentication Status'checking'Indicates that the application is checking credentials.
API RequestPOST request to '/local/token'Sends a POST request to the '/local/token' endpoint to perform local authentication.
Success (Authenticated)AuthAction with token and null error messageIf the API call is successful, it updates the authentication status to 'authenticated' and sets the user token while clearing any previous error message.
Failure (Invalid credentials)Sets error message to 'Invalid credentials'If the API call fails (e.g., due to invalid credentials), it sets the error message to 'Invalid credentials'.
Stop loading indicatorNoneStops the loading indicator after API request completion.
Action/Thunk Name: userLdapAuth
Element ModifiedValue SetDescription
Authentication Status'checking'Indicates that the application is checking credentials.
API RequestPOST request to '/ldap/token'Sends a POST request to the '/ldap/token' endpoint to perform LDAP authentication.
Success (Authenticated)AuthAction with token and null error messageIf the API call is successful, it updates the authentication status to 'authenticated' and sets the user token while clearing any previous error message.
Failure (Invalid credentials)Sets error message to 'Invalid credentials'If the API call fails (e.g., due to invalid credentials), it sets the error message to 'Invalid credentials'.

Slice Name: config

Initial State Type: Configuration

Description:

The config slice is responsible for managing configuration data in the application state. It defines actions and reducers for manipulating this configuration data.

Actions and Reducers:

Action/Reducer NameState Element ModifiedValue SetDescription
setConfigtype, display_name, url_ui_path, roles, groups, pipelinesCorresponding values from Configuration typeSets the configuration data in the state.
setAuthMethodauthenticationAuthDataSets the authentication method in the state.
setFieldsConfigfieldsArray of valuesSets the configuration fields in the state.
defaultConfigtype, display_name, url_ui_path, roles, groups, pipelines, fields, authentication, appConfigCorresponding values from initialStateResets the configuration data to its initial state.
setAppConfigappConfigAppConfigSets the application configuration data in the state.
Action/Thunk Name: getInitialConfig
Elements ModifiedValue SetDescription
Start loading indicatorNoneStarts the loading indicator.
Authentication StateAuthDataIf a valid access token is present and the user is not authenticated, it logs in the user and updates the authentication state with method and redirect information.
Configuration DataResult from the APIUpdates the application configuration data in the state with the data obtained from the API endpoint "/webview/config".
Stop loading indicatorNoneStops the loading indicator.
Action/Thunk Name: getAppConfig
Elements ModifiedValue SetDescription
Start loading indicatorNoneStarts the loading indicator.
Application ConfigurationResult from getConfig()Updates the application configuration data in the state with the data obtained from the getConfig() function.
Stop loading indicatorNoneStops the loading indicator.

Slice Name: toolbar

Initial State Type: Loader

Description:

The toolbar slice is responsible for managing the loading indicator's state in the application. It defines actions and reducers for controlling the loading state.

Actions and Reducers:

Action/Reducer NameState Element ModifiedValue SetDescription
startLoadingloadingtrueStarts the loading indicator by setting the loading state to true.
stopLoadingloadingfalseStops the loading indicator by setting the loading state to false.

Slice Name: search

Initial State Type: SearchResultModel

Description:

The search slice is responsible for managing search result data in the application state. It defines actions and reducers for updating and resetting the search results.

Actions and Reducers:

Action/Reducer NameState Element ModifiedValue SetDescription
setSearchValuehits, aggregations, totalCorresponding values from SearchResultModelSets the search result data in the state.
setStateToDefaulthits, aggregations, totalReset to initial valuesResets the search result data to its initial state.
Action/Thunk Name: getResultsData
Element ModifiedValue SetDescription
Start loading indicatorNoneStarts the loading indicator.
API RequestPOST request to '/search/'Sends a POST request to the '/search/' endpoint with the provided payload to retrieve search results.
Success (Set Search Results)SearchResultModelIf the API call is successful, it retrieves and sets the search results in the state using the setSearchValue action.
Calculate Total PagesTotal pages calculated using totalPagesCalculates the total number of pages based on the total search results and a predefined items-per-page value (20 in this case).
Set Total PagesTotal pagesSets the calculated total pages in the state using the setToolbarTotalPages action.
Stop loading indicatorNoneStops the loading indicator after API request completion.

Slice Name: theme

Initial State Type: ThemeModel

Description:

The theme slice is responsible for managing the application's theme mode in the state. It defines actions and reducers for toggling the color mode.

Actions and Reducers:

Action/Reducer NameState Element ModifiedValue SetDescription
toggleColorModemodeThemeMode value from action payloadToggles the color mode of the application by setting the mode state to the provided ThemeMode value from the action payload.


Slice Name: toolbar

Initial State Type: Toolbar

Description:

The toolbar slice is responsible for managing toolbar-related data in the application state. It defines actions and reducers for updating and controlling toolbar options.

Actions and Reducers:

Action/Reducer NameState Element ModifiedValue SetDescription
setToolbarTotalPagestotalPagesnumberSets the total number of pages in the toolbar.
setToolbarSortsortSortOptionSets the sorting options in the toolbar.
setToolbarSortOptionssortOptionsSortOption[]Sets the available sorting options in the toolbar.
setToolbarPagepagenumberSets the current page in the toolbar.
  • No labels