New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
useFonts hook randomly failing to load fonts #21885
Comments
I am also facing a similar issue |
Robert: I actually figured out a fix that worked for me. For some reason the splashScreen would never register the value of fontsLoaded changing, but I was able to fix the issue by using the deprecated element called AppLoading from expo-app-loading. All I did was do |
Thank you for filing this issue! |
I took a look at this and I can reproduce this reliably on Android when downloading an EAS update and reloading the app with the update. Investigating. |
@crschmidt2 you are correct that you should show a loading component and not null while fonts are not loaded. Also, we recommend that you handle errors from the export default function App() {
const [fontsLoaded, fontError] = useFonts({
Abel_400Regular,
HankenGrotesk_300Light
})
const onLayoutRootView = useCallback(async () => {
if (fontsLoaded || fontError) {
await SplashScreen.hideAsync();
}
}, [fontsLoaded, fontError]);
if (!fontsLoaded && !fontError) { return <AppLoading/> }
return (
<Text style={{fontFamily: "Abel_400Regular", alignSelf: "center", marginTop: 500}}>Styling! :D Hooray!</Text>
);
} |
Our examples of `useFonts()` usage do not include error handling. Because of this, a customer can have trouble debugging the problem if there is an error in loading fonts -- in our examples, the splash screen will never hide. (See #21885 for such an issue.) I've updated the examples to show correct error handling. # Checklist <!-- Please check the appropriate items below if they apply to your diff. This is required for changes to Expo modules. --> - [x] Documentation is up to date to reflect these changes (eg: https://docs.expo.dev and README.md). - [x] Conforms with the [Documentation Writing Style Guide](https://github.com/expo/expo/blob/main/guides/Expo%20Documentation%20Writing%20Style%20Guide.md) - [x] This diff will work correctly for `npx expo prebuild` & EAS Build (eg: updated a module plugin).
Seeing this in Expo 49 currently, if you implemented const onLayoutRootView = useCallback(async () => {
if (fontsLoaded) {
await SplashScreen.hideAsync();
}
}, [fontsLoaded]);
if (!fontsLoaded) {
return null;
} Your app will randomly hang on the splash screen on iOS. I haven't confirmed on Android. It's easy to reproduce this. Force quit 10-15 times and you will get the app to hang on the splashscreen. I also added a |
@douglowder, in your example, you recommend proceeding into the app even if there is a We are also seeing the same behavior described by @mphill in Expo SDK 49. We are using the |
You make a good point -- depending on the app, it may be desirable to show an error screen or have code that handles falling back to system fonts. My main concern was that the splash screen be hidden even if errors occur, otherwise font problems will be very difficult to debug. |
For what it’s worth I don’t think this is the fonts hook that is failing, it's an assets loading issue. When this issue shows up, the in-app images don't load either. |
This does seem to be correct or at least related. In the errors we are seeing reported, it is complaining that the font asset file doesn't even exist.
Given the version that is being logged, it looks like the issue is also causing the app to fallback to the bundle that was shipped with the binary build versus the latest OTA. This seems to be a pretty prevalent issue for us, so any additional findings would be welcome. |
@mphill have you found any usable workaround in the meantime? We are seeing the issue roughly every 10-15 app starts, which is pretty rough. Given that the underlaying issue appears to be something with the loading of assets (i.e. the font file doesn't even appear available to the app), we can't necessarily hide the splash screen (i.e. The issue appears to be temporarily fixed by a force quit + reopen of the app. But, it can return again randomly at any point. Given that, we were going to programmatically restart the app with |
@carbonatedcoder if you are seeing the message above, it means that you are not actually using |
@douglowder, thanks for the followup, but we do actually make use of Additionally, we use |
Hello,
|
@carbonatedcoder if you are going to use expo-updates, it needs to be configured to use EAS update server, or your own server that follows our updates protocol. Could you share the contents of |
@douglowder, this is a managed workflow project so it's all default configuration when it comes to EAS. No custom servers are specified and we've used this for months without issue after switching from classic updates to EAS. We've never had issues with it. The OTA updates are checked and download just fine, so the issue is not really with that process. The only reason I called out the updates exception is because our idea to "mask" this assets/font issue was to reload the app for the user but this exception is only seen when trying to call The custom Updates strategy we use is similar to the one described here, with the addition of redirecting the user to a different screen while the update is happening. The |
Ok so this
is only happening at startup, when you detect the font loading issue? |
That's correct. We can (and do) call Until the root cause is fixed, we thought we could mask the issue (to the user) by using All of these somehow stem from the assets/font issue where, completely randomly, the app will start and be unable to locate the asset/font file. So whatever is happening there is likely related to this other behavior. We see it maybe once per 10-15 app starts. |
@nathantew14 to debug your issue, I would recommend catching the error that is returned by the import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
import { useFonts, Inter_900Black } from '@expo-google-fonts/inter';
export default function App() {
let [fontsLoaded, fontError] = useFonts({
Inter_900Black,
});
if (!fontsLoaded && !fontError) {
return null;
}
return (
<View style={styles.container}>
<Text style={{ fontFamily: 'Inter_900Black', fontSize: 40 }}>Inter Black</Text>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
}); Then you can hide the splash screen when the font load either completes successfully, or completes with an error: const onLayoutRootView = useCallback(async () => {
if (fontsLoaded || fontError) {
await SplashScreen.hideAsync();
}
}, [fontsLoaded, fontError]); |
@douglowder I actually tried to capture the error with Sentry and automatically restart the app on in your suggestion you just hid the splashscreen upon error (which is essentially ignoring it, right?), but from the comments above it seems like a failure to load the fonts would indicate a failure to load all other assets? |
@nathantew14 I am not suggesting that the error be ignored -- it does look like a failure to load all assets. I was just saying that it will help with debugging if you hide the splash screen when the error happens. In cases like this, I display the error in the UI as well. If you hide the splashscreen and then have a useEffect that throws when the error happens, I think Sentry should hopefully be able to capture that. |
Hi, is there a solution for this? Expo app works fine with in Expo Go, but as soon as I make an ios build, the app in TestFlight freezes in the Splash Screen, not sure how debug this. thanks |
Tried all solutions suggested here, including loading from |
Happens the same to me right now... |
This issue still happens on sdk 50 |
@itsezc @AlbertoAquinoDev @aindong do you have an Expo SDK 50 project that shows this issue? If so, please provide that and the steps you follow when observing the font loading bug (including whether the bug happens on iOS, Android, or both). If you can provide that, I'll create a new GitHub issue (as it is probably not the same as the problem originally happening in this issue). |
For me it works inside the RootLayout but not inside the Stack component thats loaded within ` import { function RootLayout() {
} export default RootLayout;` |
@douglowder I got this issue straight off the bat with |
It's from the root layout and I am seeing it only with the local font
though the icons also do not load (albeit not on the load path) Commenting out SpaceMono enables the load of the FontAwesome font |
@parkwherever thanks for the report. This seems like a different issue than the one originally posted here... is the font error happening every time? Please provide a repo with the code and assets to repro the issue. |
Hi @douglowder App.js File import React, { useCallback, useEffect, useState } from "react";
import { NavigationContainer } from "@react-navigation/native";
import { createNativeStackNavigator } from "@react-navigation/native-stack";
import { View } from "react-native";
import { ThemeProvider } from "@shopify/restyle";
import Login from "./src/components/Authentication/Login";
import theme from "./src/theme";
import Signup from "./src/components/Authentication/Signup";
import { useFonts } from "expo-font";
import * as SplashScreen from 'expo-splash-screen';
const Stack = createNativeStackNavigator();
export default function App() {
const [fontsLoaded, fontError] = useFonts({
'LemonLove': require('./assets/fonts/LemonLove.ttf')
});
const onLayoutRootView = useCallback(async () => {
if (fontsLoaded || fontError) {
await SplashScreen.hideAsync();
}
}, [fontsLoaded, fontError]);
if (!fontsLoaded && !fontError) {
return <View>
<Text>Fonts not loaded</Text>
</View>
}
return (
<ThemeProvider theme={theme}>
<Text style={{ fontSize: 30, fontFamily: 'LemonLove' }}>Inter Black 3</Text>
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
name="login"
component={Login}
options={{ headerShown: false }}
/>
<Stack.Screen
name="register"
component={Signup}
options={{ headerShown: false }}
/>
</Stack.Navigator>
</NavigationContainer>
</ThemeProvider>
);
} Signup Component: import React from "react";
import { Box, SafeTopSpace, ScrollView, Text } from "../Common";
import { StyleSheet } from "react-native";
const Signup = () => {
const styles = StyleSheet.create({
heading: {
fontFamily: "LemonLove",
fontSize: 28,
fontWeight: "700",
lineHeight: 30,
textAlign: "left",
},
});
return (
<Box
flex={1}
backgroundColor={"grayB"}
height={500}
paddingVertical={"m"}
paddingHorizontal={"s"}
>
<SafeTopSpace />
<Text color={"grayA"} style={styles.heading}>
Lets Create a new Account
</Text>
<Text color={"grayC"}>Please fill in the data below</Text>
<Box
padding={"s"}
marginVertical={"s"}
borderRadius={"medium"}
backgroundColor={"white"}
></Box>
</Box>
);
};
export default Signup; Thank you! |
@ganeshkumarburra what happens if you use |
Thank you @douglowder , For replying quickly. Then i created one more sample app to test this. import { StatusBar } from 'expo-status-bar';
import { StyleSheet, Text, View } from 'react-native';
import { createStackNavigator } from '@react-navigation/stack';
import { NavigationContainer } from '@react-navigation/native';
import 'react-native-gesture-handler';
import { useFonts } from 'expo-font';
import * as SplashScreen from 'expo-splash-screen';
import Home from './src/screens/home';
import { useCallback } from 'react';
SplashScreen.preventAutoHideAsync();
const Stack = createStackNavigator();
export default function App() {
const [fontsLoaded, fontError] = useFonts({
'LemonLove': require('./assets/fonts/LemonLove.ttf'),
});
const onLayoutRootView = useCallback(async () => {
if (fontsLoaded || fontError) {
await SplashScreen.hideAsync();
}
}, [fontsLoaded, fontError]);
if (!fontsLoaded && !fontError) {
return null;
}
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Home" component={Home} />
</Stack.Navigator>
</NavigationContainer>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
}); Home.tsx import { StatusBar } from 'expo-status-bar';
import { StyleSheet, Text, View } from 'react-native';
export default function Home() {
return (
<View >
<Text style={{fontFamily:"LemonLove"}}>Home Screen</Text>
</View>
);
} package.json {
"name": "lecturepedia",
"version": "1.0.0",
"main": "node_modules/expo/AppEntry.js",
"scripts": {
"start": "expo start",
"android": "expo start --android",
"ios": "expo start --ios",
"web": "expo start --web",
"ts:check": "tsc"
},
"dependencies": {
"@react-navigation/native": "^6.1.16",
"@react-navigation/stack": "^6.3.28",
"expo": "~50.0.13",
"expo-font": "^11.10.3",
"expo-splash-screen": "^0.26.4",
"expo-status-bar": "~1.11.1",
"react": "18.2.0",
"react-native": "0.73.5",
"react-native-gesture-handler": "^2.15.0",
"react-native-safe-area-context": "^4.9.0"
},
"devDependencies": {
"@babel/core": "^7.20.0",
"@types/react": "~18.2.45",
"typescript": "^5.1.3"
},
"private": true
} |
I believe you are supposed to import GestureHandlerRootView from the gesture handler package, and then wrap your app in the GestureHandlerRootView component. Example here: https://github.com/infinitered/ignite/blob/master/boilerplate/app/app.tsx |
Edit: Nevermind... I apologize for pinging everyone. I had my I noticed this happening today, on both SDK 50 and SDK 51. Get a false and null for fontsLoaded and fontError, but never get a response update after that, and I don't see anything in my console to explain what's going on. Seems like it's infinitely loading, or silently failing |
@chasem-dev - can you share a minimal reproducible example in a new issue? |
I apologize @brentvatne updated my comment just now, found a bug in my repo causing it 🤦 |
@brentvatne I'm having issue loading my font. const [fontsLoaded, fontError] = useFonts({
'nunito-semi-bold': require('./assets/fonts/Nunito-SemiBold.ttf'),
'nunito-medium': require('./assets/fonts/nunito-medium.ttf'),
'nunito-bold': require('./assets/fonts/nunito-bold.ttf'),
'nunito-classic': require('./assets/fonts/nunito-classic.ttf'),
nunito: require('./assets/fonts/nunito.ttf'),
}); But I always get fontError on IOS:
Do you have any idea how to solve this issue? |
I'm having a similar issue using sdk 51 and expo-font |
Same issue as you @pera14 and @slauzinho... Since I update my project to Expo 51 with react-native 0.74 and expo-font 12.04... My custom .otf font is loading and displaying as requested on the first dev build (but with the same dismissible error as @pera14). And when I fast-reload my app, the text loose the custom font family and all others text styles... |
I did following and it's working for me now.
{
"expo": {
...
"plugins": [
...
[
"expo-font",
{
"fonts": [
"./assets/fonts/nunito-semi-bold.ttf",
"./assets/fonts/nunito-medium.ttf",
"./assets/fonts/nunito-bold.ttf",
"./assets/fonts/nunito-classic.ttf",
"./assets/fonts/nunito.ttf"]
}
]
],
}
}
const [fontsLoaded, fontError] = useFonts({
'nunito-semi-bold': require('./assets/fonts/nunito-semi-bold.ttf'),
'nunito-medium': require('./assets/fonts/nunito-medium.ttf'),
'nunito-bold': require('./assets/fonts/nunito-bold.ttf'),
'nunito-classic': require('./assets/fonts/nunito-classic.ttf'),
nunito: require('./assets/fonts/nunito.ttf'),
}); But I start the app even if an error occurs, since the font will be loaded in runtime. This solution works for me so far. |
This is what I already did, but still not working after refresh. And custom font not working at all on Android... |
Have the same issue using Icomoon font and did the steps in the reply above no luck, still fails. It seems to be failing in production build uncontrollably and on the iOS simulator when the hot-refresh happens. And btw I'm on expo 51 😅 |
Summary
When I use the {useFonts, Abel_400Regular} hook from "@expo-google-fonts/abel" and {HankenGrotesk_300} from "@expo-google-fonts/hanken-grotesk" the Abe font will fail to load on my iOS Expo Go app and my Android studio emulator. However, when I add the function
and save my editor the font loads fine. But when I reload each app from Expo Cli the font refuses to load again unless I remove the function, save in my editor, add the function, and save again. I had this issue earlier with locally saved .otf font files, so I believe the issue is with the { useFonts } hook. I've tried all fixes I can find online and nothing's helped.
EDIT: I found out it's loading the fonts whenever I hot-reload after changing any code in the render return statement for a function component. I just added an if (fontsLoaded) {} and saved and it loaded the fonts. I'm guessing it's throwing the Font not loaded error slightly before the font gets a chance to load, but when I use a splashscreen to wait for it to load it gets stuck on the splashscreen forever.
What platform(s) does this occur on?
Android, iOS
SDK Version
~48.0.9
Environment
Minimal reproducible example
Here is the minimum code I was able to reproduce the error with. When I change the return statement and hot-save the project, the render update fixes the font.
Here is one of the screens the font is running on
The text was updated successfully, but these errors were encountered: