diff options
| author | Oskar Nyberg <oskar@mullvad.net> | 2022-09-07 15:57:09 +0200 |
|---|---|---|
| committer | Oskar Nyberg <oskar@mullvad.net> | 2022-09-09 09:33:44 +0200 |
| commit | 04b2f58527e7ec60a18de93108dacd4bf99e70fe (patch) | |
| tree | 2a450ed4d00f333fdeeeaf946481d006f21b3b57 /gui | |
| parent | 79bd0197520fe657564a16c19c59474231eca394 (diff) | |
| download | mullvadvpn-04b2f58527e7ec60a18de93108dacd4bf99e70fe.tar.xz mullvadvpn-04b2f58527e7ec60a18de93108dacd4bf99e70fe.zip | |
Add component for pausing redux
Diffstat (limited to 'gui')
| -rw-r--r-- | gui/src/renderer/components/Modal.tsx | 12 | ||||
| -rw-r--r-- | gui/src/renderer/components/TransitionContainer.tsx | 33 | ||||
| -rw-r--r-- | gui/src/renderer/lib/will-exit.tsx | 13 | ||||
| -rw-r--r-- | gui/src/renderer/redux/store.ts | 14 |
4 files changed, 55 insertions, 17 deletions
diff --git a/gui/src/renderer/components/Modal.tsx b/gui/src/renderer/components/Modal.tsx index f6fa9f25b4..8d96d47c7b 100644 --- a/gui/src/renderer/components/Modal.tsx +++ b/gui/src/renderer/components/Modal.tsx @@ -4,6 +4,7 @@ import styled from 'styled-components'; import { colors } from '../../config.json'; import log from '../../shared/logging'; +import { usePause } from '../lib/pause-rendering'; import { tinyText } from './common-styles'; import CustomScrollbars from './CustomScrollbars'; import ImageView from './ImageView'; @@ -162,12 +163,19 @@ export function ModalAlert(props: IModalAlertProps & { isOpen: boolean }) { const [closing, setClosing] = useState(false); const prevIsOpen = useRef(isOpen); - const onTransitionEnd = useCallback(() => setClosing(false), []); + const [paused, runIfNotPaused] = usePause(); + useEffect(() => { setClosing((closing) => closing || (prevIsOpen.current && !isOpen)); - prevIsOpen.current = isOpen; + + // Unmounting the Modal during view transitions result in a visual glitch. + runIfNotPaused(() => { + prevIsOpen.current = isOpen; + }); }, [isOpen]); + const onTransitionEnd = useCallback(() => runIfNotPaused(() => setClosing(false)), [paused]); + if (!prevIsOpen.current && !isOpen && !closing) { return null; } diff --git a/gui/src/renderer/components/TransitionContainer.tsx b/gui/src/renderer/components/TransitionContainer.tsx index e360e6838e..30827bd903 100644 --- a/gui/src/renderer/components/TransitionContainer.tsx +++ b/gui/src/renderer/components/TransitionContainer.tsx @@ -2,6 +2,7 @@ import * as React from 'react'; import styled from 'styled-components'; import { ITransitionSpecification } from '../lib/history'; +import { PauseRendering } from '../lib/pause-rendering'; interface ITransitioningViewProps { viewId: string; @@ -155,28 +156,32 @@ export default class TransitionContainer extends React.Component<IProps, IState> public render() { const disableUserInteraction = - this.state.itemQueue.length > 0 || this.state.nextItem ? true : false; + this.state.itemQueue.length > 0 || this.state.nextItem !== undefined; return ( <StyledTransitionContainer disableUserInteraction={disableUserInteraction}> {this.state.currentItem && ( - <StyledTransitionContent + <PauseRendering key={this.state.currentItem.view.props.viewId} - ref={this.currentContentRef} - transition={this.state.currentItemStyle} - onTransitionEnd={this.onTransitionEnd}> - {this.state.currentItem.view} - </StyledTransitionContent> + pause={disableUserInteraction}> + <StyledTransitionContent + ref={this.currentContentRef} + transition={this.state.currentItemStyle} + onTransitionEnd={this.onTransitionEnd}> + {this.state.currentItem.view} + </StyledTransitionContent> + </PauseRendering> )} {this.state.nextItem && ( - <StyledTransitionContent - key={this.state.nextItem.view.props.viewId} - ref={this.nextContentRef} - transition={this.state.nextItemStyle} - onTransitionEnd={this.onTransitionEnd}> - {this.state.nextItem.view} - </StyledTransitionContent> + <PauseRendering key={this.state.nextItem.view.props.viewId}> + <StyledTransitionContent + ref={this.nextContentRef} + transition={this.state.nextItemStyle} + onTransitionEnd={this.onTransitionEnd}> + {this.state.nextItem.view} + </StyledTransitionContent> + </PauseRendering> )} </StyledTransitionContainer> ); diff --git a/gui/src/renderer/lib/will-exit.tsx b/gui/src/renderer/lib/will-exit.tsx new file mode 100644 index 0000000000..67ce4c5549 --- /dev/null +++ b/gui/src/renderer/lib/will-exit.tsx @@ -0,0 +1,13 @@ +import React, { useContext } from 'react'; + +// This context tells its subtree if it should stop rendering or not. This is useful during +// transitions, e.g. on log out, since data might be updated which makes the disappearing view +// update a lot during the transition. There's currently no support for unpausing, which can be +// added later if needed. +const willExitContext = React.createContext<boolean>(false); + +export const WillExit = willExitContext.Provider; + +export function useWillExit() { + return useContext(willExitContext); +} diff --git a/gui/src/renderer/redux/store.ts b/gui/src/renderer/redux/store.ts index 79700497c6..a8d3a302b6 100644 --- a/gui/src/renderer/redux/store.ts +++ b/gui/src/renderer/redux/store.ts @@ -1,6 +1,8 @@ +import { useRef } from 'react'; import { useSelector as useReduxSelector } from 'react-redux'; import { combineReducers, compose, createStore, Dispatch } from 'redux'; +import { usePause } from '../lib/pause-rendering'; import accountActions, { AccountAction } from './account/actions'; import accountReducer, { IAccountReduxState } from './account/reducers'; import connectionActions, { ConnectionAction } from './connection/actions'; @@ -64,6 +66,16 @@ function composeEnhancers(): typeof compose { : compose(); } +// This hook adds typing to state to make use simpler. It also prevents the state from update if the +// ReduxPause context has been told to pause updates caused by new values in the redux state. export function useSelector<R>(fn: (state: IReduxState) => R): R { - return useReduxSelector(fn); + const [paused] = usePause(); + const value = useReduxSelector(fn); + const valueBeforePause = useRef(value); + + if (!paused) { + valueBeforePause.current = value; + } + + return paused ? valueBeforePause.current : value; } |
