This is a very important architectural decision in Gutenberg β and honestly, many developers misuse both.
Letβs break it down in a practical, real-world way so you can decide like a tech lead π
π§ select('core') vs apiFetch β Whatβs the Difference?
| Feature | select('core') | apiFetch |
|---|---|---|
| Data Source | WP Data Store (core-data) | Direct REST API |
| Reactivity | β Reactive (auto re-render) | β Not reactive |
| Caching | β Built-in caching | β No caching |
| Performance | β Optimized | β οΈ Depends on usage |
| Ease of Use | β Cleaner in blocks | β οΈ More manual |
| Control | β οΈ Limited | β Full control |
β
When You Should Use select('core') (Recommended Most of the Time)
π Use this inside Gutenberg blocks/UI
β Best for:
- Fetching posts, pages, users
- Displaying dynamic data in UI
- When you want automatic updates
- When performance matters
Example
const posts = useSelect((select) => {
return select('core').getEntityRecords('postType', 'post');
}, []);
π‘ Why it’s better
- Uses centralized state (Redux-like store)
- Avoids duplicate API calls
- Auto re-renders UI when data changes
- Works seamlessly with Gutenberg
β οΈ When apiFetch is Better
π Use this when you need full control or custom behavior
β Best for:
- Custom REST API endpoints
- POST / PUT / DELETE requests
- Non-Gutenberg environments
- One-time operations (form submit, migration scripts, etc.)
Example
import apiFetch from '@wordpress/api-fetch';const fetchData = async () => {
const posts = await apiFetch({
path: '/wp/v2/posts?per_page=5',
}); console.log(posts);
};
π¨ Common Mistake (Very Important)
β Using apiFetch inside React render logic:
// β BAD PRACTICE
const posts = await apiFetch({ path: '/wp/v2/posts' });
π This causes:
- Multiple API calls
- No caching
- Performance issues
β‘ Real-World Decision Rule (Use This)
π Ask yourself:
1. Is this UI data inside Gutenberg?
π β
Use select('core')
2. Is this a custom API or action (POST/UPDATE)?
π β
Use apiFetch
3. Do I need caching + reactivity?
π β
Use select('core')
4. Do I need full control over request?
π β
Use apiFetch
π Best Practice (Senior-Level Pattern)
π Combine both when needed:
- Use
select('core')β for reading data - Use
apiFetchβ for writing/updating data
Example Pattern
// Read (cached + reactive)
const posts = useSelect((select) =>
select('core').getEntityRecords('postType', 'post')
);// Write (manual control)
const createPost = async () => {
await apiFetch({
path: '/wp/v2/posts',
method: 'POST',
data: { title: 'New Post' },
});
};
π§© Bonus Insight (Interview-Level)
π select('core') internally:
- Uses @wordpress/core-data
- Wraps REST API calls
- Adds caching + resolution tracking
- Prevents duplicate requests
π Final Verdict
π If you’re building Gutenberg blocks:
Use
select('core')80β90% of the time
π Use apiFetch only when:
- You need custom logic
- Or you’re mutating data