# Top 30 Pertanyaan Wawancara React: Panduan Lengkap untuk Sukses
> 30 pertanyaan wawancara React paling sering ditanyakan pada 2026. Jawaban rinci, contoh kode, dan tips untuk mendapatkan posisi React developer.
- Published: 2026-01-31
- Updated: 2026-04-21
- Author: SharpSkill
- Tags: react interview, frontend interview, react questions, javascript, technical interview
- Reading time: 18 min
---
Wawancara teknis React mengukur pemahaman terhadap konsep dasar, pola lanjutan, dan praktik terbaik. Panduan ini menyajikan 30 pertanyaan yang paling sering muncul, lengkap dengan jawaban rinci dan contoh kode untuk persiapan yang efektif.
> **Saran persiapan**
>
> Pertanyaan-pertanyaan ini disusun berdasarkan tingkat kesulitan. Menguasai dasar sebelum beralih ke konsep lanjutan memungkinkan persiapan yang lebih terstruktur.
## Dasar-dasar React
### 1. Apa itu Virtual DOM dan mengapa React menggunakannya?
Virtual DOM adalah representasi JavaScript yang ringan dari DOM sebenarnya. React memanfaatkan abstraksi ini untuk mengoptimalkan pembaruan antarmuka.
Prosesnya berlangsung dalam tiga langkah: React pertama-tama membuat salinan virtual dari DOM, kemudian membandingkan salinan tersebut dengan versi sebelumnya ketika terjadi perubahan (algoritma diffing), lalu menerapkan hanya modifikasi yang diperlukan pada DOM sebenarnya (rekonsiliasi).
```jsx
// Simplified example of the concept
// When state changes, React doesn't recreate the entire DOM
function Counter() {
const [count, setCount] = useState(0)
// Only the span containing count will be updated in the real DOM
// The rest of the component is untouched
return (
Counter
{count}
)
}
```
Pendekatan ini menghindari operasi DOM yang mahal dan memungkinkan pembaruan yang cepat bahkan untuk antarmuka yang kompleks.
### 2. Apa perbedaan antara komponen fungsional dan komponen kelas?
Komponen fungsional adalah fungsi JavaScript yang menerima props dan mengembalikan JSX. Sejak React 16.8, hooks memungkinkan penggunaan state dan siklus hidup dalam komponen fungsional.
```jsx
// Functional component (recommended)
// More concise, easier to test, supports hooks
function Welcome({ name }) {
const [visits, setVisits] = useState(0)
useEffect(() => {
setVisits(v => v + 1)
}, [])
return
Hello {name}, visit #{visits}
}
// Class component (legacy)
// More verbose, requires this binding
class WelcomeClass extends React.Component {
state = { visits: 0 }
componentDidMount() {
this.setState(prev => ({ visits: prev.visits + 1 }))
}
render() {
return
}
}
```
Komponen fungsional kini menjadi standar. Komponen kelas tetap didukung tetapi tidak lagi direkomendasikan untuk proyek baru.
### 3. Bagaimana JSX bekerja?
JSX merupakan ekstensi sintaks JavaScript yang memungkinkan penulisan markup di dalam kode. JSX bukanlah HTML, melainkan JavaScript dalam bentuk yang disamarkan.
```jsx
// What we write (JSX)
const element = (
Title
Paragraph
)
// What Babel compiles (pure JavaScript)
const element = React.createElement(
'div',
{ className: 'container' },
React.createElement('h1', null, 'Title'),
React.createElement('p', null, 'Paragraph')
)
```
Perbedaan dengan HTML mencakup: `className` alih-alih `class`, `htmlFor` alih-alih `for`, camelCase untuk atribut (`onClick`, `tabIndex`), dan keharusan menutup tag self-closing.
### 4. Apa perbedaan state dan props?
Props adalah data yang diteruskan dari komponen induk ke komponen anak. Props bersifat hanya baca. State merupakan kondisi internal suatu komponen yang dapat diubah melalui setter.
```jsx
// UserCard.jsx
// name and role are props (immutable)
function UserCard({ name, role }) {
// isExpanded is state (mutable)
const [isExpanded, setIsExpanded] = useState(false)
return (
{name}
{role}
{/* Modifying state triggers a re-render */}
{isExpanded && }
)
}
// Usage
```
Aturan mendasarnya: props mengalir ke bawah (induk → anak), sedangkan state bersifat lokal untuk setiap komponen.
### 5. Mengapa key penting dalam daftar?
Key membantu React mengidentifikasi elemen mana yang berubah, ditambahkan, atau dihapus dalam suatu daftar. Tanpa key yang unik dan stabil, React bisa menunjukkan perilaku yang tidak terduga.
```jsx
// ❌ Bad practice: index as key
// Problem: if order changes, React loses tracking
{items.map((item, index) => (
))}
// ✅ Good practice: unique and stable identifier
{items.map(item => (
))}
// Concrete example of the problem with indices
function TodoList() {
const [todos, setTodos] = useState([
{ id: 1, text: 'Learn React' },
{ id: 2, text: 'Create a project' }
])
// When deleting the first element with key={index}
// React will think element 0's content changed
// instead of understanding an element was removed
return (
{todos.map(todo => (
{todo.text}
))}
)
}
```
## React Hooks
### 6. Jelaskan useState dan jebakan umumnya
`useState` mengelola state lokal dalam komponen fungsional. Setter dapat menerima sebuah nilai atau sebuah fungsi pembaru.
```jsx
// Declaration with initial value
const [count, setCount] = useState(0)
// ❌ Pitfall: multiple updates in the same cycle
function increment() {
setCount(count + 1) // count = 0, sets 1
setCount(count + 1) // count = 0 still, sets 1
setCount(count + 1) // count = 0 still, sets 1
// Final result: 1 (not 3)
}
// ✅ Solution: use the update function
function incrementCorrect() {
setCount(prev => prev + 1) // 0 → 1
setCount(prev => prev + 1) // 1 → 2
setCount(prev => prev + 1) // 2 → 3
// Final result: 3
}
// ❌ Pitfall: object mutation
const [user, setUser] = useState({ name: 'Alice', age: 25 })
user.age = 26 // Direct mutation, no re-render
// ✅ Solution: create a new object
setUser({ ...user, age: 26 })
// or
setUser(prev => ({ ...prev, age: 26 }))
```
### 7. Bagaimana useEffect bekerja dengan array dependensinya?
`useEffect` menjalankan efek samping setelah render. Array dependensi mengendalikan kapan efek tersebut dieksekusi.
```jsx
// Executed on every render (rare, usually avoid)
useEffect(() => {
console.log('Render completed')
})
// Executed only on mount (equivalent to componentDidMount)
useEffect(() => {
console.log('Component mounted')
// Cleanup on unmount (equivalent to componentWillUnmount)
return () => {
console.log('Component unmounted')
}
}, [])
// Executed when userId changes
useEffect(() => {
async function fetchUser() {
const response = await fetch(`/api/users/${userId}`)
const data = await response.json()
setUser(data)
}
fetchUser()
}, [userId])
// ❌ Missing dependency - subtle bug
useEffect(() => {
const timer = setInterval(() => {
setCount(count + 1) // count is "captured" at its initial value
}, 1000)
return () => clearInterval(timer)
}, []) // count is missing from dependencies
// ✅ Fix with update function
useEffect(() => {
const timer = setInterval(() => {
setCount(prev => prev + 1) // No need for count in deps
}, 1000)
return () => clearInterval(timer)
}, [])
```
> **Aturan ESLint**
>
> Sebaiknya `eslint-plugin-react-hooks` selalu diaktifkan untuk mendeteksi dependensi yang hilang. Aturan ini mencegah banyak bug yang sulit didiagnosis.
### 8. Kapan sebaiknya menggunakan useMemo dan useCallback?
Kedua hook ini memungkinkan memoisasi agar tidak terjadi perhitungan ulang atau pembuatan ulang yang tidak perlu. Namun, keduanya sebaiknya tidak digunakan secara berlebihan.
```jsx
// useMemo: memoizes a computed value
function ProductList({ products, filter }) {
// Recalculated only if products or filter change
const filteredProducts = useMemo(() => {
console.log('Filtering...')
return products.filter(p => p.category === filter)
}, [products, filter])
return
{filteredProducts.map(p =>
{p.name}
)}
}
// useCallback: memoizes a function
function ParentComponent() {
const [count, setCount] = useState(0)
// Without useCallback, handleClick is recreated on every render
// Causing unnecessary re-renders of ExpensiveChild
const handleClick = useCallback((id) => {
console.log('Clicked:', id)
}, []) // Empty deps = stable function
return (
<>
{count}
{/* React.memo on ExpensiveChild for this to be effective */}
>
)
}
// ❌ Over-optimization: not needed here
const SimpleComponent = () => {
// This calculation is trivial, useMemo adds overhead
const doubled = useMemo(() => 2 * 2, [])
return {doubled}
}
```
Kedua hook ini sebaiknya digunakan hanya ketika ditemukan masalah performa nyata atau untuk menjaga stabilitas referensi yang diteruskan ke komponen yang dimemoisasi.
### 9. Bagaimana useRef bekerja dan apa saja kasus penggunaannya?
`useRef` menciptakan referensi yang dapat berubah dan bertahan antar-render tanpa memicu render ulang ketika nilainya berubah.
```jsx
// Case 1: Access a DOM element
function TextInput() {
const inputRef = useRef(null)
const focusInput = () => {
inputRef.current.focus()
}
return (
<>
>
)
}
// Case 2: Store a mutable value without re-render
function Timer() {
const [seconds, setSeconds] = useState(0)
const intervalRef = useRef(null)
const start = () => {
// Store the interval ID to be able to stop it
intervalRef.current = setInterval(() => {
setSeconds(s => s + 1)
}, 1000)
}
const stop = () => {
clearInterval(intervalRef.current)
}
return (
{seconds}s
)
}
// Case 3: Keep the previous value
function usePrevious(value) {
const ref = useRef()
useEffect(() => {
ref.current = value
}, [value])
return ref.current
}
```
### 10. Jelaskan useContext dan kapan menggunakannya
`useContext` memberikan akses ke React context tanpa harus menurunkan props berlapis-lapis. Ideal untuk data global seperti tema atau pengguna yang sedang login.
```jsx
// 1. Create the context
const ThemeContext = createContext({
theme: 'light',
toggleTheme: () => {}
})
// 2. Create the provider
function ThemeProvider({ children }) {
const [theme, setTheme] = useState('light')
const toggleTheme = useCallback(() => {
setTheme(prev => prev === 'light' ? 'dark' : 'light')
}, [])
// Memoize the value to avoid unnecessary re-renders
const value = useMemo(() => ({ theme, toggleTheme }), [theme, toggleTheme])
return (
{children}
)
}
// 3. Use the context
function ThemedButton() {
const { theme, toggleTheme } = useContext(ThemeContext)
return (
)
}
// 4. Wrap the application
function App() {
return (
)
}
```
## Pola lanjutan
### 11. Apa itu Higher-Order Component (HOC)?
HOC adalah fungsi yang menerima sebuah komponen dan mengembalikan komponen baru yang telah diperluas. Penggunaannya lebih jarang sejak adanya hooks, namun masih ditemui di beberapa library.
```jsx
// HOC that adds logging
function withLogging(WrappedComponent) {
return function WithLogging(props) {
useEffect(() => {
console.log(`${WrappedComponent.name} mounted with props:`, props)
return () => {
console.log(`${WrappedComponent.name} unmounted`)
}
}, [])
return
}
}
// HOC that handles authentication
function withAuth(WrappedComponent) {
return function WithAuth(props) {
const { user, isLoading } = useAuth()
if (isLoading) return
if (!user) return
return
}
}
// Usage
const ProtectedDashboard = withAuth(Dashboard)
const LoggedButton = withLogging(Button)
```
### 12. Jelaskan pola Render Props
Pola Render Props berbagi logika antar-komponen melalui prop yang berupa fungsi.
```jsx
// Component with render prop
function MouseTracker({ render }) {
const [position, setPosition] = useState({ x: 0, y: 0 })
useEffect(() => {
const handleMove = (e) => {
setPosition({ x: e.clientX, y: e.clientY })
}
window.addEventListener('mousemove', handleMove)
return () => window.removeEventListener('mousemove', handleMove)
}, [])
// Call the render function with data
return render(position)
}
// Usage
function App() {
return (
(
Position: {x}, {y}
)}
/>
)
}
// Modern version with custom hook (preferred)
function useMousePosition() {
const [position, setPosition] = useState({ x: 0, y: 0 })
useEffect(() => {
const handleMove = (e) => {
setPosition({ x: e.clientX, y: e.clientY })
}
window.addEventListener('mousemove', handleMove)
return () => window.removeEventListener('mousemove', handleMove)
}, [])
return position
}
function App() {
const { x, y } = useMousePosition()
return
Position: {x}, {y}
}
```
### 13. Bagaimana membuat custom hook?
Custom hook mengekstrak dan memungkinkan penggunaan ulang logika stateful antar-komponen.
```jsx
// useLocalStorage.js
function useLocalStorage(key, initialValue) {
// Initialize with localStorage value or default
const [storedValue, setStoredValue] = useState(() => {
try {
const item = window.localStorage.getItem(key)
return item ? JSON.parse(item) : initialValue
} catch (error) {
console.error(error)
return initialValue
}
})
// Setter wrapper that syncs with localStorage
const setValue = useCallback((value) => {
try {
// Support update functions
const valueToStore = value instanceof Function ? value(storedValue) : value
setStoredValue(valueToStore)
window.localStorage.setItem(key, JSON.stringify(valueToStore))
} catch (error) {
console.error(error)
}
}, [key, storedValue])
return [storedValue, setValue]
}
// Usage
function Settings() {
const [theme, setTheme] = useLocalStorage('theme', 'light')
const [fontSize, setFontSize] = useLocalStorage('fontSize', 16)
return (
setFontSize(Number(e.target.value))}
/>
)
}
```
### 14. Apa itu pola Compound Components?
Pola ini menciptakan komponen-komponen yang bekerja bersama secara implisit, mirip seperti tag `