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 // the respective conference again if the first invocation was followed
// by leaving the conference. However, React and, respectively, // by leaving the conference. However, React and, respectively,
// appProperties/initialProperties are declarative expressions i.e. one // 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 // JavaScript source code. The workaround implemented bellow introduces
// imperativeness in React Component props by defining a unique value // imperativeness in React Component props by defining a unique value
// per loadURLObject: invocation. // 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 again if the first invocation was followed by leaving the
// conference. However, React and, respectively, // conference. However, React and, respectively,
// appProperties/initialProperties are declarative expressions i.e. one and // 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 // source code. The workaround implemented bellow introduces imperativeness
// in React Component props by defining a unique value per loadURLObject: // in React Component props by defining a unique value per loadURLObject:
// invocation. // invocation.

View File

@ -205,6 +205,18 @@ export default class AlwaysOnTop extends Component<*, State> {
this._hideToolbarAfterTimeout(); 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. * Removes all listeners.
* *
@ -223,18 +235,6 @@ export default class AlwaysOnTop extends Component<*, State> {
window.removeEventListener('mousemove', this._mouseMove); 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()}. * 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. * immediately before mounting occurs.
* *
* @inheritdoc * @inheritdoc
*/ */
componentWillMount() { componentDidMount() {
this._mounted = true; this._mounted = true;
} }

View File

@ -102,26 +102,8 @@ class StatelessDialog extends Component<Props> {
this._onDialogDismissed = this._onDialogDismissed.bind(this); this._onDialogDismissed = this._onDialogDismissed.bind(this);
this._onKeyDown = this._onKeyDown.bind(this); this._onKeyDown = this._onKeyDown.bind(this);
this._onSubmit = this._onSubmit.bind(this); this._onSubmit = this._onSubmit.bind(this);
this._renderFooter = this._renderFooter.bind(this);
this._setDialogElement = this._setDialogElement.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 ( return (
<Modal <Modal
autoFocus = { true } autoFocus = { true }
footer = { this._Footer } footer = { this._renderFooter }
heading = { titleString || t(titleKey) } heading = { titleString || t(titleKey) }
i18n = { this.props.i18n } i18n = { this.props.i18n }
onClose = { this._onDialogDismissed } onClose = { this._onDialogDismissed }
@ -174,41 +156,38 @@ 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 * @param {Object} propsFromModalFooter - The props passed in from the
* footer should display. Essentially {@code StatelessDialog} props should * {@link ModalFooter} component.
* be passed in.
* @private * @private
* @returns {ReactElement} * @returns {ReactElement}
*/ */
_createFooterConstructor(options) { _renderFooter(propsFromModalFooter) {
// Filter out falsy (null) values because {@code ButtonGroup} will error // Filter out falsy (null) values because {@code ButtonGroup} will error
// if passed in anything but buttons with valid type props. // if passed in anything but buttons with valid type props.
const buttons = [ const buttons = [
this._renderOKButton(options), this._renderOKButton(),
this._renderCancelButton(options) this._renderCancelButton()
].filter(Boolean); ].filter(Boolean);
return function Footer(modalFooterProps) { return (
return ( <ModalFooter showKeyline = { propsFromModalFooter.showKeyline } >
<ModalFooter showKeyline = { modalFooterProps.showKeyline } > {
{
/** /**
* Atlaskit has this empty span (JustifySim) so... * Atlaskit has this empty span (JustifySim) so...
*/ */
} }
<span /> <span />
<ButtonGroup> <ButtonGroup>
{ buttons } { buttons }
</ButtonGroup> </ButtonGroup>
</ModalFooter> </ModalFooter>
); );
};
} }
_onCancel: () => void; _onCancel: () => void;
@ -257,21 +236,14 @@ class StatelessDialog extends Component<Props> {
/** /**
* Renders Cancel button. * 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 * @private
* @returns {ReactElement|null} The Cancel button if enabled and dialog is * @returns {ReactElement|null} The Cancel button if enabled and dialog is
* not modal. * not modal.
*/ */
_renderCancelButton(options = {}) { _renderCancelButton() {
if (options.cancelDisabled if (this.props.cancelDisabled
|| options.isModal || this.props.isModal
|| options.hideCancelButton) { || this.props.hideCancelButton) {
return null; return null;
} }
@ -286,7 +258,7 @@ class StatelessDialog extends Component<Props> {
key = 'cancel' key = 'cancel'
onClick = { this._onCancel } onClick = { this._onCancel }
type = 'button'> type = 'button'>
{ t(options.cancelTitleKey || 'dialog.Cancel') } { t(this.props.cancelTitleKey || 'dialog.Cancel') }
</Button> </Button>
); );
} }
@ -294,18 +266,11 @@ class StatelessDialog extends Component<Props> {
/** /**
* Renders OK button. * 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 * @private
* @returns {ReactElement|null} The OK button if enabled. * @returns {ReactElement|null} The OK button if enabled.
*/ */
_renderOKButton(options = {}) { _renderOKButton() {
if (options.submitDisabled) { if (this.props.submitDisabled) {
return null; return null;
} }
@ -318,11 +283,11 @@ class StatelessDialog extends Component<Props> {
appearance = 'primary' appearance = 'primary'
form = 'modal-dialog-form' form = 'modal-dialog-form'
id = { OK_BUTTON_ID } id = { OK_BUTTON_ID }
isDisabled = { options.okDisabled } isDisabled = { this.props.okDisabled }
key = 'submit' key = 'submit'
onClick = { this._onSubmit } onClick = { this._onSubmit }
type = 'button'> type = 'button'>
{ t(options.okTitleKey || 'dialog.Ok') } { t(this.props.okTitleKey || 'dialog.Ok') }
</Button> </Button>
); );
} }

View File

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

View File

@ -1,6 +1,6 @@
// @flow // @flow
import React, { Component, type Node } from 'react'; import React, { PureComponent, type Node } from 'react';
import { Animated, TouchableWithoutFeedback, View } from 'react-native'; import { Animated, TouchableWithoutFeedback, View } from 'react-native';
import styles, { SIDEBAR_WIDTH } from './styles'; 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. * 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. * 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 * @inheritdoc
*/ */
componentWillReceiveProps({ show }: Props) { componentDidUpdate() {
(show === this.props.show) || this._setShow(show); this._setShow(this.props.show);
} }
/** /**
@ -148,8 +159,6 @@ export default class SideBar extends Component<Props, State> {
* @returns {void} * @returns {void}
*/ */
_setShow(show) { _setShow(show) {
show && this.setState({ showOverlay: true });
Animated Animated
.timing( .timing(
/* value */ this.state.sliderAnimation, /* value */ this.state.sliderAnimation,

View File

@ -206,6 +206,16 @@ export default class AbstractButton<P: Props, S: *> extends Component<P, S> {
return buttonStyles; 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 * Helper function to be implemented by subclasses, which must return a
* boolean value indicating if this button is disabled or not. * 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(), iconName: this._getIconName(),
label: this._getLabel(), label: this._getLabel(),
styles: this._getStyles(), styles: this._getStyles(),
tooltip: this.tooltip tooltip: this._getTooltip()
}; };
return ( return (

View File

@ -81,23 +81,15 @@ class DeepLinkingMobilePage extends Component<Props, State> {
constructor(props: Props) { constructor(props: Props) {
super(props); super(props);
this.state = {
joinURL: generateDeepLinkingURL()
};
// Bind event handlers so they are only bound once per instance. // Bind event handlers so they are only bound once per instance.
this._onDownloadApp = this._onDownloadApp.bind(this); this._onDownloadApp = this._onDownloadApp.bind(this);
this._onOpenApp = this._onOpenApp.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. * Implements the Component's componentDidMount method.
* *

View File

@ -1,7 +1,7 @@
// @flow // @flow
import Tabs from '@atlaskit/tabs'; import Tabs from '@atlaskit/tabs';
import React, { Component } from 'react'; import React, { PureComponent } from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { Dialog, hideDialog } from '../../base/dialog'; import { Dialog, hideDialog } from '../../base/dialog';
@ -94,12 +94,36 @@ type State = {
types: Array<string> types: Array<string>
}; };
/** /**
* React component for DesktopPicker. * React component for DesktopPicker.
* *
* @extends Component * @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; _poller = null;
state = { state = {
@ -133,7 +157,7 @@ class DesktopPicker extends Component<Props, State> {
this._updateSources = this._updateSources.bind(this); this._updateSources = this._updateSources.bind(this);
this.state.types 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(); 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. * Clean up component and DesktopCapturerSource store state.
* *
@ -241,17 +240,6 @@ class DesktopPicker extends Component<Props, State> {
return selectedSource; 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; _onCloseModal: (?string, string) => void;
/** /**

View File

@ -63,9 +63,9 @@ class AudioInputPreview extends Component<Props, State> {
* @inheritdoc * @inheritdoc
* @returns {void} * @returns {void}
*/ */
componentWillReceiveProps(nextProps: Props) { componentDidUpdate(prevProps: Props) {
if (nextProps.track !== this.props.track) { if (prevProps.track !== this.props.track) {
this._listenForAudioUpdates(nextProps.track); this._listenForAudioUpdates(this.props.track);
this._updateAudioLevel(0); 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} prevProps - Previous props this component received.
* @param {Object} prevState - Previous state this component had. * @param {Object} prevState - Previous state this component had.
@ -174,25 +175,15 @@ class DeviceSelection extends AbstractDialogTab<Props, State> {
}); });
}); });
} }
}
/** if (prevProps.selectedAudioInputId
* Updates audio input and video input previews. !== this.props.selectedAudioInputId) {
* this._createAudioInputTrack(this.props.selectedAudioInputId);
* @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) { if (prevProps.selectedVideoInputId
this._createVideoInputTrack(nextProps.selectedVideoInputId); !== this.props.selectedVideoInputId) {
this._createVideoInputTrack(this.props.selectedVideoInputId);
} }
} }

View File

@ -70,6 +70,12 @@ type Props = {
*/ */
type State = { 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. * Whether or not {@code InfoDialog} should be visible.
*/ */
@ -83,6 +89,23 @@ type State = {
* @extends Component * @extends Component
*/ */
class InfoDialogButton extends Component<Props, State> { 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. * Initializes new {@code InfoDialogButton} instance.
* *
@ -92,6 +115,7 @@ class InfoDialogButton extends Component<Props, State> {
super(props); super(props);
this.state = { this.state = {
hasConnectedToConference: props._isConferenceJoined,
showDialog: false 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()}. * 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; _onDialogClose: () => void;
/** /**

View File

@ -112,6 +112,28 @@ type State = {
class InfoDialog extends Component<Props, State> { class InfoDialog extends Component<Props, State> {
_copyElement: ?Object; _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. * {@code InfoDialog} component's local state.
* *
@ -162,28 +184,6 @@ class InfoDialog extends Component<Props, State> {
this._setCopyElement = this._setCopyElement.bind(this); 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()}. * Implements React's {@link Component#render()}.
* *

View File

@ -55,6 +55,17 @@ type State = {
* @extends Component * @extends Component
*/ */
class PasswordForm extends Component<Props, State> { class PasswordForm extends Component<Props, State> {
/**
* Implements React's {@link Component#getDerivedStateFromProps()}.
*
* @inheritdoc
*/
static getDerivedStateFromProps(props, state) {
return {
enteredPassword: props.editEnabled ? state.enteredPassword : ''
};
}
state = { state = {
enteredPassword: '' enteredPassword: ''
}; };
@ -74,19 +85,6 @@ class PasswordForm extends Component<Props, State> {
this._onPasswordSubmit = this._onPasswordSubmit.bind(this); 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()}. * Implements React's {@link Component#render()}.
* *
@ -182,5 +180,4 @@ class PasswordForm extends Component<Props, State> {
} }
} }
export default translate(PasswordForm); export default translate(PasswordForm);

View File

@ -32,6 +32,19 @@ type State = {
* @extends Component * @extends Component
*/ */
class Labels extends AbstractLabels<Props, State> { 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. * 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()}. * 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. * Starts or stops the interval to update the image displayed in the canvas.
* *
* @inheritdoc * @inheritdoc
* @param {Object} nextProps - The read-only React {@code Component} props
* with which the new instance is to be initialized.
*/ */
componentWillReceiveProps(nextProps: Props) { componentDidUpdate(prevProps: Props) {
if (this.props.hidden && !nextProps.hidden) { if (prevProps.hidden && !this.props.hidden) {
this._clearCanvas(); this._clearCanvas();
this._setUpdateCanvasInterval(); this._setUpdateCanvasInterval();
} }
if ((!this.props.hidden && nextProps.hidden) if ((!prevProps.hidden && this.props.hidden)
|| !nextProps.videoElement) { || !this.props.videoElement) {
this._clearCanvas(); this._clearCanvas();
this._clearUpdateCanvasInterval(); this._clearUpdateCanvasInterval();
} }

View File

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

View File

@ -54,6 +54,18 @@ const STALE_TIMEOUT = 10 * 1000;
*/ */
export default class AbstractRecordingLabel export default class AbstractRecordingLabel
extends Component<Props, State> { 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. * Initializes a new {@code AbstractRecordingLabel} component.
* *
@ -70,12 +82,12 @@ export default class AbstractRecordingLabel
} }
/** /**
* Implements {@code Component#componentWillReceiveProps}. * Implements {@code Component#componentDidUpdate}.
* *
* @inheritdoc * @inheritdoc
*/ */
componentWillReceiveProps(newProps: Props) { componentDidUpdate(prevProps: Props) {
this._updateStaleStatus(this.props, newProps); this._updateStaleStatus(prevProps, this.props);
} }
/** /**
@ -137,13 +149,8 @@ export default class AbstractRecordingLabel
} }
}, STALE_TIMEOUT); }, STALE_TIMEOUT);
} }
} else if (this.state.staleLabel) {
this.setState({
staleLabel: false
});
} }
} }
} }
/** /**

View File

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

View File

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

View File

@ -37,26 +37,6 @@ class LiveStreamButton extends AbstractLiveStreamButton<Props> {
iconName = 'icon-public'; iconName = 'icon-public';
toggledIconName = '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 * Helper function to be implemented by subclasses, which returns
* a React Element to display (a beta tag) at the end of the button. * 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 * Helper function to be implemented by subclasses, which must return a
* boolean value indicating if this button is disabled or not. * boolean value indicating if this button is disabled or not.

View File

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

View File

@ -36,23 +36,13 @@ class RecordButton extends AbstractRecordButton<Props> {
toggledIconName = 'icon-camera-take-picture'; 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) { _getTooltip() {
super(props); return this.tooltip || '';
this.tooltip = props._fileRecordingsDisabledTooltipKey;
}
/**
* Implements {@code Component}'s componentWillReceiveProps.
*
* @inheritdoc
*/
componentWillReceiveProps(newProps: Props) {
this.tooltip = newProps._fileRecordingsDisabledTooltipKey;
} }
/** /**

View File

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

View File

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

View File

@ -37,6 +37,17 @@ type Props = {
export class AbstractWelcomePage extends Component<Props, *> { export class AbstractWelcomePage extends Component<Props, *> {
_mounted: ?boolean; _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. * 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 * Implements React's {@link Component#componentDidMount()}. Invoked
* immediately before mounting occurs. * immediately after mounting occurs.
* *
* @inheritdoc * @inheritdoc
*/ */
componentWillMount() { componentDidMount() {
this._mounted = true; 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 * Implements React's {@link Component#componentWillUnmount()}. Invoked
* immediately before this component is unmounted and destroyed. * immediately before this component is unmounted and destroyed.

View File

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

View File

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