9

I'm trying to implement the loader animation in my react native app but it does't trigger the loader when the button is clicked, although the animating already change to true.

Check out my code below.

componentWillMount(){
    this.hideLoader();
}

showLoader = () => { this.setState({ showLoader:true }); };
hideLoader = () => { this.setState({ showLoader:false }); };

doSignup = () => {
    this.showLoader();
}

render() {
    console.log(this.state.showLoader);
    return (
        <View>
            <TouchableOpacity style={{ marginTop: 25 }} onPress={this.doSignup}>
              <View style={[ styles.button, { backgroundColor: '#5a0060' } ]}>
                <Text style={{ fontSize: 20, color: Colors.white }}>Sign Up Now</Text>
              </View>
            </TouchableOpacity>

            <View style={{ position: 'absolute', top: 0, bottom: 0, right: 0, left: 0 }}>
              <ActivityIndicator animating={this.state.showLoader} size="small" color="#00ff00" />
            </View>
        </View>
    );
}

When the screen is loaded, I set the loader animation as false. When the button is clicked only set to true which should be able to animate the loader but it doesn't appear.

Leon
  • 329
  • 2
  • 3
  • 15

4 Answers4

9

I've tried to simplify your code to its logical skeleton. I hope this will work and you can start adding styling and etc.

export default class LoginButton extends Component {
  state = {
    isLoading: false
  };

  doSignup = async () => {
    this.setState({ isLoading: true });
    await asyncSignupFunction();
    this.setState({ isLoading: false })
  };

  render() {
    return (
      <View>
        <TouchableOpacity onPress={this.doSignup}>
          <Text>Sign Up Now</Text>
        </TouchableOpacity>
        <ActivityIndicator animating={this.state.isLoading} />
      </View>
    );
  }
}
gazdagergo
  • 6,187
  • 1
  • 31
  • 45
4

Issue is with the position of ActivityIndicator.

Try removing styling of the Container View, loader will be visible.

  <View>
     <ActivityIndicator animating={this.state.showLoader} size="small" 
        color="#00ff00" />
   </View>
Deepak
  • 724
  • 4
  • 13
  • Absolutely right. Indicator is placed under the violet background. Simply put 'transparent' for Text bg and you will see ActivityIndicator. – Shulyk Volodymyr Aug 09 '18 at 09:43
  • I don't think it's because of the styling, because if I put the animating as true by default, the loader will be shown. – Leon Aug 09 '18 at 10:13
4

I am not against other answers but I am not in favour of other answers approach.

Why I am not impressed :

Suppose we have 6 screen so according to other answers approach I have to handle my loader in all 6 screens , when we can handle it globally why to go after each screens(which was I am doing from last one year).

My new approach :

npm i react-native-loading-spinner-overlay

Create AppLoader.js

import React from 'react';
import Spinner from 'react-native-loading-spinner-overlay';
export const loaderRef = React.createRef();

export function showLoader() {
    let ref = loaderRef.current
    if (ref) {
        ref.showLoader()
    }
}

export function hideLoader() {
    let ref = loaderRef.current
    if (ref) {
        ref.hideLoader()
    }
}

class AppLoader extends React.Component {

    constructor(props) {
        super(props)
        this.state = { loader: false }
    }

    showLoader() {
        this.setState({ loader: true })
    }

    hideLoader() {
        this.setState({ loader: false })
    }

    render() {
        return (
            <Spinner visible={this.state.loader} />
        );
    }
};

export default AppLoader

and inside your App.js

import AppLoader, { loaderRef } from 'path of AppLoader.js';

render(){
return (
        <View style={{ flex: 1 }}>
          <AppLoader ref={loaderRef} />
        </View>
  );
}

How to use it :

import { showLoader, hideLoader } from 'path of Appoader.js';

now you can easily use showLoader() and hideLoader() function without dealing state and loader handling.

Tushar Pandey
  • 4,557
  • 4
  • 33
  • 50
  • This is a very elegant solution. The only thing I can't get to work is that I can't figure out how to implement the View. the App.js has Navigation Stack and screen and don't want to see Views in there. The Login page has KeyboardAvoidingView and adding a view inside that seems to cause a padding shift, even if the loader view is not visible. – FMaz008 Oct 09 '21 at 13:48
  • You can use `` in `...`. Outside other `Navigator`. – Gursahb Webcyst Jul 31 '23 at 06:16
0

I've made some corrections to your existing code.

I'm mentioning some key changes here:

  1. View structure
  2. Position in activity indicator view

    constructor(props) {
      super(props);
      this.doSignup = this.doSignup.bind(this);
      this.state = {
        showLoader:false
      }
    }
      showLoader = () => { this.setState({ showLoader:true }); };
      hideLoader = () => { this.setState({ showLoader:false }); };
    
     doSignup(){
       this.showLoader();
     }
    render() {
      return (
         <View style={{flex:1}}>
            <TouchableOpacity style={{ marginTop: 25 }} onPress={this.doSignup}>
              <View style={[ styles.button, { backgroundColor: '#5a0060' } ]}>
               <Text style={{ fontSize: 20, color: "white" }}>Sign Up Now</Text>
            </View>
           </TouchableOpacity>
    
        <View style={{ position: 'absolute', top:"50%",right: 0, left: 0 }}>
          <ActivityIndicator animating={this.state.showLoader} size="large" color="red" />
        </View>
    </View>
      );
     }