🚀 React pentru Începători

Tutorial complet + Întrebări de interviu

🎯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).

// Component simplu function Greeting() { return <h1>Salut, lume!</h1>; } // Component cu parametri (props) function Welcome(props) { return <h1>Bună, {props.name}!</h1>; } // Utilizare <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() { // Declarăm o variabilă de state numită "count" const [count, setCount] = useState(0); // ↑ ↑ ↑ // valoare setter val. inițială 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, // Copiază tot obiectul name: newName // Actualizează doar name }); }; 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

// math.js - Export named export const add = (a, b) => a + b; export const subtract = (a, b) => a - b; // Export default export default function multiply(a, b) { return a * b; }

Import

// Import named exports import { add, subtract } from './math.js'; // Import default export import multiply from './math.js'; // Import React și hooks import React, { useState, useEffect } from 'react'; // Import componente 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(''); // Click handler const handleClick = () => { alert('Buton apăsat!'); }; // Input handler const handleInputChange = (event) => { setInputValue(event.target.value); }; // Form submit const handleSubmit = (event) => { event.preventDefault(); // Previne reîncărcarea paginii 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> {/* Conditional simplu cu && */} {isLoggedIn && <p>Bun venit!</p>} {/* Ternary operator */} {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); // 1. Rulează după fiecare render useEffect(() => { console.log('Component s-a reîncărcat'); }); // 2. Rulează doar o dată (la mount) useEffect(() => { console.log('Component montat'); }, []); // Array gol = doar la mount // 3. Rulează când se schimbă count useEffect(() => { document.title = `Count: ${count}`; }, [count]); // Se execută când count se schimbă // 4. Cleanup (curățenie) useEffect(() => { const timer = setInterval(() => { setCount(c => c + 1); }, 1000); // Cleanup function 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() { // State management const [todos, setTodos] = useState([]); const [inputValue, setInputValue] = useState(''); // Load from localStorage useEffect(() => { const saved = localStorage.getItem('todos'); if (saved) { setTodos(JSON.parse(saved)); } }, []); // Save to localStorage useEffect(() => { localStorage.setItem('todos', JSON.stringify(todos)); }, [todos]); // Functions 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

  1. Unidirectional Data Flow - Datele curg de sus în jos prin props
  2. Immutability - Întotdeauna creezi copii noi pentru state
  3. Component Lifecycle - Mount, Update, Unmount
  4. 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.

// JSX const element = <h1>Hello, world!</h1>; // Se transpune în: 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:

  1. Creează o copie virtuală a DOM-ului
  2. Compară (diffing) versiunea veche cu cea nouă
  3. 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):

// Array const [items, setItems] = useState([]); // ❌ Greșit items.push(newItem); setItems(items); // ✅ Corect setItems([...items, newItem]); setItems(items.filter(item => item.id !== deleteId)); // Object const [user, setUser] = useState({ name: '', age: 0 }); // ❌ Greșit user.name = 'New Name'; setUser(user); // ✅ Corect 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:

// Mount și update useEffect(() => { // cod }); // Doar la mount useEffect(() => { // cod }, []); // Când se schimbă dependencies useEffect(() => { // cod }, [dependency1, dependency2]); // Cu cleanup useEffect(() => { const timer = setInterval(() => {}, 1000); return () => clearInterval(timer); // cleanup }, []);

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:

// Fără array - rulează la fiecare render useEffect(() => { console.log('Every render'); }); // Array gol - rulează doar o dată (mount) useEffect(() => { console.log('Only once'); }, []); // Cu dependencies - rulează când se schimbă 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) => { // handle click }, []);
Intermediar

Q12: Când folosești useMemo vs useCallback?

R:

  • useMemo - Pentru valori calculate
  • useCallback - Pentru funcții
// useMemo - pentru valori const expensiveValue = useMemo(() => { return calculateSomething(data); }, [data]); // useCallback - pentru funcții 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:

// Crearea context-ului const ThemeContext = React.createContext('light'); // Provider function App() { return ( <ThemeContext.Provider value="dark"> <Toolbar /> </ThemeContext.Provider> ); } // Consumer cu useContext 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:

// Custom Hook 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]; } // Utilizare 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; } } // Utilizare <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'; // Custom Hook 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 }; } // Utilizare 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'; // Custom Hook pentru debounce function useDebounce(value, delay) { const [debouncedValue, setDebouncedValue] = useState(value); useEffect(() => { const handler = setTimeout(() => { setDebouncedValue(value); }, delay); return () => { clearTimeout(handler); }; }, [value, delay]); return debouncedValue; } // Component function SearchComponent() { const [searchTerm, setSearchTerm] = useState(''); const [results, setResults] = useState([]); const debouncedSearchTerm = useDebounce(searchTerm, 500); useEffect(() => { if (debouncedSearchTerm) { // Simulare API call 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:

  1. Virtual DOM Comparison - React compară Virtual DOM-ul vechi cu cel nou
  2. Diffing Algorithm - React folosește un algoritm de tip "heuristic" O(n) în loc de O(n³)
  3. 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
// Controlled Component function ControlledInput() { const [value, setValue] = useState(''); return ( <input value={value} onChange={(e) => setValue(e.target.value)} /> ); } // Uncontrolled Component 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