How to debug React with console.log
Console logging is the quickest way to debug React components, inspect props and state, and track re-renders. As the creator of CoreUI with 25 years of debugging experience, I use strategic console.log placement to diagnose issues in React applications serving millions of users.
The most effective approach combines descriptive labels, grouped logs, and render tracking to quickly identify issues.
Log Props and State
function UserProfile({ user }) {
const [count, setCount] = useState(0)
console.log('UserProfile render:', { user, count })
return (
<div>
<h1>{user.name}</h1>
<button onClick={() => setCount(count + 1)}>
Count: {count}
</button>
</div>
)
}
Track Re-renders
import { useEffect, useRef } from 'react'
function ExpensiveComponent({ data }) {
const renderCount = useRef(0)
useEffect(() => {
renderCount.current++
console.log(`ExpensiveComponent rendered ${renderCount.current} times`)
})
return <div>{data.map(item => <p key={item.id}>{item.name}</p>)}</div>
}
Log Hook Dependencies
function DataFetcher({ userId }) {
const [data, setData] = useState(null)
useEffect(() => {
console.log('useEffect triggered, userId:', userId)
fetch(`/api/users/${userId}`)
.then(res => res.json())
.then(result => {
console.log('Data fetched:', result)
setData(result)
})
}, [userId])
return <div>{data?.name}</div>
}
Group Related Logs
function ComplexForm({ initialData }) {
const [formData, setFormData] = useState(initialData)
const handleSubmit = async (e) => {
e.preventDefault()
console.group('Form Submission')
console.log('Form data:', formData)
console.log('Timestamp:', new Date().toISOString())
try {
const response = await fetch('/api/submit', {
method: 'POST',
body: JSON.stringify(formData)
})
console.log('Response:', response)
} catch (error) {
console.error('Submission failed:', error)
} finally {
console.groupEnd()
}
}
return <form onSubmit={handleSubmit}>...</form>
}
Log Before and After State Updates
function Counter() {
const [count, setCount] = useState(0)
const increment = () => {
console.log('Before:', count)
setCount(count + 1)
console.log('After setState (still old):', count)
}
useEffect(() => {
console.log('After render (updated):', count)
}, [count])
return <button onClick={increment}>Count: {count}</button>
}
Log Component Lifecycle
function LifecycleLogger({ name }) {
console.log(`${name} render`)
useEffect(() => {
console.log(`${name} mounted`)
return () => {
console.log(`${name} unmounted`)
}
}, [name])
useEffect(() => {
console.log(`${name} updated`)
})
return <div>{name}</div>
}
Conditional Logging
function DataList({ items }) {
const debugMode = process.env.NODE_ENV === 'development'
if (debugMode && items.length === 0) {
console.warn('DataList rendered with empty items array')
}
if (debugMode && items.length > 100) {
console.warn('DataList has', items.length, 'items - consider pagination')
}
return <ul>{items.map(item => <li key={item.id}>{item.name}</li>)}</ul>
}
Table Logging
function UserTable({ users }) {
console.table(users.map(u => ({
ID: u.id,
Name: u.name,
Email: u.email,
Active: u.isActive
})))
return <table>...</table>
}
Time Logging
function ExpensiveOperation({ data }) {
console.time('Data Processing')
const processed = data.map(item => {
return heavyCalculation(item)
})
console.timeEnd('Data Processing')
return <div>{processed.length} items processed</div>
}
Custom Logger Hook
const useLogger = (componentName, props) => {
const renderCount = useRef(0)
useEffect(() => {
renderCount.current++
})
useEffect(() => {
console.log(`[${componentName}] Mount`)
return () => console.log(`[${componentName}] Unmount`)
}, [componentName])
useEffect(() => {
console.log(
`[${componentName}] Render #${renderCount.current}`,
{ props }
)
})
}
function MyComponent(props) {
useLogger('MyComponent', props)
return <div>...</div>
}
Best Practice Note
This is the same console debugging strategy we use when developing CoreUI components. Strategic console.log placement reveals component behavior, re-render patterns, and state issues quickly. Always remove console logs before production or use conditional logging with environment variables.
For advanced debugging, consider using React DevTools for visual component inspection.
Related Articles
For performance analysis, you might also want to learn how to measure performance in React for detailed profiling.



