diff --git a/Libraries/Components/StatusBar/StatusBar.js b/Libraries/Components/StatusBar/StatusBar.js index 6448283651d8f9..7b2913a416874b 100644 --- a/Libraries/Components/StatusBar/StatusBar.js +++ b/Libraries/Components/StatusBar/StatusBar.js @@ -138,11 +138,34 @@ function createStackEntry(props: any): any { * * ### Imperative API * - * For cases where using a component is not ideal, there is also an imperative - * API exposed as static functions on the component. It is however not recommended - * to use the static API and the component for the same prop because any value - * set by the static API will get overriden by the one set by the component in - * the next render. + * For cases where using a component is not ideal, there are static methods + * to manipulate the `StatusBar` display stack. These methods have the same + * behavior as mounting and unmounting a `StatusBar` component. + * + * For example, you can call `StatusBar.pushStackEntry` to update the status bar + * before launching a third-party native UI component, and then call + * `StatusBar.popStackEntry` when completed. + * + * ``` + * const openThirdPartyBugReporter = async () => { + * // The bug reporter has a dark background, so we push a new status bar style. + * const stackEntry = StatusBar.pushStackEntry({barStyle: 'light-content'}); + * + * // `open` returns a promise that resolves when the UI is dismissed. + * await BugReporter.open(); + * + * // Don't forget to call `popStackEntry` when you're done. + * StatusBar.popStackEntry(stackEntry); + * }; + * ``` + * + * There is legacy imperative API that enables you to manually update the + * status bar styles. However, the legacy API does not update the internal + * `StatusBar` diaplay stack, which means that any changes will be overridden + * whenever a `StatusBar` component is mounted or unmounted. + * + * It is strongly advised that you use `pushStackEntry`, `popStackEntry`, or + * `replaceStackEntry` instead of the static methods beginning with `set`. * * ### Constants * @@ -261,6 +284,48 @@ class StatusBar extends React.Component<{ StatusBarManager.setTranslucent(translucent); } + /** + * Push a StatusBar entry onto the stack. + * The return value should be passed to `popStackEntry` when complete. + * + * @param props Object containing the StatusBar props to use in the stack entry. + */ + static pushStackEntry(props) { + const entry = createStackEntry(props); + StatusBar._propsStack.push(entry); + StatusBar._updatePropsStack(); + return entry; + } + + /** + * Pop a StatusBar entry from the stack. + * + * @param entry Entry returned from `pushStackEntry`. + */ + static popStackEntry(entry) { + const index = StatusBar._propsStack.indexOf(entry); + if (index !== -1) { + StatusBar._propsStack.splice(index, 1); + } + StatusBar._updatePropsStack(); + } + + /** + * Replace an existing StatusBar stack entry with new props. + * + * @param entry Entry returned from `pushStackEntry` to replace. + * @param props Object containing the StatusBar props to use in the replacement stack entry. + */ + static replaceStackEntry(entry, props) { + const newEntry = createStackEntry(props); + const index = StatusBar._propsStack.indexOf(entry); + if (index !== -1) { + StatusBar._propsStack[index] = newEntry; + } + StatusBar._updatePropsStack(); + return newEntry; + } + static propTypes = { /** * If the status bar is hidden. @@ -314,33 +379,24 @@ class StatusBar extends React.Component<{ // Every time a StatusBar component is mounted, we push it's prop to a stack // and always update the native status bar with the props from the top of then // stack. This allows having multiple StatusBar components and the one that is - // added last or is deeper in the view hierarchy will have priority. - this._stackEntry = createStackEntry(this.props); - StatusBar._propsStack.push(this._stackEntry); - this._updatePropsStack(); + // added last or is deeper in the view hierachy will have priority. + this._stackEntry = StatusBar.pushStackEntry(this.props); } componentWillUnmount() { // When a StatusBar is unmounted, remove itself from the stack and update // the native bar with the next props. - const index = StatusBar._propsStack.indexOf(this._stackEntry); - StatusBar._propsStack.splice(index, 1); - - this._updatePropsStack(); + StatusBar.popStackEntry(this._stackEntry); } componentDidUpdate() { - const index = StatusBar._propsStack.indexOf(this._stackEntry); - this._stackEntry = createStackEntry(this.props); - StatusBar._propsStack[index] = this._stackEntry; - - this._updatePropsStack(); + this._stackEntry = StatusBar.replaceStackEntry(this._stackEntry, this.props); } /** * Updates the native status bar with the props from the stack. */ - _updatePropsStack = () => { + static _updatePropsStack = () => { // Send the update to the native module only once at the end of the frame. clearImmediate(StatusBar._updateImmediate); StatusBar._updateImmediate = setImmediate(() => { @@ -358,7 +414,7 @@ class StatusBar extends React.Component<{ ) { StatusBarManager.setStyle( mergedProps.barStyle.value, - mergedProps.barStyle.animated, + mergedProps.barStyle.animated || false, ); } if (!oldProps || oldProps.hidden.value !== mergedProps.hidden.value) {