Load fonts at runtime and use them in React Native components.
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
React hooks for integrating font loading into component lifecycles with automatic state management, error handling, and rehydration support for server-side rendering.
Load fonts and track their loading state within React components.
/**
* Load a map of fonts at runtime and return loading state and error
* @param map - Font family name or map of fontFamily to FontSource
* @returns Tuple of [loaded: boolean, error: Error | null]
*/
function useFonts(
map: string | Record<string, FontSource>
): [boolean, Error | null];Usage Examples:
import React from 'react';
import { Text, View } from 'react-native';
import { useFonts } from 'expo-font';
// Basic usage with multiple fonts
function MyComponent() {
const [fontsLoaded, error] = useFonts({
'Inter-Regular': require('./assets/fonts/Inter-Regular.otf'),
'Inter-Bold': require('./assets/fonts/Inter-Bold.otf'),
'CustomFont': 'https://example.com/font.woff2',
});
if (error) {
// Handle font loading error
console.error('Font loading failed:', error);
throw error; // or show error UI
}
if (!fontsLoaded) {
// Show loading state while fonts are loading
return <LoadingScreen />;
}
// Fonts are loaded, safe to use
return (
<View>
<Text style={{ fontFamily: 'Inter-Regular' }}>
Regular text with custom font
</Text>
<Text style={{ fontFamily: 'Inter-Bold' }}>
Bold text with custom font
</Text>
</View>
);
}
// Usage with single font (string)
function SingleFontComponent() {
const [fontLoaded, error] = useFonts('MyCustomFont');
if (error) throw error;
if (!fontLoaded) return <LoadingSpinner />;
return <Text style={{ fontFamily: 'MyCustomFont' }}>Hello!</Text>;
}
// Usage with FontResource options
function WebOptimizedComponent() {
const [fontsLoaded, error] = useFonts({
'WebFont': {
uri: require('./fonts/WebFont.woff2'),
display: FontDisplay.SWAP // Improves web loading experience
}
});
if (error) throw error;
if (!fontsLoaded) return null;
return <Text style={{ fontFamily: 'WebFont' }}>Optimized for web</Text>;
}The hook provides comprehensive error handling for various failure scenarios:
import { useFonts } from 'expo-font';
function ComponentWithErrorHandling() {
const [fontsLoaded, error] = useFonts({
'MyFont': require('./assets/fonts/MyFont.ttf'),
});
// Handle different error types
if (error) {
if (error.message.includes('network')) {
// Network error - show retry option
return <RetryableFontError onRetry={() => window.location.reload()} />;
} else {
// Other errors - fall back to system fonts
console.warn('Font loading failed, using system fonts:', error);
return <Text style={{ fontFamily: 'System' }}>Fallback content</Text>;
}
}
if (!fontsLoaded) {
return <LoadingSpinner />;
}
return <Text style={{ fontFamily: 'MyFont' }}>Custom font content</Text>;
}import React, { useMemo } from 'react';
import { useFonts } from 'expo-font';
// Conditional font loading based on user preferences
function AdaptiveFontComponent({ userPreferredFont }) {
const fontMap = useMemo(() => {
const fonts = {
'DefaultFont': require('./fonts/Default.ttf'),
};
if (userPreferredFont === 'dyslexia-friendly') {
fonts['DyslexiaFont'] = require('./fonts/OpenDyslexic.ttf');
}
return fonts;
}, [userPreferredFont]);
const [fontsLoaded, error] = useFonts(fontMap);
if (error) throw error;
if (!fontsLoaded) return <LoadingScreen />;
const fontFamily = userPreferredFont === 'dyslexia-friendly'
? 'DyslexiaFont'
: 'DefaultFont';
return (
<Text style={{ fontFamily }}>
Adaptive font content
</Text>
);
}
// Using with React Suspense
function SuspenseFontComponent() {
const [fontsLoaded, error] = useFonts({
'MyFont': require('./fonts/MyFont.ttf'),
});
if (error) throw error;
// Throw promise for Suspense boundary
if (!fontsLoaded) {
throw new Promise(resolve => {
// This pattern works with the loading behavior
const checkLoaded = () => {
if (fontsLoaded) resolve();
else setTimeout(checkLoaded, 100);
};
checkLoaded();
});
}
return <Text style={{ fontFamily: 'MyFont' }}>Suspense content</Text>;
}[false, null] on first render[false, null] while fonts are being loaded[true, null] when all fonts have loaded successfully[false, Error] if any font fails to loadThe hook optimizes for server-side rendering and client-side rehydration:
// On server: fonts are registered statically, hook returns [true, null]
// On client: hook checks if fonts are already loaded before starting load process
// This prevents flash of unstyled text (FOUT) during rehydration// ❌ Don't create new objects on every render
function BadComponent() {
const [fontsLoaded] = useFonts({
'MyFont': require('./MyFont.ttf') // New object every render
});
// This will cause unnecessary re-loading
}
// ✅ Use stable references
const FONT_MAP = {
'MyFont': require('./MyFont.ttf')
};
function GoodComponent() {
const [fontsLoaded] = useFonts(FONT_MAP); // Stable reference
// Font loading is optimized
}
// ✅ Or use useMemo for dynamic fonts
function DynamicComponent({ theme }) {
const fontMap = useMemo(() => ({
'ThemeFont': require(`./fonts/${theme}.ttf`)
}), [theme]);
const [fontsLoaded] = useFonts(fontMap);
}