简体   繁体   中英

How to add Fonts into React Expo Project

I am having issues using downloaded fonts into my Expo project.

I have added all the fonts I wanted into assets/fonts folder but even if there are a lot of examples (documentation: https://docs.expo.io/versions/latest/sdk/font/#usefonts ) on how to do it I still not have found the solution.

At this moment I am using two Main scripts (App.js and AppScreen.js)

I am looking to add fonts on all the project.

App.js Script:

import React from 'react'
import {Provider} from 'react-redux'
import {createStore, combineReducers} from 'redux'
import { StyleSheet, Text, View, Button, ActivityIndicator } from 'react-native'
import { NavigationContainer } from '@react-navigation/native'
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'
import { createStackNavigator } from '@react-navigation/stack'


import { FontAwesome5 } from '@expo/vector-icons'

// Screens
import HomeScreen from './components/screens/HomeScreen'
import ExchangeScreen from './components/screens/ExchangeScreen'
import MessageScreen from './components/screens/MessageScreen'
import NewAdScreen from './components/screens/NewAdScreen'
import ProfileScreen from './components/screens/ProfileScreen'
import AppScreen from './components/screens/AppScreen'

// Reducers
import userConnected from './components/reducers/userConnected'
import { Extrapolate } from 'react-native-reanimated'

import { useFonts } from 'expo-font';

const store = createStore(combineReducers({ userConnected }));


function App() {

  const Stack = createStackNavigator();
  const Tab = createBottomTabNavigator();

  // const StackMenu = () => {
  //   return (
  //     <NavigationContainer>
  //       <Stack.Navigator>
  //         <Stack.Screen name='App' component={AppScreen}/>
  //       </Stack.Navigator>
  //     </NavigationContainer>
  //   )
  // }

  let TabMenu = () => {
    return (
      <Tab.Navigator screenOptions={({ route }) => ({
        tabBarIcon: ({ focused, color, size }) => {
          let iconName;

          if (route.name === 'Home') {
            iconName = 'home'
          } else if (route.name === 'Exchange') {
            iconName = 'exchange-alt'
          } else if (route.name === 'Message') {
            iconName = 'comment-dots'
          } else if (route.name === 'NewAd') {
            iconName = 'plus-square';
          } else if (route.name === 'Profile') {
            iconName = 'user';
          }

          // You can return any component that you like here!
          // return <Ionicons name={iconName} size={size} color={color} />;
          return <FontAwesome5 name={iconName} size={size} color={color} />
        },
      })}
        tabBarOptions={{
          activeTintColor: 'tomato',
          inactiveTintColor: 'gray',
        }}>
        <Tab.Screen name="Home" component={HomeScreen} />
        <Tab.Screen name="Exchange" component={ExchangeScreen} />
        <Tab.Screen name="Message" component={MessageScreen} />
        <Tab.Screen name="NewAd" component={NewAdScreen} />
        <Tab.Screen name="Profile" component={ProfileScreen} />
      </Tab.Navigator>
    )
  }

  return (
    <Provider store={store}>
      <NavigationContainer>
        <Stack.Navigator screenOptions={{ headerShown: false }}>
          <Stack.Screen name='App' component={AppScreen} />
          <Stack.Screen name='TabMenu' component={TabMenu} />
        </Stack.Navigator>
      </NavigationContainer>
    </Provider>
  );
}

export default App;

And this AppScreen.js:

// This component implements the "Accueil" screen

import { StatusBar } from "expo-status-bar";
import React, { Component, useEffect, useState } from 'react'
import { StyleSheet, Text, View, Image, ScrollView } from 'react-native'

import { connect } from 'react-redux'
import AsyncStorage from '@react-native-async-storage/async-storage'

import { Input, Button, Overlay, CheckBox } from 'react-native-elements'

import { black, cranberrie, darkGreen, green, grey } from '../../tools/globalVariables'
import { storeLocalData } from '../../tools/functions'
import { useFonts } from 'expo-font';
import * as Font from 'expo-font'; 

const myIP = '##########'

function AppScreen(props) {

  const [screen, setScreen] = useState(false)

  const [modalSignUpVisible, setModalSignUpVisible] = useState(false)
  const [modalSignInVisible, setModalSignInVisible] = useState(false)

  const [firstName, setFirstName] = useState('')
  const [lastName, setLastName] = useState('')
  const [email, setEmail] = useState('')
  const [password, setPassword] = useState('')

  // States for Sign In
  const [wrongPassSignIn, setWrongPassSignIn] = useState(false)
  const [wrongEmailSignIn, setWrongEmailSignIn] = useState(false)
  const [labelPassSignIn, setLabelPassSignIn] = useState('Mot de passe')
  const [labelMailSignIn, setLabelMailSignIn] = useState('Email')

  // States for Sign Up
  const [wrongFirstName, setWrongFirstName] = useState(false)
  const [wrongLastName, setWrongLastName] = useState(false)
  const [wrongEmail, setWrongEmail] = useState(false)
  const [wrongPassword, setWrongPassword] = useState(false)
  const [labelFirstName, setLabelFirstName] = useState('Prénom')
  const [labelLastName, setLabelLastName] = useState('Nom')
  const [labelEmail, setLabelEmail] = useState('Email')
  const [labelPassword, setLabelPassword] = useState('Mot de passe')
  const [proAccount, setProAccount] = useState(false)

  


  useEffect(() => {
    // Show logo at first for 2 seconde, then the application screen
    const timer = setTimeout(() => {
      setScreen(true)
    }, 2000);

    const getData = async () => {
      try {
        const value = await AsyncStorage.getItem('userToken')
        if (value !== null) {
          const rawAnswer = await fetch(`http://${myIP}:3000/user/userInfos?token=${value}`)
          const answer = await rawAnswer.json()

          props.saveUser(answer.user)
          props.navigation.navigate('TabMenu', { screen: 'Home' })
        }
      } catch (e) {
        console.log('ERROR : ', e)
      }
    }

    getData()

    return () => clearTimeout(timer);
  }, []);


  /////// SIGN UP
  const handleSignUp = async () => {
    const dataUser = {
      firstname: firstName,
      lastname: lastName,
      email,
      password,
      proAccount
    }

    ///// Sending request to server //////
    const rawAnswer = await fetch('http://' + myIP + ':3000/user/sign-up', {
      method: 'POST',
      headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(dataUser)
    });
    const answer = await rawAnswer.json();

    if (answer.result) {
      // TO DO : STORE IN LOCAL STORAGE //

      // Reset states values
      setFirstName('')
      setLastName('')
      setEmail('')
      setPassword('')
      setProAccount(false)
      setModalSignUpVisible(false)
      props.navigation.navigate('TabMenu', { screen: 'Home' })

    } else {
      // Errors gestion
      answer.error.map((err) => {
        if (err.includes("firstname")) {
          setWrongFirstName(true)
          setLabelFirstName('Le prénom doit avoir 2 caractères minimum')
        }
        if (err.includes("lastname")) {
          setWrongLastName(true)
          setLabelLastName('Le nom doit avoir 2 caractères minimum')
        }
        if (err.includes("password")) {
          setWrongPassword(true)
          setLabelPassword('Le mot de passe doit faire entre 6 et 50 caractères')
        }
        if (err.includes("email")) {
          setWrongEmail(true)
          if (err.includes("existant")) {
            setLabelEmail('Email déjà existant')
          } else {
            setLabelEmail("L'email doit être au bon format")
          }
        }
      })
    }
  }


  /////// SIGN IN
  const handleSignIn = async () => {
    console.log('Sign in')

    const connexionData = {
      email,
      password
    }

    ///// Sending request to server //////
    const rawAnswer = await fetch('http://' + myIP + ':3000/user/sign-in', {
      method: 'POST',
      headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(connexionData)
    });
    const answer = await rawAnswer.json();
    console.log(answer.error)
    if (answer.result) {
      setEmail('')
      setPassword('')

      // Save in Local Storage
      props.saveUser(answer.userFound)
      await AsyncStorage.setItem('userToken', answer.userFound.token)

      setModalSignInVisible(false)
      props.navigation.navigate('TabMenu', { screen: 'Home' })

    } else {

      if (answer.error.indexOf('inexisting email') >= 0) {
        setEmail('')
        setPassword('')
        setWrongEmailSignIn(true)
        setLabelMailSignIn('Email inconnu')
        setWrongPassSignIn(false)
        setLabelPassSignIn('Mot de passe')
      } else {
        setPassword('')
        setWrongPassSignIn(true)
        setLabelPassSignIn('Mot de passe incorrect')
        setWrongEmailSignIn(false)
        setLabelMailSignIn('Email')
      }
    }
  }


  const handleCancel = () => {
    // Reset state values and labels
    setFirstName('')
    setLastName('')
    setEmail('')
    setPassword('')
    setProAccount(false)

    setModalSignUpVisible(false)
    setModalSignInVisible(false)
    setWrongEmailSignIn(false)
    setWrongPassSignIn(false)
    setWrongPassword(false)
    setWrongEmail(false)
    setWrongFirstName(false)
    setWrongLastName(false)

    setLabelPassSignIn('Mot de passe')
    setLabelMailSignIn('Email')
    setLabelEmail('Email')
    setLabelPassword('Mot de passe')
    setLabelFirstName('Prénom')
    setLabelLastName('Nom')
  }

  return (

    <View>
      {
        screen ?
          
          <View style={{ flexDirection: 'column', alignItems: 'center', backgroundColor: 'white', height: '100%', width: '100%' }}>
            <Image source={require('../../assets/logoSmallBlack.png')} style={{ width: '30%', height: '25%', resizeMode: 'contain' }} />

            <View style={{ flexDirection: 'row', justifyContent: 'space-between', height: '50%', width: '100%' }}>
              <Image source={require('../../assets/planteGauche.png')} style={{ width: '32%', height: '72%', resizeMode: 'contain' }} />
              <Image source={require('../../assets/planteCentre.png')} style={{ width: '32%', height: '72%', resizeMode: 'contain', marginTop: 45 }} />
              <Image source={require('../../assets/planteDroite.png')} style={{ width: '30%', height: '72%', resizeMode: 'contain' }} />
            </View>
            <StatusBar style="auto" />
            
            <View >
            <Text style={{ color: black, fontSize: 20, paddingBottom:-20 }}>Les plus belles plantes</Text>
            <Text style={{ color: black, fontSize: 20, fontFamily: 'Recoleta'}}>près de chez toi !</Text>
            </View>
        

            {/* SIGN UP OVERLAY */}
            <Overlay isVisible={modalSignUpVisible} onBackdropPress={() => { setModalSignUpVisible(!modalSignUpVisible); }}>
              <View style={{ width: '80%' }}>
                <ScrollView>
                  <Text style={{ textAlign: "center" }}>S'inscrire</Text>
                  <Input style={{ fontSize: 13 }} inputContainerStyle={{ width: '90%', borderBottomWidth: 0 }} label={labelFirstName} labelStyle={[wrongFirstName ? { color: cranberrie, fontSize: 13 } : { color: black, fontSize: 15 }]} placeholder='Entrez votre prénom' value={firstName} onChangeText={(value) => setFirstName(value)} />
                  <Input style={{ fontSize: 13 }} inputContainerStyle={{ width: '90%', borderBottomWidth: 0 }} label={labelLastName} labelStyle={[wrongLastName ? { color: cranberrie, fontSize: 13 } : { color: black, fontSize: 15 }]} placeholder='Entrez votre nom' value={lastName} onChangeText={(value) => setLastName(value)} />
                  <Input style={{ fontSize: 13 }} inputContainerStyle={{ width: '90%', borderBottomWidth: 0 }} label={labelEmail} labelStyle={[wrongEmail ? { color: cranberrie, fontSize: 13 } : { color: black, fontSize: 15 }]} placeholder='Entrez votre email' value={email} onChangeText={(value) => setEmail(value)} />
                  <Input style={{ fontSize: 13 }} inputContainerStyle={{ width: '90%', borderBottomWidth: 0 }} label={labelPassword} labelStyle={[wrongPassword ? { color: cranberrie, fontSize: 13 } : { color: black, fontSize: 15 }]} secureTextEntry={true} placeholder='Entrez votre mot de passe' value={password} onChangeText={(value) => setPassword(value)} />
                  <CheckBox title='Je suis un professionnel' textStyle={{ fontSize: 12 }} containerStyle={{ backgroundColor: "transparent", borderWidth: 0, marginTop: -20, marginLeft: 0 }} checked={proAccount} onPress={() => { setProAccount(!proAccount) }} />
                  <View style={{ flexDirection: 'row', justifyContent: 'space-between', width: '100%' }}>
                    <Button title='Annuler' buttonStyle={{ backgroundColor: black }} titleStyle={{ fontSize: 13 }} onPress={() => { handleCancel() }} />
                    <Button title='Valider mon inscription' buttonStyle={{ backgroundColor: black }} titleStyle={{ fontSize: 13 }} onPress={() => { handleSignUp() }} />
                  </View>
                </ScrollView>
              </View>
            </Overlay>

            {/* SIGN IN OVERLAY */}
            <Overlay isVisible={modalSignInVisible} onBackdropPress={() => { setModalSignInVisible(!modalSignInVisible); }}>
              <View style={{ width: '80%' }}>
                <Input style={{ fontSize: 13 }} inputContainerStyle={{ width: '90%', borderBottomWidth: 0 }} label={labelMailSignIn} labelStyle={[{ fontSize: 15 }, wrongEmailSignIn ? { color: cranberrie } : { color: black }]} placeholder='Entrez votre email' value={email} onChangeText={(value) => setEmail(value)} />
                <Input style={{ fontSize: 13 }} inputContainerStyle={{ width: '90%', borderBottomWidth: 0 }} label={labelPassSignIn} labelStyle={[{ fontSize: 15 }, wrongPassSignIn ? { color: cranberrie } : { color: black }]} secureTextEntry={true} placeholder='Entrez votre mot de passe' value={password} onChangeText={(value) => setPassword(value)} />
                <View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
                  <Button title='Annuler' buttonStyle={{ backgroundColor: black }} titleStyle={{ fontSize: 13 }} onPress={() => { handleCancel() }} />
                  <Button title='Me connecter' buttonStyle={{ backgroundColor: black }} titleStyle={{ fontSize: 13 }} onPress={() => { handleSignIn() }} />
                </View>
              </View>
            </Overlay>

            <Button title="S'inscrire sur Plan.T" buttonStyle={{ backgroundColor: black, borderRadius: 5, width: '100%' }} onPress={() => { setModalSignUpVisible(true) }} />
            <Button title="J'ai déjà un compte" buttonStyle={{ backgroundColor: 'white', borderRadius: 5, width: '100%', borderColor: '1px solid black' }} titleStyle={{ color: black }} onPress={() => { setModalSignInVisible(true) }} />
          </View>

          :

          <View style={{ backgroundColor: darkGreen, height: '100%', justifyContent: 'center', alignItems: 'center' }}>
            <Image source={require('../../assets/logo.png')} style={{ width: '70%', resizeMode: 'contain' }} />
          </View>

      }
    </View>
  )}



function mapDispatchToProps(dispatch) {
  return {
    saveUser: function (user) {
      dispatch({ type: 'saveUser', user })
    }
  }
}

export default connect(
  null,
  mapDispatchToProps
)(AppScreen)

In my case I've added 26 fonts (see picture):

Here the fonts I've added into asset/fonts folder

Let's say that I would like to use Recoleta Bold.otf inside a text part in AppScreen.js How would you do this?

Thanks in advance for your time and help. Much appreciate it.

I am adding a code snippet as an example from the official expo docs for easy reference.

import React from 'react';
import { Text, View } from 'react-native';
import AppLoading from 'expo-app-loading';
import { useFonts } from 'expo-font';

export default props => {
  let [fontsLoaded] = useFonts({
    'Inter-Black': require('./assets/fonts/Inter-Black.otf'),
  });

  if (!fontsLoaded) {
    return <AppLoading />;
  } else {
    return (
      <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
        <Text style={{ fontFamily: 'Inter-Black', fontSize: 40 }}>Inter Black</Text>
        <Text style={{ fontSize: 40 }}>Platform Default</Text>
      </View>
    );
  }
};

Incase you want to dive more deep here is the link to official expo docs

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM