Search code examples
typescriptreact-nativereact-native-ui-kitten

Fonts are not loaded when UI Kitten wants to use them in React Native project


I am using the UI Kitten library in a React Native project with Typescript.
I've created a mapping.json and a react-native.config.js file which look like this:

  • mapping.json:

    {
       "strict": {
          "text-font-family": "OpenSans-Regular",
    
          "text-heading-1-font-size": 30,
          "text-heading-1-font-weight": "800",
          "text-heading-1-font-family": "OpenSans-Bold",
    
          "text-subtitle-1-font-size": 15,
          "text-subtitle-1-font-weight": "600",
          "text-subtitle-1-font-family": "OpenSans-ExtraBoldItalic",
    
          "text-paragraph-1-font-size": 12,
          "text-paragraph-1-font-weight": "400",
          "text-paragraph-1-font-family": "OpenSans-Light",
    
          "text-caption-1-font-size": 12,
          "text-caption-1-font-weight": "400",
          "text-caption-1-font-family": "OpenSans-Regular",
    
          "text-label-font-size": 12,
          "text-label-font-weight": "800",
          "text-label-font-family": "OpenSans-SemiboldItalic"
       }
    }
    
  • react-native.config.js:

     module.exports = {
       project: {
       ios: {},
       android: {},
       },
       assets: ['./assets/fonts'],
     };
    

My custom fonts are located under the assets/fonts folder and I've executed the npx react-native link command.

I am getting the following error message: enter image description here

If I click on Dismiss the application is working correctly I think the fonts are not loaded only when the application starts.

I tried loading the fonts like this in my App.tsx, didn't help:

 const App = (): JSX.Element => {
 const [assetsLoaded, setAssetsLoaded] = useState(false);
 useEffect(() => {
   async function importFonts() {
     await Font.loadAsync({
    'openSans-bold': require('../assets/fonts/OpenSans-Bold.ttf'),
    'openSans-bold-italic': require('../assets/fonts/OpenSans-BoldItalic.ttf'),
    'openSans-extra-bold': require('../assets/fonts/OpenSans-ExtraBold.ttf'),
    'openSans-extra-bold-italic': require('../assets/fonts/OpenSans-ExtraBoldItalic.ttf'),
    'openSans-italic': require('../assets/fonts/OpenSans-Italic.ttf'),
    'openSans-light': require('../assets/fonts/OpenSans-Light.ttf'),
    'openSans-light-italic': require('../assets/fonts/OpenSans-LightItalic.ttf'),
    'openSans-regular': require('../assets/fonts/OpenSans-Regular.ttf'),
    'openSans-semi-bold': require('../assets/fonts/OpenSans-Semibold.ttf'),
    'openSans-semi-bold-italic': require('../assets/fonts/OpenSans-SemiboldItalic.ttf'),
  });
}
importFonts().catch((error) => {
  console.error(error);
});
setAssetsLoaded(true);
}, []);
 if (assetsLoaded) {
return (
  <>
    <IconRegistry icons={EvaIconsPack} />
    <ApplicationProvider {...eva} theme={{ ...eva.light, ...theme }} customMapping={mapping}>
      <NavigationContainer>
        <TabNavigator />
      </NavigationContainer>
    </ApplicationProvider>
  </>
);
}
  return (
     <ApplicationProvider {...eva} theme={{ ...eva.light, ...theme }}>
       <Text>Loading</Text>
     </ApplicationProvider>
  );
};

I am also getting a Property 'components' is missing in type ... on customMapping={mapping} I don't know if that relates to this problem.
I've reviewed all of the SO questions and github issues related to this, nothing helped.
I've also ran expo r -c, deleted node_modules and ran yarn install again, nothing helped, I am quite lost.


Solution

  • Given your error I assume you are using Expo. Expo docs say this about loading fonts:

    Since your fonts won't be ready right away, it is generally a good practice to not render anything until the font is ready. (link to this part of the docs here)

    It's a good idea to use an AppLoading component in your app. It should not affect the visual aspects of your app, because it works in the "backstage".

    So your component might look a little bit like this: (sorry it's not in TypeScript, I don't have any experience with TSX)

    import React from 'react';
    import { View, Text } from 'react-native';
    import { AppLoading, Asset, Font, Icon } from 'expo';
    
    export default class App extends React.Component {
      state = {
        isLoadingComplete: false,
      };
    
      render() {
        if (!this.state.isLoadingComplete && !this.props.skipLoadingScreen) {
          return (
            <AppLoading
              startAsync={this._loadResourcesAsync}
              onError={this._handleLoadingError}
              onFinish={this._handleFinishLoading}
            />
          );
        } else {
          return (
            <View style={styles.container}>
              <Text>The app is loaded, yay!</Text>
            </View>
          );
        }
      }
    
      _loadResourcesAsync = async () => {
        return Promise.all([
          Asset.loadAsync([
            require('./assets/images/robot-dev.png'),
            require('./assets/images/robot-prod.png'),
          ]),
          Font.loadAsync({
            'space-mono': require('./assets/fonts/SpaceMono-Regular.ttf'),
            'taviraj': require('./assets/fonts/Taviraj-Regular.ttf'),
          }),
        ]);
      };
    
      _handleLoadingError = error => {
        // In this case, you might want to report the error to your error
        // reporting service, for example Sentry
        console.warn(error);
      };
    
      _handleFinishLoading = () => {
        this.setState({ isLoadingComplete: true });
      };
    }
    
    const styles = StyleSheet.create({
      container: {
        flex: 1,
        backgroundColor: primaryColor,
      },
    });