How to show loading progress or spinner in the middle of the screen with React Native?
Asked Answered
P

10

9

I am developing React Native app.

I was able to solve all problems by myself but this is exception. I am going to load another screen with bottom tab navigator.

For example, after user login to the app, it should show main home screen which has many pictures and many style sheet effects, icons. Because of that, after login confirm ( I mean after alert of the login confirm), the main home screen appears after a few seconds.

So I want to show some spinner in the login screen while loading main home screen in the background and when it is ready to show, erase spinner and show main home screen. How can I do this?

My bottom tab navigator was simply created with createBottomTabNavigator() method.

Pifer answered 29/1, 2020 at 0:37 Comment(0)
F
26

So in your case you can do several things

  1. You can use React Native Activity Indicator -> View
  2. You can use Overlay Library -> react-native-loading-spinner-overlay -> View GitHub
  3. If you like to make loading like facebook / instagram -> then use react-native-easy-content-loader -> View GitHub

Assume that you are using React Native Activity Indicator :

import { ActivityIndicator } from "react-native";

export default class HomeScreen extends Component {
  constructor(props) {
    super(props);
    this.state = {
      isLoading: true
    };
  }

  //Get Home Screen Data API Action
  componentDidMount() {
    this.loadAPI(); // Call home screen get data API function
  }

  //Login API Function
  loadAPI = () => {
    this.setState({ isLoading: true }); // Once You Call the API Action loading will be true
    fetch(API_URL, {
      method: "POST",
      headers: {
        "Content-Type": "application/json"
      }
    })
      .then(response => response.json())
      .then(responseText => {
        // You can do anything accroding to your API response
        this.setState({ isLoading: false }); // After getting response make loading to false
      })
      .catch(error => {});
  };

  render() {
    return (
      <View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
        {this.state.isLoading && <ActivityIndicator color={"#fff"} />}
      </View>
    );
  }
}
  • If you want to hide all the view until loading finish like images, so you can use custom library instead of Activity Indicator.
Friesland answered 29/1, 2020 at 3:57 Comment(3)
I get great help from you. I still have a question. Can you explain about navigation.dispatch?Pifer
@Yuri Glad to help you ! You can see this thread about dispatch -> #43870403Friesland
Also refer this reactnavigation.org/docs/en/navigation-actions.htmlFriesland
M
5

I have created my custom Loader component. Using this you can display built in ActivityIndicator or your custom gif loader image with overlay.

Loader.js

import React, { Component } from 'react';
import {
  StyleSheet,
  View,
  Modal,
  Image,
  ActivityIndicator
} from 'react-native';

class Loader extends Component {
  constructor(props) {
    super(props);
    this.state = {
      isLoading: this.props.isLoading
    }
  }

  static getDerivedStateFromProps(nextProps) {
    return {
      isLoading: nextProps.isLoading
    };
  }

  render() {
    return (
      <Modal
        transparent={true}
        animationType={'none'}
        visible={this.state.isLoading}
        style={{ zIndex: 1100 }}
        onRequestClose={() => { }}>
        <View style={styles.modalBackground}>
          <View style={styles.activityIndicatorWrapper}>
            <ActivityIndicator animating={this.state.isLoading} color="black" />
            
            {/* If you want to image set source here */}
            {/* <Image
              source={require('../assets/images/loader.gif')}
              style={{ height: 80, width: 80 }}
              resizeMode="contain"
              resizeMethod="resize"
            /> */}
          </View>
        </View>
      </Modal>
    )
  }
}

const styles = StyleSheet.create({
  modalBackground: {
    flex: 1,
    alignItems: 'center',
    flexDirection: 'column',
    justifyContent: 'space-around',
    backgroundColor: '#rgba(0, 0, 0, 0.5)',
    zIndex: 1000
  },
  activityIndicatorWrapper: {
    backgroundColor: '#FFFFFF',
    height: 100,
    width: 100,
    borderRadius: 10,
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'space-around'
  }
});

export default Loader

Now you can use it when you have to display loading indicator as below :

<Loader isLoading={this.state.isLoading} />
Michaella answered 29/1, 2020 at 4:30 Comment(0)
P
3

import { ActivityIndicator } from 'react-native';

export default class LoginScreen extends Component {
    constructor(props) {
        super(props);
        this.state = {
            spinner : true
        }
    }
    render() {
        return (
        <View style={{flex : 1, justifyContent: 'center', alignItems: 'center',}}>
        {
          this.state.spinner &&
          <ActivityIndicator  color={'#fff'} />
        }
        </View>
        )
    }
}
Pierce answered 29/1, 2020 at 1:44 Comment(1)
Thanks for your answer. But what I want to know is that how to set those this.state.spinner. When I have to set it true and when false?Pifer
M
2

So you can show the SPinner for suppose when you have to load an API or something and when you get the response of api, you can set spinner loading value to false.

For eg :

import {View, ActivityIndicator } from 'react-native';

export default class MainScreen extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            spinner : true
        }
    }

componentDidMount(){
this.loadApi();
}

loadApi = async() => {
let result = axios.get('url').then((data) =>{
this.setState({spinner:false});
}
).catch((err) => this.setState({spinner:false})
}

    render() {
        return (
        <View style={{flex : 1, justifyContent: 'center', alignItems: 'center',}}>
        {
          this.state.spinner? <ActivityIndicator  color={'#fff'} />:<View><Text>Data loaded</Text></View>

        }
        </View>
        )
    }
}
Melosa answered 29/1, 2020 at 3:26 Comment(0)
S
2

you have to use ActivityIndicator you can have to load this activityindicator before getting data from the server , you have to check below code hope you will understand

    import React, {useEffect, useState} from 'react';
import {ActivityIndicator, View, Dimensions} from 'react-native';
import HomeScreen from './Home';

const DataViewer = () => {
  const [data, setData] = useState([]);
  const {height, width} = Dimensions.get('window');
  useEffect(() => {
    fetch('http://example.com/movies.json')
      .then(response => {
        return response.json();
      })
      .then(myJson => {
        setData(myJson);
      });
  });

  return data.length > 0 ? (
    <HomeScreen data={data} />
  ) : (
    <View
      style={{justifyContent: 'center', alignItems: 'center', height, width}}>
      <ActivityIndicator size="large" color="#0000ff" />
    </View>
  );
};

export default DataViewer;
Shewmaker answered 29/1, 2020 at 4:42 Comment(0)
P
1

You can use the Activity indicator as the default loading animation. But you can also use Lottie files to implement custom loading screen animation on your project by installing npm i lottie-react-native or yarn add lottie-react-native

Paunch answered 12/8, 2022 at 10:58 Comment(0)
A
0

Another option is to use a simple spinning icon to show progress. You can put it in a view and move it to the center of the page or like in my case put it inside the button to show some activity to the user.

FontAwesomeSpin.tsx

import React, { Component } from 'react';
import { Animated, Easing } from 'react-native';

import { FontAwesomeIcon } from '@fortawesome/react-native-fontawesome';

interface FontAwesomeSpinProps {
  enabled: boolean;
  color?: string;
  size?: number;
}

class FontAwesomeSpin extends Component<FontAwesomeSpinProps> {
  spinValue = new Animated.Value(0);
  _isMounted = false;

  componentDidMount() {
    this._isMounted = true;
    if (this.props.enabled) {
      this.spin();
    }
  }

  componentDidUpdate(prevProps: FontAwesomeSpinProps) {
    if (this.props.enabled && !prevProps.enabled) {
      this.spinValue.setValue(0);
      this.spin();
    }
  }

  componentWillUnmount() {
    this._isMounted = false;
  }

  spin = () => {
    this.spinValue.setValue(0);

    Animated.timing(this.spinValue, {
      toValue: 1,
      duration: 1000,
      easing: Easing.linear,
      useNativeDriver: true,
    }).start(() => {
      if (this._isMounted && this.props.enabled) {
        this.spin();
      }
    });
  };

  render() {
    const { enabled: loading, color, size = 24 } = this.props;

    if (!loading) {
      return null;
    }

    const rotate = this.spinValue.interpolate({ inputRange: [0, 1], outputRange: ['0deg', '360deg'] });

    return (
      <Animated.View
        style={{
          width: size,
          height: size,
          alignItems: 'center',
          justifyContent: 'center',
          overflow: 'hidden',
          transform: [{ rotate }],
        }}
      >
        <FontAwesomeIcon icon="spinner" color={color} size={size} />
      </Animated.View>
    );
  }
}

export default FontAwesomeSpin;

You can use it like this:

 <FontAwesomeSpin enabled={loading} size={32} style={{ marginTop: 20 }} />
Analects answered 18/9, 2023 at 5:32 Comment(0)
B
0
import { View, Text, Dimensions, StyleSheet } from 'react-native'
import React from 'react'
import LottieView from "lottie-react-native";
import { moderateScale } from 'react-native-size-matters';
export const Loader = () => {
  return (
    <View style={styles.main}>
<LottieView source={require("../json/Loader.json")} autoPlay loop style={{height:moderateScale(500),width:moderateScale(500)}}  />
    
    </View>
    
  )
}

const styles = StyleSheet.create({
  main:{
...StyleSheet.absoluteFillObject,
justifyContent:'center',
alignItems:'center',
flex:1,
backgroundColor:'rgba(0,0,0,0.5)',

} }) export default Loader

Bates answered 22/1 at 9:12 Comment(0)
M
0

Something that might not be mentioned yet is to make custom view component that displays spinner:

import React from 'react';
import { View as RNView, ActivityIndicator } from 'react-native';

const View = ({ children, loading, ...props }) => {
  return (
    <RNView {...props}>
      {children}
      {loading && (
        <RNView
          style={{
            position: 'absolute',
            top: 0,
            left: 0,
            right: 0,
            bottom: 0,
            justifyContent: 'center',
            alignItems: 'center',
            backgroundColor: 'rgba(0, 0, 0, 0.5)',
          }}>
          <ActivityIndicator size="large" color="blue" />
        </RNView>
      )}
    </RNView>
  );
};

export default View;

This can be used like:

<View loading={true}> ... </View>
Monocarpic answered 22/3 at 16:19 Comment(0)
M
0

React Native has ActivityIndicator component to show an animated spinner.

//App.js
import { ActivityIndicator } from 'react-native';

export default function App() {

  const [showSpinner, setShowSpinner] = useState(true);

  return (
      <>
      {(showSpinner) ? <ActivityIndicator  color={'#11f'} /> : ""}
      <Button title="Toggle Spinner" onPress={() => setShowSpinner(!showSpinner)} />
      </>
      )

enter image description here

https://snack.expo.dev/@danilobatistaqueiroz/spinner

Mordacious answered 13/8 at 19:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.