I was trying to use the Avatar and Icon objects from react-native-elements I kept getting the following error:
fontFamily 'MaterialIcons' is not a system font and has not been loaded through Expo.Font.loadAsync.
- If you intended to use a system font, make sure you typed the name correctly and that it is supported by your device operating system.
- If this is a custom font, be sure to load it with Expo.Font.loadAsync.
It was driving me nuts. Googling for the answer just brought up snippets of information about what to do. So finally I pieced together the parts to get it working.
You have to load the fonts before they are used. It seems that if you ever blow away your node_modules and then do npm install again, you lose the built in loading. So you have to do it manually. Here is how!
I made sure the @expo/vector icons are loaded:
npm install --save @expo/vector-icons
Then I changed the App to load them directly:
import React from 'react';
import { View } from 'react-native';
import { Avatar } from 'react-native-elements';
import { AppLoading, Font } from 'expo';
import FontAwesome
from './node_modules/@expo/vector-icons/fonts/FontAwesome.ttf';
import MaterialIcons
from './node_modules/@expo/vector-icons/fonts/MaterialIcons.ttf';
export default class App extends React.Component {
state = {
fontLoaded: false
};
async componentWillMount() {
try {
await Font.loadAsync({
FontAwesome,
MaterialIcons
});
this.setState({ fontLoaded: true });
} catch (error) {
console.log('error loading icon fonts', error);
}
}
render() {
if (!this.state.fontLoaded) {
return <AppLoading />;
}
return (
<View>
<Text>My App</Text>
<Avatar
small
rounded
icon={{ name: 'add' }}
/>
</View>
);
}
}
So now the fonts load before the app is shown. While they are loading, the AppLoading continues to render the loading screen before showing any of the app. The fonts get loaded, then the state is set so the AppLoading component no longer renders and it continues to your app.
But why throw all that into the main App.js? It's messy. So I made an AppFontLoader utility that looks like this:
import React from 'react';
import { AppLoading, Font } from 'expo';
import FontAwesome
from '../../node_modules/@expo/vector-icons/fonts/FontAwesome.ttf';
import MaterialIcons
from '../../node_modules/@expo/vector-icons/fonts/MaterialIcons.ttf';
class AppFontLoader extends React.Component {
state = {
fontLoaded: false
};
async componentWillMount() {
try {
await Font.loadAsync({
FontAwesome,
MaterialIcons
});
this.setState({ fontLoaded: true });
} catch (error) {
console.log('error loading icon fonts', error);
}
}
render() {
if (!this.state.fontLoaded) {
return <AppLoading />;
}
return this.props.children;
}
}
export { AppFontLoader };
Now the App.js gets simplified!
import React from 'react';
import { View } from 'react-native';
import { Avatar } from 'react-native-elements';
import { AppFontLoader } from './src/utils';
export default class App extends React.Component { render() {
return (
<View>
<Text>My App</Text>
<Avatar
small
rounded
icon={{ name: 'add' }}
/>
</View>
);
}
}
I hope this helps you. It shouldn't take 4 hours to figure this out!