Merge pull request #3584 from virtuacoplenny/lenny/update-lifecycles-1

Remove some usages of deprecated lifecycle methods
This commit is contained in:
virtuacoplenny 2018-11-27 09:02:05 -08:00 committed by GitHub
commit f349357d3c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 269 additions and 370 deletions

View File

@ -262,7 +262,7 @@ public class JitsiMeetView
// the respective conference again if the first invocation was followed
// by leaving the conference. However, React and, respectively,
// appProperties/initialProperties are declarative expressions i.e. one
// and the same URL will not trigger componentWillReceiveProps in the
// and the same URL will not trigger an automatic re-render in the
// JavaScript source code. The workaround implemented bellow introduces
// imperativeness in React Component props by defining a unique value
// per loadURLObject: invocation.

View File

@ -268,7 +268,7 @@ static NSMapTable<NSString *, JitsiMeetView *> *views;
// conference again if the first invocation was followed by leaving the
// conference. However, React and, respectively,
// appProperties/initialProperties are declarative expressions i.e. one and
// the same URL will not trigger componentWillReceiveProps in the JavaScript
// the same URL will not trigger an automatic re-render in the JavaScript
// source code. The workaround implemented bellow introduces imperativeness
// in React Component props by defining a unique value per loadURLObject:
// invocation.

View File

@ -205,6 +205,18 @@ export default class AlwaysOnTop extends Component<*, State> {
this._hideToolbarAfterTimeout();
}
/**
* Sets a timeout to hide the toolbar when the toolbar is shown.
*
* @inheritdoc
* @returns {void}
*/
componentDidUpdate(prevProps: *, prevState: State) {
if (!prevState.visible && this.state.visible) {
this._hideToolbarAfterTimeout();
}
}
/**
* Removes all listeners.
*
@ -223,18 +235,6 @@ export default class AlwaysOnTop extends Component<*, State> {
window.removeEventListener('mousemove', this._mouseMove);
}
/**
* Sets a timeout to hide the toolbar when the toolbar is shown.
*
* @inheritdoc
* @returns {void}
*/
componentWillUpdate(nextProps: *, nextState: State) {
if (!this.state.visible && nextState.visible) {
this._hideToolbarAfterTimeout();
}
}
/**
* Implements React's {@link Component#render()}.
*

View File

@ -49,12 +49,12 @@ export default class AbstractDialog<P : Props, S : State>
}
/**
* Implements React's {@link Component#componentWillMount()}. Invoked
* Implements React's {@link Component#componentDidMount()}. Invoked
* immediately before mounting occurs.
*
* @inheritdoc
*/
componentWillMount() {
componentDidMount() {
this._mounted = true;
}

View File

@ -102,26 +102,8 @@ class StatelessDialog extends Component<Props> {
this._onDialogDismissed = this._onDialogDismissed.bind(this);
this._onKeyDown = this._onKeyDown.bind(this);
this._onSubmit = this._onSubmit.bind(this);
this._renderFooter = this._renderFooter.bind(this);
this._setDialogElement = this._setDialogElement.bind(this);
this._Footer = this._createFooterConstructor(props);
}
/**
* React Component method that executes before the component is updated.
*
* @inheritdoc
* @param {Object} nextProps - The next properties, before the update.
* @returns {void}
*/
componentWillUpdate(nextProps) {
// If button states have changed, update the Footer constructor function
// so buttons of the proper state are rendered.
if (nextProps.okDisabled !== this.props.okDisabled
|| nextProps.cancelDisabled !== this.props.cancelDisabled
|| nextProps.submitDisabled !== this.props.submitDisabled) {
this._Footer = this._createFooterConstructor(nextProps);
}
}
/**
@ -142,7 +124,7 @@ class StatelessDialog extends Component<Props> {
return (
<Modal
autoFocus = { true }
footer = { this._Footer }
footer = { this._renderFooter }
heading = { titleString || t(titleKey) }
i18n = { this.props.i18n }
onClose = { this._onDialogDismissed }
@ -174,28 +156,26 @@ class StatelessDialog extends Component<Props> {
);
}
_onCancel: () => Function;
_renderFooter: () => React$Node;
/**
* Returns a functional component to be used for the modal footer.
* Returns a ReactElement to display buttons for closing the modal.
*
* @param {Object} options - The configuration for how the buttons in the
* footer should display. Essentially {@code StatelessDialog} props should
* be passed in.
* @param {Object} propsFromModalFooter - The props passed in from the
* {@link ModalFooter} component.
* @private
* @returns {ReactElement}
*/
_createFooterConstructor(options) {
_renderFooter(propsFromModalFooter) {
// Filter out falsy (null) values because {@code ButtonGroup} will error
// if passed in anything but buttons with valid type props.
const buttons = [
this._renderOKButton(options),
this._renderCancelButton(options)
this._renderOKButton(),
this._renderCancelButton()
].filter(Boolean);
return function Footer(modalFooterProps) {
return (
<ModalFooter showKeyline = { modalFooterProps.showKeyline } >
<ModalFooter showKeyline = { propsFromModalFooter.showKeyline } >
{
/**
@ -208,7 +188,6 @@ class StatelessDialog extends Component<Props> {
</ButtonGroup>
</ModalFooter>
);
};
}
_onCancel: () => void;
@ -257,21 +236,14 @@ class StatelessDialog extends Component<Props> {
/**
* Renders Cancel button.
*
* @param {Object} options - The configuration for the Cancel button.
* @param {boolean} options.cancelDisabled - True if the cancel button
* should not be rendered.
* @param {string} options.cancelTitleKey - The translation key to use as
* text on the button.
* @param {boolean} options.isModal - True if the cancel button should not
* be rendered.
* @private
* @returns {ReactElement|null} The Cancel button if enabled and dialog is
* not modal.
*/
_renderCancelButton(options = {}) {
if (options.cancelDisabled
|| options.isModal
|| options.hideCancelButton) {
_renderCancelButton() {
if (this.props.cancelDisabled
|| this.props.isModal
|| this.props.hideCancelButton) {
return null;
}
@ -286,7 +258,7 @@ class StatelessDialog extends Component<Props> {
key = 'cancel'
onClick = { this._onCancel }
type = 'button'>
{ t(options.cancelTitleKey || 'dialog.Cancel') }
{ t(this.props.cancelTitleKey || 'dialog.Cancel') }
</Button>
);
}
@ -294,18 +266,11 @@ class StatelessDialog extends Component<Props> {
/**
* Renders OK button.
*
* @param {Object} options - The configuration for the OK button.
* @param {boolean} options.okDisabled - True if the button should display
* as disabled and clicking should have no effect.
* @param {string} options.okTitleKey - The translation key to use as text
* on the button.
* @param {boolean} options.submitDisabled - True if the button should not
* be rendered.
* @private
* @returns {ReactElement|null} The OK button if enabled.
*/
_renderOKButton(options = {}) {
if (options.submitDisabled) {
_renderOKButton() {
if (this.props.submitDisabled) {
return null;
}
@ -318,11 +283,11 @@ class StatelessDialog extends Component<Props> {
appearance = 'primary'
form = 'modal-dialog-form'
id = { OK_BUTTON_ID }
isDisabled = { options.okDisabled }
isDisabled = { this.props.okDisabled }
key = 'submit'
onClick = { this._onSubmit }
type = 'button'>
{ t(options.okTitleKey || 'dialog.Ok') }
{ t(this.props.okTitleKey || 'dialog.Ok') }
</Button>
);
}

View File

@ -64,17 +64,24 @@ export default class CircularLabel extends AbstractCircularLabel<Props, State> {
this.state = {
pulseAnimation: new Animated.Value(0)
};
this._maybeToggleAnimation({}, props);
}
/**
* Implements {@code Component#componentWillReceiveProps}.
* Implements {@code Component#componentDidMount}.
*
* @inheritdoc
*/
componentWillReceiveProps(newProps: Props) {
this._maybeToggleAnimation(this.props, newProps);
componentDidMount() {
this._maybeToggleAnimation({}, this.props);
}
/**
* Implements {@code Component#componentDidUpdate}.
*
* @inheritdoc
*/
componentDidUpdate(prevProps: Props) {
this._maybeToggleAnimation(prevProps, this.props);
}
/**

View File

@ -1,6 +1,6 @@
// @flow
import React, { Component, type Node } from 'react';
import React, { PureComponent, type Node } from 'react';
import { Animated, TouchableWithoutFeedback, View } from 'react-native';
import styles, { SIDEBAR_WIDTH } from './styles';
@ -46,7 +46,18 @@ type State = {
/**
* A generic animated side bar to be used for left-side, hamburger-style menus.
*/
export default class SideBar extends Component<Props, State> {
export default class SideBar extends PureComponent<Props, State> {
/**
* Implements React's {@link Component#getDerivedStateFromProps()}.
*
* @inheritdoc
*/
static getDerivedStateFromProps(props: Props, prevState: State) {
return {
showOverlay: props.show || prevState.showOverlay
};
}
/**
* Initializes a new {@code SideBar} instance.
*
@ -74,12 +85,12 @@ export default class SideBar extends Component<Props, State> {
}
/**
* Implements React's {@link Component#componentWillReceiveProps()}.
* Implements React's {@link Component#componentDidUpdate()}.
*
* @inheritdoc
*/
componentWillReceiveProps({ show }: Props) {
(show === this.props.show) || this._setShow(show);
componentDidUpdate() {
this._setShow(this.props.show);
}
/**
@ -148,8 +159,6 @@ export default class SideBar extends Component<Props, State> {
* @returns {void}
*/
_setShow(show) {
show && this.setState({ showOverlay: true });
Animated
.timing(
/* value */ this.state.sliderAnimation,

View File

@ -206,6 +206,16 @@ export default class AbstractButton<P: Props, S: *> extends Component<P, S> {
return buttonStyles;
}
/**
* Get the tooltip to display when hovering over the button.
*
* @private
* @returns {string}
*/
_getTooltip() {
return this.tooltip || '';
}
/**
* Helper function to be implemented by subclasses, which must return a
* boolean value indicating if this button is disabled or not.
@ -258,7 +268,7 @@ export default class AbstractButton<P: Props, S: *> extends Component<P, S> {
iconName: this._getIconName(),
label: this._getLabel(),
styles: this._getStyles(),
tooltip: this.tooltip
tooltip: this._getTooltip()
};
return (

View File

@ -81,23 +81,15 @@ class DeepLinkingMobilePage extends Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = {
joinURL: generateDeepLinkingURL()
};
// Bind event handlers so they are only bound once per instance.
this._onDownloadApp = this._onDownloadApp.bind(this);
this._onOpenApp = this._onOpenApp.bind(this);
}
/**
* Initializes the text and URL of the `Start a conference` / `Join the
* conversation` button which takes the user to the mobile app.
*
* @inheritdoc
*/
componentWillMount() {
this.setState({
joinURL: generateDeepLinkingURL()
});
}
/**
* Implements the Component's componentDidMount method.
*

View File

@ -1,7 +1,7 @@
// @flow
import Tabs from '@atlaskit/tabs';
import React, { Component } from 'react';
import React, { PureComponent } from 'react';
import { connect } from 'react-redux';
import { Dialog, hideDialog } from '../../base/dialog';
@ -94,12 +94,36 @@ type State = {
types: Array<string>
};
/**
* React component for DesktopPicker.
*
* @extends Component
*/
class DesktopPicker extends Component<Props, State> {
class DesktopPicker extends PureComponent<Props, State> {
/**
* Implements React's {@link Component#getDerivedStateFromProps()}.
*
* @inheritdoc
*/
static getDerivedStateFromProps(props) {
return {
types: DesktopPicker._getValidTypes(props.desktopSharingSources)
};
}
/**
* Extracts only the valid types from the passed {@code types}.
*
* @param {Array<string>} types - The types to filter.
* @private
* @returns {Array<string>} The filtered types.
*/
static _getValidTypes(types = []) {
return types.filter(
type => VALID_TYPES.includes(type));
}
_poller = null;
state = {
@ -133,7 +157,7 @@ class DesktopPicker extends Component<Props, State> {
this._updateSources = this._updateSources.bind(this);
this.state.types
= this._getValidTypes(this.props.desktopSharingSources);
= DesktopPicker._getValidTypes(this.props.desktopSharingSources);
}
/**
@ -146,31 +170,6 @@ class DesktopPicker extends Component<Props, State> {
this._startPolling();
}
/**
* Notifies this mounted React Component that it will receive new props.
* Sets a default selected source if one is not already set.
*
* @inheritdoc
* @param {Object} nextProps - The read-only React Component props that this
* instance will receive.
* @returns {void}
*/
componentWillReceiveProps(nextProps: Props) {
const { desktopSharingSources } = nextProps;
/**
* Do only reference check in order to not calculate the types on every
* update. This is enough for our use case and we don't need value
* checking because if the value is the same we won't change the
* reference for the desktopSharingSources array.
*/
if (desktopSharingSources !== this.props.desktopSharingSources) {
this.setState({
types: this._getValidTypes(desktopSharingSources)
});
}
}
/**
* Clean up component and DesktopCapturerSource store state.
*
@ -241,17 +240,6 @@ class DesktopPicker extends Component<Props, State> {
return selectedSource;
}
/**
* Extracts only the valid types from the passed {@code types}.
*
* @param {Array<string>} types - The types to filter.
* @returns {Array<string>} The filtered types.
*/
_getValidTypes(types = []) {
return types.filter(
type => VALID_TYPES.includes(type));
}
_onCloseModal: (?string, string) => void;
/**

View File

@ -63,9 +63,9 @@ class AudioInputPreview extends Component<Props, State> {
* @inheritdoc
* @returns {void}
*/
componentWillReceiveProps(nextProps: Props) {
if (nextProps.track !== this.props.track) {
this._listenForAudioUpdates(nextProps.track);
componentDidUpdate(prevProps: Props) {
if (prevProps.track !== this.props.track) {
this._listenForAudioUpdates(this.props.track);
this._updateAudioLevel(0);
}
}

View File

@ -151,7 +151,8 @@ class DeviceSelection extends AbstractDialogTab<Props, State> {
}
/**
* Checks if audio / video permissions were granted.
* Checks if audio / video permissions were granted. Updates audio input and
* video input previews.
*
* @param {Object} prevProps - Previous props this component received.
* @param {Object} prevState - Previous state this component had.
@ -174,25 +175,15 @@ class DeviceSelection extends AbstractDialogTab<Props, State> {
});
});
}
if (prevProps.selectedAudioInputId
!== this.props.selectedAudioInputId) {
this._createAudioInputTrack(this.props.selectedAudioInputId);
}
/**
* Updates audio input and video input previews.
*
* @inheritdoc
* @param {Object} nextProps - The read-only props which this Component will
* receive.
* @returns {void}
*/
componentWillReceiveProps(nextProps: Object) {
const { selectedAudioInputId, selectedVideoInputId } = this.props;
if (selectedAudioInputId !== nextProps.selectedAudioInputId) {
this._createAudioInputTrack(nextProps.selectedAudioInputId);
}
if (selectedVideoInputId !== nextProps.selectedVideoInputId) {
this._createVideoInputTrack(nextProps.selectedVideoInputId);
if (prevProps.selectedVideoInputId
!== this.props.selectedVideoInputId) {
this._createVideoInputTrack(this.props.selectedVideoInputId);
}
}

View File

@ -70,6 +70,12 @@ type Props = {
*/
type State = {
/**
* Cache the conference connection state to derive when transitioning from
* not joined to join, in order to auto-show the InfoDialog.
*/
hasConnectedToConference: boolean,
/**
* Whether or not {@code InfoDialog} should be visible.
*/
@ -83,6 +89,23 @@ type State = {
* @extends Component
*/
class InfoDialogButton extends Component<Props, State> {
/**
* Implements React's {@link Component#getDerivedStateFromProps()}.
*
* @inheritdoc
*/
static getDerivedStateFromProps(props, state) {
return {
hasConnectedToConference: props._isConferenceJoined,
showDialog: (props._toolboxVisible && state.showDialog)
|| (!state.hasConnectedToConference
&& props._isConferenceJoined
&& props._participantCount < 2
&& props._toolboxVisible
&& !props._disableAutoShow)
};
}
/**
* Initializes new {@code InfoDialogButton} instance.
*
@ -92,6 +115,7 @@ class InfoDialogButton extends Component<Props, State> {
super(props);
this.state = {
hasConnectedToConference: props._isConferenceJoined,
showDialog: false
};
@ -111,22 +135,6 @@ class InfoDialogButton extends Component<Props, State> {
}
}
/**
* Update the visibility of the {@code InfoDialog}.
*
* @inheritdoc
*/
componentWillReceiveProps(nextProps) {
// Ensure the dialog is closed when the toolbox becomes hidden.
if (this.state.showDialog && !nextProps._toolboxVisible) {
this._onDialogClose();
return;
}
this._maybeAutoShowDialog(nextProps);
}
/**
* Implements React's {@link Component#render()}.
*
@ -159,24 +167,6 @@ class InfoDialogButton extends Component<Props, State> {
);
}
/**
* Invoked to trigger display of the {@code InfoDialog} if certain
* conditions are met.
*
* @param {Object} nextProps - The future properties of this component.
* @private
* @returns {void}
*/
_maybeAutoShowDialog(nextProps) {
if (!this.props._isConferenceJoined
&& nextProps._isConferenceJoined
&& nextProps._participantCount < 2
&& nextProps._toolboxVisible
&& !nextProps._disableAutoShow) {
this.setState({ showDialog: true });
}
}
_onDialogClose: () => void;
/**

View File

@ -112,6 +112,28 @@ type State = {
class InfoDialog extends Component<Props, State> {
_copyElement: ?Object;
/**
* Implements React's {@link Component#getDerivedStateFromProps()}.
*
* @inheritdoc
*/
static getDerivedStateFromProps(props, state) {
let phoneNumber = state.phoneNumber;
if (!state.phoneNumber && props.dialIn.numbers) {
const { defaultCountry, numbers } = props.dialIn;
phoneNumber = _getDefaultPhoneNumber(numbers, defaultCountry);
}
return {
// Exit edit mode when a password is set locally or remotely.
passwordEditEnabled: state.passwordEditEnabled && props._password
? false : state.passwordEditEnabled,
phoneNumber
};
}
/**
* {@code InfoDialog} component's local state.
*
@ -162,28 +184,6 @@ class InfoDialog extends Component<Props, State> {
this._setCopyElement = this._setCopyElement.bind(this);
}
/**
* Implements React's {@link Component#componentWillReceiveProps()}. Invoked
* before this mounted component receives new props.
*
* @inheritdoc
* @param {Props} nextProps - New props component will receive.
*/
componentWillReceiveProps(nextProps) {
if (!this.props._password && nextProps._password) {
this.setState({ passwordEditEnabled: false });
}
if (!this.state.phoneNumber && nextProps.dialIn.numbers) {
const { defaultCountry, numbers } = nextProps.dialIn;
this.setState({
phoneNumber:
_getDefaultPhoneNumber(numbers, defaultCountry)
});
}
}
/**
* Implements React's {@link Component#render()}.
*

View File

@ -55,6 +55,17 @@ type State = {
* @extends Component
*/
class PasswordForm extends Component<Props, State> {
/**
* Implements React's {@link Component#getDerivedStateFromProps()}.
*
* @inheritdoc
*/
static getDerivedStateFromProps(props, state) {
return {
enteredPassword: props.editEnabled ? state.enteredPassword : ''
};
}
state = {
enteredPassword: ''
};
@ -74,19 +85,6 @@ class PasswordForm extends Component<Props, State> {
this._onPasswordSubmit = this._onPasswordSubmit.bind(this);
}
/**
* Implements React's {@link Component#componentWillReceiveProps()}. Invoked
* before this mounted component receives new props.
*
* @inheritdoc
* @param {Props} nextProps - New props component will receive.
*/
componentWillReceiveProps(nextProps: Props) {
if (this.props.editEnabled && !nextProps.editEnabled) {
this.setState({ enteredPassword: '' });
}
}
/**
* Implements React's {@link Component#render()}.
*
@ -182,5 +180,4 @@ class PasswordForm extends Component<Props, State> {
}
}
export default translate(PasswordForm);

View File

@ -32,6 +32,19 @@ type State = {
* @extends Component
*/
class Labels extends AbstractLabels<Props, State> {
/**
* Updates the state for whether or not the filmstrip is transitioning to
* a displayed state.
*
* @inheritdoc
*/
static getDerivedStateFromProps(props, prevState) {
return {
filmstripBecomingVisible: !prevState.filmstripBecomingVisible
&& props._filmstripVisible
};
}
/**
* Initializes a new {@code Labels} instance.
*
@ -46,22 +59,6 @@ class Labels extends AbstractLabels<Props, State> {
};
}
/**
* Updates the state for whether or not the filmstrip is being toggled to
* display after having being hidden.
*
* @inheritdoc
* @param {Object} nextProps - The read-only props which this Component will
* receive.
* @returns {void}
*/
componentWillReceiveProps(nextProps) {
this.setState({
filmstripBecomingVisible: nextProps._filmstripVisible
&& !this.props._filmstripVisible
});
}
/**
* Implements React's {@link Component#render()}.
*

View File

@ -117,17 +117,15 @@ export class LargeVideoBackground extends Component<Props> {
* Starts or stops the interval to update the image displayed in the canvas.
*
* @inheritdoc
* @param {Object} nextProps - The read-only React {@code Component} props
* with which the new instance is to be initialized.
*/
componentWillReceiveProps(nextProps: Props) {
if (this.props.hidden && !nextProps.hidden) {
componentDidUpdate(prevProps: Props) {
if (prevProps.hidden && !this.props.hidden) {
this._clearCanvas();
this._setUpdateCanvasInterval();
}
if ((!this.props.hidden && nextProps.hidden)
|| !nextProps.videoElement) {
if ((!prevProps.hidden && this.props.hidden)
|| !this.props.videoElement) {
this._clearCanvas();
this._clearUpdateCanvasInterval();
}

View File

@ -109,7 +109,7 @@ class AudioRoutePickerDialog extends Component<Props, State> {
state = {
/**
* Available audio devices, it will be set in
* {@link #componentWillMount()}.
* {@link #componentDidMount()}.
*/
devices: []
};
@ -132,7 +132,7 @@ class AudioRoutePickerDialog extends Component<Props, State> {
*
* @inheritdoc
*/
componentWillMount() {
componentDidMount() {
AudioMode.getAudioDevices().then(({ devices, selected }) => {
const audioDevices = [];

View File

@ -54,6 +54,18 @@ const STALE_TIMEOUT = 10 * 1000;
*/
export default class AbstractRecordingLabel
extends Component<Props, State> {
/**
* Implements {@code Component#getDerivedStateFromProps}.
*
* @inheritdoc
*/
static getDerivedStateFromProps(props: Props, prevState: State) {
return {
staleLabel: props._status !== JitsiRecordingConstants.status.OFF
&& prevState.staleLabel ? false : prevState.staleLabel
};
}
/**
* Initializes a new {@code AbstractRecordingLabel} component.
*
@ -70,12 +82,12 @@ export default class AbstractRecordingLabel
}
/**
* Implements {@code Component#componentWillReceiveProps}.
* Implements {@code Component#componentDidUpdate}.
*
* @inheritdoc
*/
componentWillReceiveProps(newProps: Props) {
this._updateStaleStatus(this.props, newProps);
componentDidUpdate(prevProps: Props) {
this._updateStaleStatus(prevProps, this.props);
}
/**
@ -137,13 +149,8 @@ export default class AbstractRecordingLabel
}
}, STALE_TIMEOUT);
}
} else if (this.state.staleLabel) {
this.setState({
staleLabel: false
});
}
}
}
/**

View File

@ -33,24 +33,13 @@ export type Props = {
value: string
};
/**
* The state of the component.
*/
type State = {
/**
* The value entered in the field.
*/
value: string
}
/**
* An abstract React Component for entering a key for starting a YouTube live
* stream.
*
* @extends Component
*/
export default class AbstractStreamKeyForm extends Component<Props, State> {
export default class AbstractStreamKeyForm extends Component<Props> {
helpURL: string;
/**
@ -61,10 +50,6 @@ export default class AbstractStreamKeyForm extends Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = {
value: props.value
};
this.helpURL = (typeof interfaceConfig !== 'undefined'
&& interfaceConfig.LIVE_STREAMING_HELP_LINK)
|| LIVE_STREAMING_HELP_LINK;
@ -73,17 +58,6 @@ export default class AbstractStreamKeyForm extends Component<Props, State> {
this._onInputChange = this._onInputChange.bind(this);
}
/**
* Implements {@code Component}'s componentWillReceiveProps.
*
* @inheritdoc
*/
componentWillReceiveProps(newProps: Props) {
this.setState({
value: newProps.value
});
}
_onInputChange: Object => void
/**
@ -99,9 +73,6 @@ export default class AbstractStreamKeyForm extends Component<Props, State> {
_onInputChange(change) {
const value = typeof change === 'object' ? change.target.value : change;
this.setState({
value
});
this.props.onChange(value);
}
}

View File

@ -50,7 +50,7 @@ class StreamKeyForm extends AbstractStreamKeyForm {
onChangeText = { this._onInputChange }
placeholder = { t('liveStreaming.enterStreamKey') }
style = { styles.streamKeyInput }
value = { this.state.value } />
value = { this.props.value } />
<TouchableOpacity
onPress = { this._onOpenHelp }
style = { styles.streamKeyHelp } >

View File

@ -37,26 +37,6 @@ class LiveStreamButton extends AbstractLiveStreamButton<Props> {
iconName = 'icon-public';
toggledIconName = 'icon-public';
/**
* Constructor of the component.
*
* @inheritdoc
*/
constructor(props: Props) {
super(props);
this.tooltip = props._liveStreamDisabledTooltipKey;
}
/**
* Implements {@code Component}'s componentWillReceiveProps.
*
* @inheritdoc
*/
componentWillReceiveProps(newProps: Props) {
this.tooltip = newProps._liveStreamDisabledTooltipKey;
}
/**
* Helper function to be implemented by subclasses, which returns
* a React Element to display (a beta tag) at the end of the button.
@ -76,6 +56,16 @@ class LiveStreamButton extends AbstractLiveStreamButton<Props> {
);
}
/**
* Returns the tooltip that should be displayed when the button is disabled.
*
* @private
* @returns {string}
*/
_getTooltip() {
return this.props._liveStreamDisabledTooltipKey || '';
}
/**
* Helper function to be implemented by subclasses, which must return a
* boolean value indicating if this button is disabled or not.

View File

@ -51,7 +51,7 @@ class StreamKeyForm extends AbstractStreamKeyForm {
placeholder = { t('liveStreaming.enterStreamKey') }
shouldFitContainer = { true }
type = 'text'
value = { this.state.value } />
value = { this.props.value } />
{ this.helpURL
? <div className = 'form-footer'>
<a

View File

@ -36,23 +36,13 @@ class RecordButton extends AbstractRecordButton<Props> {
toggledIconName = 'icon-camera-take-picture';
/**
* Constructor of the component.
* Returns the tooltip that should be displayed when the button is disabled.
*
* @inheritdoc
* @private
* @returns {string}
*/
constructor(props: Props) {
super(props);
this.tooltip = props._fileRecordingsDisabledTooltipKey;
}
/**
* Implements {@code Component}'s componentWillReceiveProps.
*
* @inheritdoc
*/
componentWillReceiveProps(newProps: Props) {
this.tooltip = newProps._fileRecordingsDisabledTooltipKey;
_getTooltip() {
return this.tooltip || '';
}
/**

View File

@ -12,7 +12,7 @@ import SpeakerStatsLabels from './SpeakerStatsLabels';
declare var interfaceConfig: Object;
/**
* The type of the React {@code Component} props of {@link SpeakerStats}
* The type of the React {@code Component} props of {@link SpeakerStats}.
*/
type Props = {
@ -33,7 +33,7 @@ type Props = {
};
/**
* The type of the React {@code Component} state of {@link SpeakerStats}
* The type of the React {@code Component} state of {@link SpeakerStats}.
*/
type State = {
@ -49,10 +49,6 @@ type State = {
* @extends Component
*/
class SpeakerStats extends Component<Props, State> {
state = {
stats: {}
};
_updateInterval: IntervalID;
/**
@ -64,19 +60,20 @@ class SpeakerStats extends Component<Props, State> {
constructor(props) {
super(props);
this.state = {
stats: this.props.conference.getSpeakerStats()
};
// Bind event handlers so they are only bound once per instance.
this._updateStats = this._updateStats.bind(this);
}
/**
* Immediately request for updated speaker stats and begin
* polling for speaker stats updates.
* Begin polling for speaker stats updates.
*
* @inheritdoc
* @returns {void}
*/
componentWillMount() {
this._updateStats();
componentDidMount() {
this._updateInterval = setInterval(this._updateStats, 1000);
}

View File

@ -280,15 +280,15 @@ class Toolbox extends Component<Props> {
*
* @inheritdoc
*/
componentWillReceiveProps(nextProps) {
componentDidUpdate(prevProps) {
// Ensure the dialog is closed when the toolbox becomes hidden.
if (this.props._overflowMenuVisible && !nextProps._visible) {
if (prevProps._overflowMenuVisible && !this.props._visible) {
this._onSetOverflowVisible(false);
}
if (this.props._overflowMenuVisible
&& !this.props._dialog
&& nextProps._dialog) {
if (prevProps._overflowMenuVisible
&& !prevProps._dialog
&& this.props._dialog) {
this._onSetOverflowVisible(false);
this.props.dispatch(setToolbarHovered(false));
}

View File

@ -37,6 +37,17 @@ type Props = {
export class AbstractWelcomePage extends Component<Props, *> {
_mounted: ?boolean;
/**
* Implements React's {@link Component#getDerivedStateFromProps()}.
*
* @inheritdoc
*/
static getDerivedStateFromProps(props: Props, state: Object) {
return {
room: props._room || state.room
};
}
/**
* Save room name into component's local state.
*
@ -77,26 +88,15 @@ export class AbstractWelcomePage extends Component<Props, *> {
}
/**
* Implements React's {@link Component#componentWillMount()}. Invoked
* immediately before mounting occurs.
* Implements React's {@link Component#componentDidMount()}. Invoked
* immediately after mounting occurs.
*
* @inheritdoc
*/
componentWillMount() {
componentDidMount() {
this._mounted = true;
}
/**
* Implements React's {@link Component#componentWillReceiveProps()}. Invoked
* before this mounted component receives new props.
*
* @inheritdoc
* @param {Props} nextProps - New props component will receive.
*/
componentWillReceiveProps(nextProps: Props) {
this.setState({ room: nextProps._room });
}
/**
* Implements React's {@link Component#componentWillUnmount()}. Invoked
* immediately before this component is unmounted and destroyed.

View File

@ -29,7 +29,7 @@ class BlankPage extends Component<Props> {
* @inheritdoc
* @returns {void}
*/
componentWillMount() {
componentDidMount() {
this.props.dispatch(destroyLocalTracks());
}

View File

@ -57,15 +57,15 @@ class WelcomePage extends AbstractWelcomePage {
}
/**
* Implements React's {@link Component#componentWillMount()}. Invoked
* immediately before mounting occurs. Creates a local video track if none
* Implements React's {@link Component#componentDidMount()}. Invoked
* immediately after mounting occurs. Creates a local video track if none
* is available and the camera permission was already granted.
*
* @inheritdoc
* @returns {void}
*/
componentWillMount() {
super.componentWillMount();
componentDidMount() {
super.componentDidMount();
const { dispatch } = this.props;