Hone logo
Hone
Problems

Building Custom Store Enhancers in React with Redux Toolkit

Store enhancers are a powerful mechanism in Redux for extending the functionality of your store. They allow you to add features like persistence, logging, or performance monitoring without directly modifying the core Redux logic. This challenge will guide you in creating your own store enhancers, specifically focusing on a simple logging enhancer and a performance monitoring enhancer using Redux Toolkit.

Problem Description

You are tasked with creating two custom store enhancers for a React application using Redux Toolkit. The first enhancer, loggerEnhancer, should log every dispatched action to the console, including the action type and payload. The second enhancer, performanceEnhancer, should measure and log the time taken for each dispatched action to complete. This will help you understand the performance characteristics of your application's actions.

Key Requirements:

  • loggerEnhancer: Takes the Redux store as an argument and returns a function that modifies the next dispatch function. This modified dispatch function should log the action type and payload before calling the original next dispatch.
  • performanceEnhancer: Takes the Redux store as an argument and returns a function that modifies the next dispatch function. This modified dispatch function should record the time before and after dispatching the action, and log the duration.
  • Redux Toolkit: Utilize Redux Toolkit's configureStore function to apply both enhancers to a store.
  • Typescript: The solution must be written in Typescript.

Expected Behavior:

  • When an action is dispatched, loggerEnhancer should print a message to the console in the format: Action: [action.type], Payload: [action.payload].
  • When an action is dispatched, performanceEnhancer should print a message to the console in the format: Action [action.type] took [duration]ms.
  • Both enhancers should work seamlessly together when applied to the store.

Edge Cases to Consider:

  • Actions with no payload.
  • Asynchronous actions (actions that return promises). The performanceEnhancer should measure the time until the promise resolves or rejects.
  • Ensure the enhancers don't interfere with the normal dispatch process.

Examples

Example 1:

Input: Dispatch an action { type: 'INCREMENT', payload: 1 }
Output:
console.log("Action: INCREMENT, Payload: 1")
console.log("Action INCREMENT took 1ms") (duration will vary)

Explanation: The loggerEnhancer logs the action type and payload, and the performanceEnhancer logs the time taken to dispatch the action.

Example 2:

Input: Dispatch an action { type: 'FETCH_DATA' }
Output:
console.log("Action: FETCH_DATA, Payload: undefined")
console.log("Action FETCH_DATA took 50ms") (duration will vary)

Explanation: The loggerEnhancer logs the action type and undefined payload, and the performanceEnhancer logs the time taken to dispatch the action.

Example 3: (Asynchronous Action)

Input: Dispatch an action that returns a promise (e.g., a thunk that fetches data)
Output:
console.log("Action: FETCH_DATA, Payload: undefined")
console.log("Action FETCH_DATA took 200ms") (duration will vary, reflecting the fetch time)

Explanation: The performanceEnhancer should measure the time until the promise returned by the action resolves or rejects.

Constraints

  • The enhancers should be pure functions, meaning they should not have any side effects other than logging.
  • The performance measurement should be accurate enough to provide meaningful insights, but not so precise that it introduces significant overhead. Milliseconds are sufficient.
  • The code should be well-documented and easy to understand.
  • The solution must be compatible with Redux Toolkit version 2.x.

Notes

  • Consider using console.table for more structured logging if desired.
  • The next dispatch function is provided by Redux Toolkit's configureStore.
  • For the performanceEnhancer, you'll need to use Promise.resolve and .then to accurately measure the time taken for asynchronous actions. performance.now() is a good way to get high-resolution timestamps.
  • Focus on creating functional enhancers that are reusable and maintainable. Avoid modifying the store object directly.
Loading editor...
typescript