Skip to main content

Library vs Framework: Understanding the Difference and Why React is a Library

ยท 5 min read
Anand Raja
Senior Software Engineer

๐Ÿ” The Fundamental Differenceโ€‹

Control Flow Principleโ€‹

  • Library: You call the library - You control when and how to use it
  • Framework: The framework calls you - It controls the application flow via Inversion of Control (IoC)
Library Pattern:          Framework Pattern:
Your Code โ†’ Library Framework โ†’ Your Code
(You control) (Framework controls)

๐Ÿ”„ Inversion of Control (IoC) Explainedโ€‹

IoC is a design principle where control flow is "inverted" - instead of your code controlling execution, an external system (framework) takes control.

Hollywood Principle: "Don't call us, we'll call you"โ€‹

// Traditional Control (Library)
const result = library.doSomething(data); // You call library

// Inverted Control (Framework)
framework.register('event', () => {
// Framework calls your function when event occurs
});

๐Ÿ› ๏ธ Common IoC Implementation Methodsโ€‹

1. Dependency Injection (DI)โ€‹

Framework provides dependencies to your code instead of you creating them.

// Angular - Framework injects dependencies
@Injectable()
export class UserService {
constructor(private http: HttpClient) {} // Framework injects HttpClient
}

@Component({...})
export class UserComponent {
constructor(private userService: UserService) {} // Framework injects UserService
}

2. Event-Driven Architectureโ€‹

Framework calls your code when specific events occur.

// Express.js - Framework calls route handlers
app.get('/users', (req, res) => {
// Framework calls this when GET /users requested
res.json(users);
});

// Node.js EventEmitter
emitter.on('data', (data) => {
// Framework calls this when 'data' event emitted
});

3. Lifecycle Hooksโ€‹

Framework controls object lifecycle and calls your methods at specific times.

// Vue.js lifecycle hooks
export default {
mounted() {
// Framework calls this after component is mounted
},
beforeDestroy() {
// Framework calls this before component destruction
}
}

// Angular lifecycle
export class Component implements OnInit, OnDestroy {
ngOnInit() { /* Framework calls this */ }
ngOnDestroy() { /* Framework calls this */ }
}

4. Template/Callback Patternsโ€‹

Framework defines the algorithm structure and calls your implementations.

// Template Method Pattern
class Framework {
execute() {
this.step1();
this.step2(); // Your implementation
this.step3();
}

step2() { throw new Error('Implement this'); }
}

โœ… Benefits of IoCโ€‹

1. Loose Couplingโ€‹

Components don't directly depend on concrete implementations.

// Without IoC - Tight coupling
class UserService {
constructor() {
this.http = new HttpClient(); // Direct dependency
}
}

// With IoC - Loose coupling
class UserService {
constructor(private http: HttpClient) {} // Injected dependency
}

2. Testabilityโ€‹

Easy to mock dependencies for unit testing.

// Easy to test with IoC
const mockHttp = jasmine.createSpy('HttpClient');
const userService = new UserService(mockHttp);

3. Flexibility & Configurationโ€‹

Framework can decide which implementations to use.

// Production
container.bind(HttpClient).to(RealHttpClient);

// Testing
container.bind(HttpClient).to(MockHttpClient);

4. Separation of Concernsโ€‹

Business logic separated from object creation and lifecycle management.


๐Ÿ“š Library Examplesโ€‹

// jQuery - You control when to call
$('#button').click(() => $(this).hide());

// Lodash - You call utility functions
const names = _.map(users, 'name');

// Axios - You initiate HTTP calls
axios.get('/api/users').then(handleResponse);

Characteristics: Specific functionality, no app structure, optional usage, you control flow.


๐Ÿ—๏ธ Framework Examplesโ€‹

// Angular - Framework controls lifecycle via IoC
@Component({...})
export class UserComponent {
constructor(private userService: UserService) {} // DI

ngOnInit() { /* Framework calls this */ }
ngOnDestroy() { /* Framework calls this */ }
}

// Express.js - Framework controls request handling
app.get('/users', (req, res) => {
// Framework calls this when route matches
res.json(users);
});

Characteristics: IoC, application structure, convention over configuration, comprehensive solution.


โš›๏ธ Why React is a Library (Despite Some IoC)โ€‹

React Has Limited IoCโ€‹

// React does use some IoC with hooks
function UserComponent() {
useEffect(() => {
// React calls this after render (IoC)
}, []);

const handleClick = useCallback(() => {
// React optimizes this callback (IoC)
}, []);

return <div>Hello</div>;
}

But You Still Control the Overall Flowโ€‹

// 1. You decide when to render
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />); // YOU call React

// 2. You choose app structure
src/
components/ // Your choice
pages/ // Your choice
services/ // Your choice

// 3. You bring your own tools
import { BrowserRouter } from 'react-router-dom'; // Your choice
import { Provider } from 'react-redux'; // Your choice
import axios from 'axios'; // Your choice

// 4. Incremental adoption
<div id="react-widget"></div> // Just one part of existing site

๐Ÿ”„ Framework vs Library Comparisonโ€‹

AspectFramework (Angular)Library (React)
ControlFramework via IoCYou control
StructurePrescribedYou choose
DependenciesBuilt-in everythingYou choose libraries
AdoptionAll-or-nothingIncremental
IoC LevelFull IoC (DI, Lifecycle)Limited IoC (hooks only)

๐ŸŽฏ When to Choose Whatโ€‹

Choose Library (React) when:โ€‹

  • You want flexibility and control
  • Existing codebase integration
  • Best-of-breed tool selection
  • Experienced team that can make architectural decisions

Choose Framework (Angular) when:โ€‹

  • You want opinionated structure
  • Large enterprise applications
  • Less experienced teams benefit from guidance
  • Consistency across projects
  • You need comprehensive IoC (DI, lifecycle management)

๐Ÿงฉ Meta Frameworks: Best of Both Worldsโ€‹

// Next.js - Framework features on React library
// pages/users/[id].js - File-based routing (Framework IoC)
export default function UserPage({ user }) {
return <div>{user.name}</div>; // Still React library
}

// Framework calls this (IoC)
export async function getServerSideProps(context) {
const user = await fetchUser(context.params.id);
return { props: { user } };
}

๐Ÿ”‘ Key Takeawayโ€‹

React is a library because:

  1. You control when and how to use it
  2. Limited IoC - only component lifecycle hooks
  3. No comprehensive DI system like frameworks
  4. No application structure enforced
  5. Incremental adoption possible
  6. You choose routing, state management, styling, etc.

The limited IoC in React (hooks, lifecycle) doesn't make it a framework because you still control the overall application flow and architectural decisions. React lacks the comprehensive IoC features like dependency injection that define true frameworks.

React focuses on one thing (UI) and does it excellently, giving you freedom to choose everything