[RN] LoadingIndicator on WelcomePage
It will replace the "Join" text button while appNavigate lasts. Note about the implementation: when appNavigate completes the component may have been unmounted and thus we cannot touch its state. In order to avoid this problem I added a 'mounted' instance variable which gets set and reset in componentWillMount / Unmount respectively. This is to avoid using isMounted, which is highly discouraged.
This commit is contained in:
parent
35da39becf
commit
ca13a9b914
|
@ -48,6 +48,7 @@ export class AbstractWelcomePage extends Component {
|
|||
this.state = {
|
||||
animateTimeoutId: null,
|
||||
generatedRoomname: '',
|
||||
joining: false,
|
||||
room: '',
|
||||
roomPlaceholder: '',
|
||||
updateTimeoutId: null
|
||||
|
@ -62,7 +63,18 @@ export class AbstractWelcomePage extends Component {
|
|||
}
|
||||
|
||||
/**
|
||||
* This method is executed when component receives new properties.
|
||||
* Implements React's {@link Component#componentWillMount()}. Invoked
|
||||
* immediately before mounting occurs.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
componentWillMount() {
|
||||
this._mounted = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#componentWillReceiveProps()}. Invoked
|
||||
* before this mounted component receives new props.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @param {Object} nextProps - New props component will receive.
|
||||
|
@ -72,12 +84,14 @@ export class AbstractWelcomePage extends Component {
|
|||
}
|
||||
|
||||
/**
|
||||
* This method is executed when method will be unmounted from DOM.
|
||||
* Implements React's {@link Component#componentWillUnmount()}. Invoked
|
||||
* immediately before this component is unmounted and destroyed.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
componentWillUnmount() {
|
||||
this._clearTimeouts();
|
||||
this._mounted = false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -128,7 +142,7 @@ export class AbstractWelcomePage extends Component {
|
|||
* otherwise, false.
|
||||
*/
|
||||
_isJoinDisabled() {
|
||||
return !isRoomValid(this.state.room);
|
||||
return this.state.joining || !isRoomValid(this.state.room);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -141,7 +155,18 @@ export class AbstractWelcomePage extends Component {
|
|||
_onJoin() {
|
||||
const room = this.state.room || this.state.generatedRoomname;
|
||||
|
||||
room && this.props.dispatch(appNavigate(room));
|
||||
if (room) {
|
||||
this.setState({ joining: true });
|
||||
|
||||
// By the time the Promise of appNavigate settles, this component
|
||||
// may have already been unmounted.
|
||||
const onAppNavigateSettled = () => {
|
||||
this._mounted && this.setState({ joining: false });
|
||||
};
|
||||
|
||||
this.props.dispatch(appNavigate(room))
|
||||
.then(onAppNavigateSettled, onAppNavigateSettled);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -4,7 +4,7 @@ import { connect } from 'react-redux';
|
|||
|
||||
import { translate } from '../../base/i18n';
|
||||
import { MEDIA_TYPE } from '../../base/media';
|
||||
import { Link, Text } from '../../base/react';
|
||||
import { Link, LoadingIndicator, Text } from '../../base/react';
|
||||
import { ColorPalette } from '../../base/styles';
|
||||
import { createDesiredLocalTracks } from '../../base/tracks';
|
||||
|
||||
|
@ -41,18 +41,24 @@ class WelcomePage extends AbstractWelcomePage {
|
|||
static propTypes = AbstractWelcomePage.propTypes;
|
||||
|
||||
/**
|
||||
* Creates a video track if not already available.
|
||||
* Implements React's {@link Component#componentWillMount()}. Invoked
|
||||
* immediately before mounting occurs. Creates a local video track if none
|
||||
* is available.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @returns {void}
|
||||
*/
|
||||
componentWillMount() {
|
||||
super.componentWillMount();
|
||||
|
||||
this.props.dispatch(createDesiredLocalTracks(MEDIA_TYPE.VIDEO));
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a prompt for entering a room name.
|
||||
* Implements React's {@link Component#render()}. Renders a prompt for
|
||||
* entering a room name.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
|
@ -75,16 +81,9 @@ class WelcomePage extends AbstractWelcomePage {
|
|||
style = { styles.textInput }
|
||||
underlineColorAndroid = 'transparent'
|
||||
value = { this.state.room } />
|
||||
<TouchableHighlight
|
||||
accessibilityLabel = { 'Tap to Join.' }
|
||||
disabled = { this._isJoinDisabled() }
|
||||
onPress = { this._onJoin }
|
||||
style = { styles.button }
|
||||
underlayColor = { ColorPalette.white }>
|
||||
<Text style = { styles.buttonText }>
|
||||
{ t('welcomepage.join') }
|
||||
</Text>
|
||||
</TouchableHighlight>
|
||||
{
|
||||
this._renderJoinButton()
|
||||
}
|
||||
</View>
|
||||
{
|
||||
this._renderLegalese()
|
||||
|
@ -93,6 +92,50 @@ class WelcomePage extends AbstractWelcomePage {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the join button.
|
||||
*
|
||||
* @private
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
_renderJoinButton() {
|
||||
let children;
|
||||
|
||||
/* eslint-disable no-extra-parens */
|
||||
|
||||
if (this.state.joining) {
|
||||
// TouchableHighlight is picky about what its children can be, so
|
||||
// wrap it in a native component, i.e. View to avoid having to
|
||||
// modify non-native children.
|
||||
children = (
|
||||
<View>
|
||||
<LoadingIndicator />
|
||||
</View>
|
||||
);
|
||||
} else {
|
||||
children = (
|
||||
<Text style = { styles.buttonText }>
|
||||
{ this.props.t('welcomepage.join') }
|
||||
</Text>
|
||||
);
|
||||
}
|
||||
|
||||
/* eslint-enable no-extra-parens */
|
||||
|
||||
return (
|
||||
<TouchableHighlight
|
||||
accessibilityLabel = { 'Tap to Join.' }
|
||||
disabled = { this._isJoinDisabled() }
|
||||
onPress = { this._onJoin }
|
||||
style = { styles.button }
|
||||
underlayColor = { ColorPalette.white }>
|
||||
{
|
||||
children
|
||||
}
|
||||
</TouchableHighlight>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders legal-related content such as Terms of service/use, Privacy
|
||||
* policy, etc.
|
||||
|
|
|
@ -38,7 +38,8 @@ class WelcomePage extends AbstractWelcomePage {
|
|||
}
|
||||
|
||||
/**
|
||||
* This method is executed when comonent is mounted.
|
||||
* Implements React's {@link Component#componentDidMount()}. Invoked
|
||||
* immediately after this component is mounted.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @returns {void}
|
||||
|
|
Loading…
Reference in New Issue