🎯Ce este React?
React este o bibliotecă JavaScript pentru construirea interfețelor de utilizator (UI). Gândește-te la React ca la LEGO-uri pentru web - construiești aplicații complexe din piese mai mici numite componente.
De ce React?
- ✅ Componentizare - Cod reutilizabil și organizat
- ✅ Virtual DOM - Performanță optimizată
- ✅ Ecosistem bogat - Multe librării și resurse
- ✅ Popular în industrie - Multe joburi disponibile
🧩Concepte Fundamentale
1. Componente
Un component este ca o funcție care returnează JSX (HTML în JavaScript).
function Greeting() {
return <h1>Salut, lume!</h1>;
}
function Welcome(props) {
return <h1>Bună, {props.name}!</h1>;
}
<Welcome name="Maria" />
2. JSX (JavaScript XML)
JSX îți permite să scrii HTML în JavaScript:
✅ Reguli JSX importante:
- Un singur element părinte (sau React.Fragment
<>...</>)
className în loc de class
onClick în loc de onclick
- Expresiile JavaScript în
{}
function App() {
const name = "Ion";
const isLoggedIn = true;
return (
<div className="container">
<h1>Bună, {name}!</h1>
{isLoggedIn && <p>Ești conectat!</p>}
</div>
);
}
🏪State Management
State = datele componente tale care se pot schimba în timp.
useState Hook
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Ai apăsat de {count} ori</p>
<button onClick={() => setCount(count + 1)}>
Click aici
</button>
</div>
);
}
State cu Obiecte
function UserProfile() {
const [user, setUser] = useState({
name: '',
email: '',
age: 0
});
const updateName = (newName) => {
setUser({
...user,
name: newName
});
};
return (
<div>
<input
value={user.name}
onChange={(e) => updateName(e.target.value)}
placeholder="Numele tău"
/>
<p>Salut, {user.name}!</p>
</div>
);
}
⚠️ Reguli importante pentru State:
- State-ul este immutable - nu modifica direct!
- Folosește întotdeauna setter functions
- Actualizările sunt asincrone
📦Import/Export
Export
export const add = (a, b) => a + b;
export const subtract = (a, b) => a - b;
export default function multiply(a, b) {
return a * b;
}
Import
import { add, subtract } from './math.js';
import multiply from './math.js';
import React, { useState, useEffect } from 'react';
import Header from './components/Header';
import { Button, Input } from './components/UI';
🎮Event Handling
React folosește SyntheticEvents - evenimente native învelite.
function EventExamples() {
const [inputValue, setInputValue] = useState('');
const handleClick = () => {
alert('Buton apăsat!');
};
const handleInputChange = (event) => {
setInputValue(event.target.value);
};
const handleSubmit = (event) => {
event.preventDefault();
console.log('Form trimis:', inputValue);
};
return (
<form onSubmit={handleSubmit}>
<input
type="text"
value={inputValue}
onChange={handleInputChange}
placeholder="Scrie ceva..."
/>
<button type="submit" onClick={handleClick}>
Trimite
</button>
</form>
);
}
🔀Conditional Rendering
Afișează elemente diferite pe baza unor condiții.
function ConditionalExample() {
const [isLoggedIn, setIsLoggedIn] = useState(false);
return (
<div>
{isLoggedIn && <p>Bun venit!</p>}
{isLoggedIn ? (
<button onClick={() => setIsLoggedIn(false)}>
Logout
</button>
) : (
<button onClick={() => setIsLoggedIn(true)}>
Login
</button>
)}
</div>
);
}
📋Lists și Keys
Când afișezi liste, React are nevoie de keys unice.
function UserList() {
const users = [
{ id: 1, name: 'Ana', email: 'ana@email.com' },
{ id: 2, name: 'Ion', email: 'ion@email.com' },
{ id: 3, name: 'Maria', email: 'maria@email.com' }
];
return (
<div>
{users.map(user => (
<div key={user.id} className="user-card">
<h3>{user.name}</h3>
<p>{user.email}</p>
</div>
))}
</div>
);
}
💡 De ce sunt importante keys?
- Ajută React să identifice ce elemente s-au schimbat
- Îmbunătățesc performanța
- Evită bug-uri la reordonare
⚡useEffect Hook
useEffect rulează cod la momentele importante din viața componentei.
import React, { useState, useEffect } from 'react';
function EffectExamples() {
const [count, setCount] = useState(0);
useEffect(() => {
console.log('Component s-a reîncărcat');
});
useEffect(() => {
console.log('Component montat');
}, []);
useEffect(() => {
document.title = `Count: ${count}`;
}, [count]);
useEffect(() => {
const timer = setInterval(() => {
setCount(c => c + 1);
}, 1000);
return () => {
clearInterval(timer);
};
}, []);
return <p>Count: {count}</p>;
}
🏗️Exemplu Practic
Să construim o Mini Todo App pentru a aplica conceptele:
import React, { useState, useEffect } from 'react';
function MiniTodoApp() {
const [todos, setTodos] = useState([]);
const [inputValue, setInputValue] = useState('');
useEffect(() => {
const saved = localStorage.getItem('todos');
if (saved) {
setTodos(JSON.parse(saved));
}
}, []);
useEffect(() => {
localStorage.setItem('todos', JSON.stringify(todos));
}, [todos]);
const addTodo = () => {
if (inputValue.trim()) {
const newTodo = {
id: Date.now(),
text: inputValue.trim(),
completed: false
};
setTodos([...todos, newTodo]);
setInputValue('');
}
};
const toggleTodo = (id) => {
setTodos(todos.map(todo =>
todo.id === id
? { ...todo, completed: !todo.completed }
: todo
));
};
const deleteTodo = (id) => {
setTodos(todos.filter(todo => todo.id !== id));
};
return (
<div className="todo-app">
<h1>Mini Todo App</h1>
<input
type="text"
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
onKeyPress={(e) => e.key === 'Enter' && addTodo()}
/>
<button onClick={addTodo}>Adaugă</button>
<ul>
{todos.map(todo => (
<li key={todo.id}>
<input
type="checkbox"
checked={todo.completed}
onChange={() => toggleTodo(todo.id)}
/>
<span>{todo.text}</span>
<button onClick={() => deleteTodo(todo.id)}>❌</button>
</li>
))}
</ul>
</div>
);
}
🎯 Concepte Cheie de Reținut
- Unidirectional Data Flow - Datele curg de sus în jos prin props
- Immutability - Întotdeauna creezi copii noi pentru state
- Component Lifecycle - Mount, Update, Unmount
- Props vs State - Props = readonly, State = editabil
🚀 Următorii Pași
După ce înțelegi aceste concepte:
- React Router - Navigare între pagini
- Context API - State global
- Custom Hooks - Logică reutilizabilă
- Performance - React.memo, useMemo, useCallback
- Testing - Jest, React Testing Library
🎯 Întrebări și Răspunsuri React pentru Interviu
Colecție completă de întrebări organizate pe nivel de dificultate.
🔰 Întrebări de Bază
Începător
Q1: Ce este React și de ce îl folosim?
R: React este o bibliotecă JavaScript pentru construirea interfețelor de utilizator, dezvoltată de Facebook. Principalele avantaje:
- Component-based architecture - Cod reutilizabil și organizat
- Virtual DOM - Performanță optimizată prin actualizări eficiente
- Declarative - Descrii cum arată UI-ul, React se ocupă de "cum"
- Large ecosystem - Multe librării și tools disponibile
- Strong community - Suport activ și multe resurse
Începător
Q2: Ce este JSX?
R: JSX (JavaScript XML) este o extensie de sintaxă pentru JavaScript care îți permite să scrii markup-ul ca HTML în JavaScript.
const element = <h1>Hello, world!</h1>;
const element = React.createElement('h1', null, 'Hello, world!');
Reguli JSX:
- Un singur element părinte (sau Fragment)
className în loc de class
- CamelCase pentru atribute (
onClick, onChange)
- Expresii JavaScript în
{}
Începător
Q3: Diferența între componente funcționale și class components?
R:
| Functional Components |
Class Components |
| Mai simple și concise |
Mai verbose |
| Folosesc Hooks pentru state |
Folosesc this.state |
| Performanță ușor mai bună |
Performanță mai slabă |
| Modern, recomandat |
Legacy, depreciat |
Începător
Q4: Ce este Virtual DOM?
R: Virtual DOM este o reprezentare în memorie a DOM-ului real. React:
- Creează o copie virtuală a DOM-ului
- Compară (diffing) versiunea veche cu cea nouă
- Actualizează doar elementele care s-au schimbat în DOM-ul real
Avantaje: Actualizări mai rapide, Batch updates, Predictibilitate mai mare
🏪 State și Props
Începător
Q5: Ce este state-ul în React?
R: State-ul este un obiect care stochează datele componente care se pot schimba în timp. Când state-ul se schimbă, componenta se re-renderează.
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>{count}</p>
<button onClick={() => setCount(count + 1)}>+</button>
</div>
);
}
Reguli importante:
- State-ul este immutable - nu modifica direct
- Folosește setter functions
- Actualizările sunt asincrone
Începător
Q6: Diferența între props și state?
R:
| Props |
State |
| Date primite de la părinte |
Date proprii ale componentei |
| Read-only (immutable) |
Mutabile prin setState |
| Trec de sus în jos |
Locale componentei |
| Funcție de input |
Date interne |
Intermediar
Q7: Cum actualizezi state-ul cu obiecte și array-uri?
R: Întotdeauna creezi o copie nouă (immutability):
const [items, setItems] = useState([]);
items.push(newItem);
setItems(items);
setItems([...items, newItem]);
setItems(items.filter(item => item.id !== deleteId));
const [user, setUser] = useState({ name: '', age: 0 });
user.name = 'New Name';
setUser(user);
setUser({ ...user, name: 'New Name' });
setUser(prev => ({ ...prev, age: prev.age + 1 }));
🎣 Hooks
Intermediar
Q8: Ce sunt React Hooks?
R: Hooks sunt funcții care îți permit să "te conectezi" la funcționalitățile React (state, lifecycle) din componente funcționale.
Hooks principale:
useState - Pentru state local
useEffect - Pentru side effects
useContext - Pentru consumarea context-ului
useReducer - Pentru state management complex
useMemo - Pentru memoization
useCallback - Pentru memoization de funcții
Reguli Hooks:
- Apelează doar la top level (nu în loops, conditions)
- Doar în React functions (components sau custom hooks)
Începător
Q9: Când folosești useEffect?
R: useEffect pentru side effects:
useEffect(() => {
});
useEffect(() => {
}, []);
useEffect(() => {
}, [dependency1, dependency2]);
useEffect(() => {
const timer = setInterval(() => {}, 1000);
return () => clearInterval(timer);
}, []);
Cazuri de utilizare: API calls, Subscriptions, Timers, DOM manipulation, Cleanup
Intermediar
Q10: Ce este dependency array în useEffect?
R: Dependency array controlează când se execută useEffect:
useEffect(() => {
console.log('Every render');
});
useEffect(() => {
console.log('Only once');
}, []);
useEffect(() => {
console.log('When count changes');
}, [count]);
⚠️ ESLint Warning: Întotdeauna include toate dependencies folosite în effect.
🚀 Performance
Avansat
Q11: Cum optimizezi performanța în React?
R: Există mai multe tehnici:
1. React.memo
Previne re-renderuri inutile:
const MyComponent = React.memo(function MyComponent({ name }) {
return <div>{name}</div>;
});
2. useMemo
Memoizează calcule costisitoare:
const expensiveValue = useMemo(() => {
return items.reduce((sum, item) => sum + item.value, 0);
}, [items]);
3. useCallback
Memoizează funcții:
const handleClick = useCallback((id) => {
}, []);
Intermediar
Q12: Când folosești useMemo vs useCallback?
R:
- useMemo - Pentru valori calculate
- useCallback - Pentru funcții
const expensiveValue = useMemo(() => {
return calculateSomething(data);
}, [data]);
const memoizedCallback = useCallback((param) => {
doSomething(param);
}, [dependency]);
🔥 Întrebări Avansate
Avansat
Q13: Ce este Context API?
R: Context API permite trecerea datelor prin component tree fără prop drilling:
const ThemeContext = React.createContext('light');
function App() {
return (
<ThemeContext.Provider value="dark">
<Toolbar />
</ThemeContext.Provider>
);
}
function Button() {
const theme = useContext(ThemeContext);
return <button className={theme}>Click me</button>;
}
Avansat
Q14: Ce este useReducer și când îl folosești?
R: useReducer este o alternativă la useState pentru state management complex:
const initialState = { count: 0 };
function reducer(state, action) {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
case 'decrement':
return { count: state.count - 1 };
default:
throw new Error();
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<div>
Count: {state.count}
<button onClick={() => dispatch({ type: 'increment' })}>+</button>
</div>
);
}
Când să folosești: State complex cu multiple sub-valori, Logică complexă de actualizare, Next state depinde de previous state
Intermediar
Q15: Ce sunt Custom Hooks?
R: Custom Hooks sunt funcții care îți permit să reutilizezi logică stateful între componente:
function useLocalStorage(key, initialValue) {
const [value, setValue] = useState(() => {
const saved = localStorage.getItem(key);
return saved ? JSON.parse(saved) : initialValue;
});
useEffect(() => {
localStorage.setItem(key, JSON.stringify(value));
}, [key, value]);
return [value, setValue];
}
function App() {
const [name, setName] = useLocalStorage('name', '');
return <input value={name} onChange={(e) => setName(e.target.value)} />;
}
Convenții: Numele începe cu "use", Poate folosi alți Hooks
Avansat
Q16: Ce sunt Error Boundaries?
R: Error Boundaries sunt componente care prind erorile JavaScript oriunde în component tree-ul lor:
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
console.log('Error:', error, errorInfo);
}
render() {
if (this.state.hasError) {
return <h1>Something went wrong.</h1>;
}
return this.props.children;
}
}
<ErrorBoundary>
<MyComponent />
</ErrorBoundary>
💻 Întrebări Coding
Intermediar
Q17: Creează un component de Counter cu increment, decrement și reset
R:
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
const increment = () => setCount(count + 1);
const decrement = () => setCount(count - 1);
const reset = () => setCount(0);
return (
<div>
<h2>Count: {count}</h2>
<button onClick={increment}>+</button>
<button onClick={decrement}>-</button>
<button onClick={reset}>Reset</button>
</div>
);
}
export default Counter;
Intermediar
Q18: Implementează un component care face fetch de date de la un API
R:
import React, { useState, useEffect } from 'react';
function UserList() {
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
fetch('https://jsonplaceholder.typicode.com/users')
.then(response => {
if (!response.ok) {
throw new Error('Network error');
}
return response.json();
})
.then(data => {
setUsers(data);
setLoading(false);
})
.catch(error => {
setError(error.message);
setLoading(false);
});
}, []);
if (loading) return <p>Loading...</p>;
if (error) return <p>Error: {error}</p>;
return (
<ul>
{users.map(user => (
<li key={user.id}>{user.name} - {user.email}</li>
))}
</ul>
);
}
export default UserList;
Avansat
Q19: Creează un custom hook pentru form handling
R:
import { useState } from 'react';
function useForm(initialValues) {
const [values, setValues] = useState(initialValues);
const handleChange = (e) => {
const { name, value } = e.target;
setValues({
...values,
[name]: value
});
};
const resetForm = () => {
setValues(initialValues);
};
return { values, handleChange, resetForm };
}
function LoginForm() {
const { values, handleChange, resetForm } = useForm({
email: '',
password: ''
});
const handleSubmit = (e) => {
e.preventDefault();
console.log('Form values:', values);
resetForm();
};
return (
<form onSubmit={handleSubmit}>
<input
name="email"
value={values.email}
onChange={handleChange}
placeholder="Email"
/>
<input
name="password"
type="password"
value={values.password}
onChange={handleChange}
placeholder="Password"
/>
<button type="submit">Login</button>
</form>
);
}
Avansat
Q20: Implementează un debounced search input
R:
import React, { useState, useEffect } from 'react';
function useDebounce(value, delay) {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const handler = setTimeout(() => {
setDebouncedValue(value);
}, delay);
return () => {
clearTimeout(handler);
};
}, [value, delay]);
return debouncedValue;
}
function SearchComponent() {
const [searchTerm, setSearchTerm] = useState('');
const [results, setResults] = useState([]);
const debouncedSearchTerm = useDebounce(searchTerm, 500);
useEffect(() => {
if (debouncedSearchTerm) {
fetch(`/api/search?q=${debouncedSearchTerm}`)
.then(res => res.json())
.then(data => setResults(data));
} else {
setResults([]);
}
}, [debouncedSearchTerm]);
return (
<div>
<input
type="text"
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
placeholder="Search..."
/>
<ul>
{results.map(result => (
<li key={result.id}>{result.name}</li>
))}
</ul>
</div>
);
}
🎓 Concepte Avansate
Avansat
Q21: Explică React Reconciliation și diffing algorithm
R: Reconciliation este procesul prin care React actualizează DOM-ul:
- Virtual DOM Comparison - React compară Virtual DOM-ul vechi cu cel nou
- Diffing Algorithm - React folosește un algoritm de tip "heuristic" O(n) în loc de O(n³)
- Batch Updates - React grupează actualizările pentru eficiență
Reguli de optimizare:
- Două elemente de tipuri diferite produc arbori diferiți
- Dezvoltatorul poate sugera care elemente sunt stabile folosind
key prop
- React reutilizează componentele când este posibil
Avansat
Q22: Ce este React.StrictMode?
R: StrictMode este un tool pentru evidențierea problemelor potențiale în aplicație:
import React from 'react';
function App() {
return (
<React.StrictMode>
<MyApp />
</React.StrictMode>
);
}
Ce face StrictMode:
- Identifică componente cu lifecycle methods nesigure
- Avertizează despre folosirea legacy string ref API
- Avertizează despre deprecated findDOMNode usage
- Detectează side effects neașteptate
- Detectează legacy context API
⚠️ Notă: StrictMode renderează componentele de două ori în development pentru a detecta side effects.
Intermediar
Q23: Diferența între Controlled și Uncontrolled Components?
R:
| Controlled Components |
Uncontrolled Components |
| React controlează valoarea |
DOM-ul controlează valoarea |
| Folosește state pentru valoare |
Folosește ref pentru a accesa valoarea |
| Mai predictibil |
Mai puțin cod boilerplate |
| Recomandat pentru majoritatea cazurilor |
Folosit pentru file inputs și legacy code |
function ControlledInput() {
const [value, setValue] = useState('');
return (
<input
value={value}
onChange={(e) => setValue(e.target.value)}
/>
);
}
function UncontrolledInput() {
const inputRef = useRef();
const handleSubmit = () => {
console.log(inputRef.current.value);
};
return <input ref={inputRef} />;
}
💡 Tips pentru Interviu
Strategii de răspuns:
- ✅ Începe cu o definiție clară și concisă
- ✅ Dă exemple de cod când este relevant
- ✅ Menționează cazuri de utilizare practice
- ✅ Compară cu alternative (ex: useState vs useReducer)
- ✅ Discută despre best practices și pitfalls
- ✅ Arată că înțelegi când să folosești fiecare tehnică
- ✅ Menționează trade-offs și performance considerations
❌ Greșeli comune de evitat:
- Nu modifica state-ul direct
- Nu uita de key props în liste
- Nu uita de cleanup în useEffect
- Nu folosi index ca key pentru liste dinamice
- Nu uita să incluzi toate dependencies în useEffect
📚 Resurse pentru pregătire suplimentară:
🎯 Sfaturi finale pentru interviu:
- Comunică gândirea ta - Explică ce faci și de ce
- Pune întrebări - Clarifică cerințele înainte să codezi
- Testează-ți codul - Gândește-te la edge cases
- Optimizează treptat - Începe cu o soluție simplă, apoi optimizează
- Menționează alternativele - Arată că știi mai multe abordări
- Fii onest - Dacă nu știi ceva, spune și arată că ești dornic să înveți