Library is a collection of functions and components that developers can use as needed, maintaining control over the application architecture. Framework is a more comprehensive solution that dictates the application structure and provides a ready-made architecture.
React is a library because:
A library is a set of ready-made functions, classes, and components that can be connected to a project and used as needed. A library does not dictate the application architecture and does not limit the developer in choosing approaches.
// Example of using the Lodash library
import { debounce, throttle } from 'lodash';
// Can use only the necessary functions
const debouncedHandler = debounce(handleInput, 300);
const throttledScroll = throttle(handleScroll, 100);
A framework is a comprehensive solution that provides a ready-made application architecture, a set of rules and constraints. A framework dictates how the application should be structured and how its components should interact.
// Example of Angular structure (framework)
import { Component } from '@angular/core';
@Component({
selector: 'app-user',
template: '<h1>{{name}}</h1>'
})
export class UserComponent {
name = 'Alexander';
// Must follow Angular rules
ngOnInit() {
// Initialization logic
}
}
React is officially positioned as a library, not a framework. This is because React provides only tools for working with the user interface and does not dictate how to structure the entire application.
React does not require using a specific application architecture:
// Can use different approaches to structure
// Approach 1: Simple component
function App() {
return <div>Hello, world!</div>;
}
// Approach 2: With state
function App() {
const [count, setCount] = useState(0);
return (
<div>
<p>Counter: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
// Approach 3: Using Redux
function App() {
const count = useSelector(state => state.count);
const dispatch = useDispatch();
return (
<div>
<p>Counter: {count}</p>
<button onClick={() => dispatch(increment())}>Increment</button>
</div>
);
}
React easily integrates with other libraries and tools:
// Using React with a chart library
import { Line } from 'react-chartjs-2';
import { useQuery } from 'react-query';
function Dashboard() {
// Using react-query for API work
const { data, isLoading } = useQuery('users', fetchUsers);
if (isLoading) return <div>Loading...</div>;
// Using react-chartjs-2 for displaying charts
const chartData = {
labels: data.map(user => user.name),
datasets: [{
label: 'Activity',
data: data.map(user => user.activity)
}]
};
return <Line data={chartData} />;
}
React does not require a strict file and folder structure:
// Structure 1: By types
src/
components/
Button.jsx
Card.jsx
pages/
Home.jsx
Profile.jsx
utils/
api.js
helpers.js
// Structure 2: By functionality
src/
auth/
components/
LoginForm.jsx
pages/
Login.jsx
utils/
auth.js
dashboard/
components/
Chart.jsx
pages/
Dashboard.jsx
In React, the developer controls the application execution flow:
// Developer controls when and how state is updated
function TodoApp() {
const [todos, setTodos] = useState([]);
const [filter, setFilter] = useState('all');
// Control task addition
const addTodo = (text) => {
const newTodo = {
id: Date.now(),
text,
completed: false
};
setTodos([...todos, newTodo]);
};
// Control filtering
const filteredTodos = todos.filter(todo => {
if (filter === 'active') return !todo.completed;
if (filter === 'completed') return todo.completed;
return true;
});
return (
<div>
<TodoForm onAdd={addTodo} />
<TodoFilter currentFilter={filter} onChange={setFilter} />
<TodoList todos={filteredTodos} />
</div>
);
}
Characteristic | React | Angular |
---|---|---|
Type | Library | Framework |
Structure | Flexible | Strict |
Language | JavaScript/JSX | TypeScript |
Control | Developer | Framework |
Size | Smaller | Larger |
Learning | Easier | Harder |
// React - developer controls state management
import { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
// Full control over state updates
const increment = () => setCount(count + 1);
const decrement = () => setCount(count - 1);
const reset = () => setCount(0);
return (
<div>
<p>Counter: {count}</p>
<button onClick={increment}>+</button>
<button onClick={decrement}>-</button>
<button onClick={reset}>Reset</button>
</div>
);
}
// Angular - framework dictates structure
import { Component } from '@angular/core';
@Component({
selector: 'app-counter',
template: `
<div>
<p>Counter: {{ count }}</p>
<button (click)="increment()">+</button>
<button (click)="decrement()">-</button>
<button (click)="reset()">Reset</button>
</div>
`
})
export class CounterComponent {
count = 0;
// Must follow Angular rules
increment() {
this.count++;
}
decrement() {
this.count--;
}
reset() {
this.count = 0;
}
}
Characteristic | React | Vue |
---|---|---|
Type | Library | Framework |
Templates | JSX | HTML templates |
Reactivity | useState/useReducer | Reactive data |
Ecosystem | Large | Growing |
// React - imperative approach to reactivity
function UserCard({ user }) {
const [isEditing, setIsEditing] = useState(false);
const [name, setName] = useState(user.name);
const save = () => {
// Manually update state
updateUser(user.id, { name });
setIsEditing(false);
};
return (
<div>
{isEditing ? (
<input
value={name}
onChange={(e) => setName(e.target.value)}
/>
) : (
<h2>{name}</h2>
)}
<button onClick={() => setIsEditing(!isEditing)}>
{isEditing ? 'Save' : 'Edit'}
</button>
</div>
);
}
<!-- Vue - declarative approach to reactivity -->
<template>
<div>
<input v-if="isEditing" v-model="name" />
<h2 v-else>{{ name }}</h2>
<button @click="toggleEdit">
{{ isEditing ? 'Save' : 'Edit' }}
</button>
</div>
</template>
<script>
export default {
props: ['user'],
data() {
return {
isEditing: false,
name: this.user.name
}
},
methods: {
toggleEdit() {
this.isEditing = !this.isEditing;
if (!this.isEditing) {
this.updateUser();
}
},
updateUser() {
// Vue automatically tracks changes
this.$emit('update-user', this.user.id, { name: this.name });
}
}
}
</script>
Library allows choosing only the necessary tools:
// Can use only the necessary parts
import { useState } from 'react'; // Only state hook
// No need to connect the entire React
function SimpleComponent() {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(count + 1)}>{count}</button>;
}
Library does not impose strict constraints on development:
// Can use different approaches to styling
import './Button.css'; // CSS modules
import styled from 'styled-components'; // CSS-in-JS
import { css } from '@emotion/react'; // Emotion
// All approaches are compatible with React
Library is easier to learn as it does not require knowledge of the entire architecture:
// Enough to know the basics to get started
function Hello() {
return <h1>Hello, world!</h1>;
}
// ReactDOM.render(<Hello />, document.getElementById('root'));
Developers need to independently choose architecture and additional tools:
// Need to choose how to manage state
// Option 1: useState
const [users, setUsers] = useState([]);
// Option 2: Redux
const users = useSelector(state => state.users);
// Option 3: Context API
const { users } = useContext(UserContext);
// Option 4: Zustand
const { users } = useUserStore();
For some tasks, more code may be required:
// React - need to implement routing independently
import { useState, useEffect } from 'react';
function Router() {
const [currentPath, setCurrentPath] = useState(window.location.pathname);
useEffect(() => {
const onLocationChange = () => {
setCurrentPath(window.location.pathname);
};
window.addEventListener('popstate', onLocationChange);
return () => window.removeEventListener('popstate', onLocationChange);
}, []);
return (
<div>
{currentPath === '/' && <HomePage />}
{currentPath === '/about' && <AboutPage />}
{currentPath === '/contact' && <ContactPage />}
</div>
);
}
// With a framework this would be simpler
Without a strict architecture, inconsistency in approaches may arise:
// Developer 1 uses one approach
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
useEffect(() => {
fetchUser(userId).then(setUser);
}, [userId]);
return user ? <div>{user.name}</div> : <div>Loading...</div>;
}
// Developer 2 uses another approach
class UserProfile extends React.Component {
constructor(props) {
super(props);
this.state = { user: null };
}
componentDidMount() {
fetchUser(this.props.userId).then(user => {
this.setState({ user });
});
}
render() {
return this.state.user ?
<div>{this.state.user.name}</div> :
<div>Loading...</div>;
}
}
// Good for integration into existing applications
// Adding React component to jQuery application
$('#react-container').each(function() {
const props = JSON.parse($(this).data('props'));
ReactDOM.render(<LegacyIntegration {...props} />, this);
});
// Angular - everything included "out of the box"
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule } from '@angular/common/http';
import { ReactiveFormsModule } from '@angular/forms';
@NgModule({
imports: [
BrowserModule,
HttpClientModule,
ReactiveFormsModule
// Everything necessary is already included
],
// Automatic dependency injection setup
})
export class AppModule { }
React is a library, not a framework, because:
✅ Flexibility — does not dictate application architecture ✅ Integration — easily combines with other tools ✅ Control — developer controls execution flow ✅ Modularity — can use only necessary parts
Key differences:
Choice depends on:
Understanding these differences helps make more informed decisions when choosing technologies for a project.
Want more articles for interview preparation? Subscribe to EasyAdvice, bookmark the site, and improve yourself every day 💪