summaryrefslogtreecommitdiffhomepage
path: root/gui
diff options
context:
space:
mode:
authorOskar Nyberg <oskar@mullvad.net>2022-09-07 15:57:09 +0200
committerOskar Nyberg <oskar@mullvad.net>2022-09-09 09:33:44 +0200
commit04b2f58527e7ec60a18de93108dacd4bf99e70fe (patch)
tree2a450ed4d00f333fdeeeaf946481d006f21b3b57 /gui
parent79bd0197520fe657564a16c19c59474231eca394 (diff)
downloadmullvadvpn-04b2f58527e7ec60a18de93108dacd4bf99e70fe.tar.xz
mullvadvpn-04b2f58527e7ec60a18de93108dacd4bf99e70fe.zip
Add component for pausing redux
Diffstat (limited to 'gui')
-rw-r--r--gui/src/renderer/components/Modal.tsx12
-rw-r--r--gui/src/renderer/components/TransitionContainer.tsx33
-rw-r--r--gui/src/renderer/lib/will-exit.tsx13
-rw-r--r--gui/src/renderer/redux/store.ts14
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;
}