Debugging React — Debugging

Debugging React Applications React memiliki tantangan debugging unik karena virtual DOM, state management, dan component lifecycle. Berikut tools dan teknik khu

Debugging React Applications

React memiliki tantangan debugging unik karena virtual DOM, state management, dan component lifecycle. Berikut tools dan teknik khusus untuk React.

React DevTools Extension

Install React Developer Tools dari Chrome Web Store. Ini menambah 2 tab baru di DevTools:

Components Tab

Menampilkan component tree (bukan DOM tree):

App
├── Header
│   ├── Logo
│   └── Navigation
│       ├── NavLink (to="/")
│       └── NavLink (to="/about")
├── MainContent
│   └── UserProfile
│       ├── Avatar
│       └── UserInfo
└── Footer

Untuk setiap component, kamu bisa melihat:

Kamu juga bisa mengedit props dan state secara live — sangat berguna untuk testing berbagai state.

Profiler Tab

Untuk mengukur performance rendering. Klik record → lakukan aksi → stop recording. Kamu bisa melihat:

Bug Umum di React

1. Infinite Re-render

// ❌ useEffect tanpa dependency → infinite loop
useEffect(() => {
  setCount(count + 1);  // set state → trigger re-render → trigger effect → ...
});

// ✅ Tambahkan dependency array
useEffect(() => {
  fetchData();
}, []);  // [] = hanya sekali saat mount

// ❌ Object/array baru setiap render sebagai dependency
useEffect(() => {
  // ini trigger setiap render karena {} !== {}
}, [{ filter: "active" }]);

// ✅ Gunakan primitive value atau useMemo
useEffect(() => {
  // ini hanya trigger saat filter berubah
}, [filter]);

2. Stale State/Closure

// ❌ State stale di dalam callback
function Counter() {
  const [count, setCount] = useState(0);

  const handleClick = () => {
    setTimeout(() => {
      console.log(count);  // Selalu nilai saat handleClick dipanggil!
      setCount(count + 1); // Bisa salah jika diklik cepat
    }, 1000);
  };

  // ✅ Gunakan functional update
  const handleClickFixed = () => {
    setTimeout(() => {
      setCount(prev => prev + 1);  // Selalu berdasarkan state terbaru
    }, 1000);
  };
}

3. Missing Key di List

// ❌ Warning: Each child should have a unique "key" prop
items.map(item => <ListItem data={item} />)

// ✅ Tambahkan key unik
items.map(item => <ListItem key={item.id} data={item} />)

// ❌ Jangan gunakan index sebagai key jika list bisa berubah
items.map((item, index) => <ListItem key={index} data={item} />)

4. Props Undefined

// ❌ TypeError: Cannot read properties of undefined
function UserProfile({ user }) {
  return <h1>{user.name}</h1>;  // Jika user belum di-fetch
}

// ✅ Defensive rendering
function UserProfile({ user }) {
  if (!user) return <p>Loading...</p>;
  return <h1>{user.name}</h1>;
}

// ✅ Optional chaining
function UserProfile({ user }) {
  return <h1>{user?.name ?? "Unknown"}</h1>;
}

Teknik Debugging React

Console.log di Render

function MyComponent({ data }) {
  console.log("MyComponent render:", { data });

  // atau gunakan useEffect untuk track re-renders
  useEffect(() => {
    console.log("MyComponent mounted/updated");
  });

  return <div>{data.title}</div>;
}

Why Did You Render?

Library @welldone-software/why-did-you-render membantu mendeteksi re-render yang tidak perlu.

Error Boundary

class ErrorBoundary extends React.Component {
  state = { hasError: false, error: null };

  static getDerivedStateFromError(error) {
    return { hasError: true, error };
  }

  componentDidCatch(error, errorInfo) {
    console.error("Error caught:", error, errorInfo);
  }

  render() {
    if (this.state.hasError) {
      return <h1>Terjadi kesalahan: {this.state.error.message}</h1>;
    }
    return this.props.children;
  }
}

// Bungkus component yang rawan error
<ErrorBoundary>
  <UserProfile />
</ErrorBoundary>

Tips

  1. Selalu install React DevTools — inspect state dan props jauh lebih mudah
  2. Gunakan StrictMode di development — membantu mendeteksi masalah umum
  3. Perhatikan console warnings React — mereka biasanya sangat informatif
  4. Gunakan Profiler jika aplikasi terasa lambat
  5. Biasakan defensive rendering — selalu handle null/undefined