DEV Community

Dzmitry Harunou
Dzmitry Harunou

Posted on • Edited on

Effect Unit in Clean Architecture for Frontend Applications

This article shares the concept and implementation of the Effect unit in frontend applications within the Clean Architecture.

Repository with example:
https://github.com/harunou/react-tanstack-react-query-clean-architecture

The Effect unit encapsulates logic interacting with external resources through gateways. It manages side effects, asynchronous operations, and request orchestration.

Effect units handle cross-gateway requests, data fetching, sending processes, and sharing fetch logic across multiple use case interactors.

Effect Implementation

An Effect implements an interface provided by a consumer (use case interactor). This interface could represent a function required by use case or more complex one, which is use globally across application.

Effect implementations evolve from an inline form within consumers to extracted units:

 ---------------        ------------------
| inline effect | ---> | extracted effect |
 ---------------        ------------------
Enter fullscreen mode Exit fullscreen mode

Initially, effects are implemented inline, focused on fetching data, sending requests, and orchestrating interactions.

Inline Effect Implementation

Consider a use case interactor that initializes an entities store upon application startup, requiring orders and users data:

export const useInitializeApplicationUseCase = (): { execute: () => Promise<void> } => {
  const usersGateway = useUsersGateway();
  const ordersGateway = useOrdersGateway();

  const execute = async () => {
    // inline effect
    const users = await usersGateway.getUsers();
    const orders = await ordersGateway.getOrders();

    setUsersAndOrdersTransaction({ users, orders });
  };

  return { execute };
};
Enter fullscreen mode Exit fullscreen mode

Extracted Effect Implementation

The inline implementation can be extracted into a reusable effect unit:

// File: getUsersAndOrdersEffect.ts
export const getUsersAndOrdersEffect = async () => {
  const usersGateway = useUsersGateway();
  const ordersGateway = useOrdersGateway();

  const users = await usersGateway.getUsers();
  const orders = await ordersGateway.getOrders();

  return { users, orders };
};

// File: useInitializeApplicationUseCase.ts
export const useInitializeApplicationUseCase = (): { execute: () => Promise<void> } => {
  const execute = async () => {
    const { users, orders } = await getUsersAndOrdersEffect();

    setUsersAndOrdersTransaction({ users, orders });
  };

  return { execute };
};
Enter fullscreen mode Exit fullscreen mode

Extracted effects encapsulate logic completely, allowing internal modifications such as parallel requests without affecting consumers:

// File: getUsersAndOrdersEffect.ts
export const getUsersAndOrdersEffect = async () => {
  const usersGateway = useUsersGateway();
  const ordersGateway = useOrdersGateway();

  // Fetch users and orders in parallel
  const [users, orders] = await Promise.all([
    usersGateway.getUsers(),
    ordersGateway.getOrders(),
  ]);

  return { users, orders };
};

// File: useInitializeApplicationUseCase.ts
export const useInitializeApplicationUseCase = (): { execute: () => Promise<void> } => {
  const execute = async () => {
    const { users, orders } = await getUsersAndOrdersEffect();

    setUsersAndOrdersTransaction({ users, orders });
  };

  return { execute };
};
Enter fullscreen mode Exit fullscreen mode

Effect names should clearly indicate their function and end with the suffix Effect.

Q&A

How should an Effect unit be tested?

Effect units can be tested in integration with their dependent units or in isolation using mocks.

Where should Effects be placed?

Effects are suggested to be placed in a dedicated effects directory.

Can Effects be nested?

Yes, Effects can be nested. However, nesting may complicate reasoning and testing, so use with care.

Can multiple Effects be used simultaneously?

Yes, using multiple effects simultaneously is common and practical.

Conclusion

Effect units effectively manage asynchronous operations and coordinate cross-gateway interactions. Begin with inline implementations and extract effects only as needed, maintaining architecture flexibility as application complexity grows.

Heroku

Built for developers, by developers.

Whether you're building a simple prototype or a business-critical product, Heroku's fully-managed platform gives you the simplest path to delivering apps quickly — using the tools and languages you already love!

Learn More

Top comments (0)

SurveyJS custom survey software

JavaScript Form Builder UI Component

Generate dynamic JSON-driven forms directly in your JavaScript app (Angular, React, Vue.js, jQuery) with a fully customizable drag-and-drop form builder. Easily integrate with any backend system and retain full ownership over your data, with no user or form submission limits.

Learn more