In this final section of the chapter, you'll implement a modal that shows a progress indicator. The idea is to display the modal, and then hide it when the promise resolves. Here's the code for the generic Activity component that shows a modal with an activity indicator:
import React from 'react';
import PropTypes from 'prop-types';
import { View, Modal, ActivityIndicator } from 'react-native';
import styles from './styles';
// The "Activity" component will only display
// if the "visible" property is try. The modal
// content is an "<ActivityIndicator>" component.
const Activity = props => (
<Modal visible={props.visible} transparent>
<View style={styles.modalContainer}>
<ActivityIndicator size={props.size} />
</View>
</Modal>
);
Activity.propTypes = {
visible: PropTypes.bool.isRequired,
size: PropTypes.string.isRequired
};
Activity.defaultProps = {
visible: false,
size: 'large'
};
export default Activity;
You might be tempted to pass the promise to the component so that it automatically hides itself when the promise resolves. I don't think this is a good idea, because then you would have to introduce the state into this component. Furthermore, it would depend on a promise in order to function. With the way you've implemented this component, you can show or hide the modal based on the visible property alone. Here's what the activity modal looks like on iOS:

There's a semi-transparent background on the modal that's placed over the main view with the Fetch Stuff... link. Here's how this effect is created in styles.js:
modalContainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'rgba(0, 0, 0, 0.2)',
},
Instead of setting the actual Modal component to be transparent, you set the transparency in backgroundColor, which gives the look of an overlay. Now, let's take a look at the code that controls this component:
import React, { Component } from 'react';
import { Text, View } from 'react-native';
import { fromJS } from 'immutable';
import styles from './styles';
import Activity from './Activity';
export default class ActivityModals extends Component {
// The state is a "fetching" boolean value,
// and a "promise" that is used to determine
// when the fetching is done.
state = {
data: fromJS({
fetching: false,
promise: Promise.resolve()
})
};
// Getter for "Immutable.js" state data...
get data() {
return this.state.data;
}
// Setter for "Immutable.js" state data...
set data(data) {
this.setState({ data });
}
// When the fetch button is pressed, the
// promise that simulates async activity
// is set, along with the "fetching" state.
// When the promise resolves, the "fetching"
// state goes back to false, hiding the modal.
onPress = () => {
this.data = this.data.merge({
promise: new Promise(resolve => setTimeout(resolve, 3000)).then(
() => {
this.data = this.data.set('fetching', false);
}
),
fetching: true
});
};
render() {
return (
<View style={styles.container}>
{/* The "<Activity>" modal is only visible
when the "fetching" state is true. */}
<Activity visible={this.data.get('fetching')} />
<Text onPress={this.onPress}>Fetch Stuff...</Text>
</View>
);
}
}
When the fetch link is pressed, a new promise is created that simulates async network activity. Then, when the promise resolves, you change the fetching state back to false so that the activity dialog is hidden.