Improve performance of app - 1.182 🚀
The App.tsx had a bunch of separate useState calls which would cause unneccesary re-renders of the entire app. This became apparent after adding the global progress bar, since it caused even more re-renders to the point of being unusable.
This commit is contained in:
parent
49646c3107
commit
6950cd04f4
114
App.tsx
114
App.tsx
|
@ -1,27 +1,22 @@
|
|||
import {
|
||||
NavigationContainer,
|
||||
DarkTheme as NavigationDarkTheme,
|
||||
DefaultTheme as NavigationDefaultTheme,
|
||||
NavigationContainer,
|
||||
} from "@react-navigation/native";
|
||||
import React, { useEffect, useMemo, useState } from "react";
|
||||
import { useColorScheme } from "react-native";
|
||||
import {
|
||||
MD3DarkTheme as PaperDarkTheme,
|
||||
MD3LightTheme as PaperDefaultTheme,
|
||||
ProgressBar,
|
||||
Provider as PaperProvider,
|
||||
Snackbar,
|
||||
} from "react-native-paper";
|
||||
import MaterialIcon from "react-native-vector-icons/MaterialCommunityIcons";
|
||||
import AppSnack from "./AppSnack";
|
||||
import AppStack from "./AppStack";
|
||||
import TimerProgress from "./TimerProgress";
|
||||
import { AppDataSource } from "./data-source";
|
||||
import { settingsRepo } from "./db";
|
||||
import { emitter } from "./emitter";
|
||||
import { TickEvent } from "./TimerPage";
|
||||
import { TOAST } from "./toast";
|
||||
import { ThemeContext } from "./use-theme";
|
||||
import Settings from "./settings";
|
||||
import { MARGIN } from "./constants";
|
||||
|
||||
export const CombinedDefaultTheme = {
|
||||
...NavigationDefaultTheme,
|
||||
|
@ -43,61 +38,54 @@ export const CombinedDarkTheme = {
|
|||
|
||||
const App = () => {
|
||||
const phoneTheme = useColorScheme();
|
||||
const [initialized, setInitialized] = useState(false);
|
||||
const [snackbar, setSnackbar] = useState("");
|
||||
const [appTheme, setAppTheme] = useState("system");
|
||||
const [progress, setProgress] = useState(0);
|
||||
const [settings, setSettings] = useState<Settings>();
|
||||
|
||||
const [lightColor, setLightColor] = useState<string>(
|
||||
CombinedDefaultTheme.colors.primary
|
||||
);
|
||||
const [appSettings, setAppSettings] = useState({
|
||||
startup: undefined,
|
||||
theme: "system",
|
||||
lightColor: CombinedDefaultTheme.colors.primary,
|
||||
darkColor: CombinedDarkTheme.colors.primary,
|
||||
});
|
||||
|
||||
const [darkColor, setDarkColor] = useState<string>(
|
||||
CombinedDarkTheme.colors.primary
|
||||
);
|
||||
console.log("Rerendered App");
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
if (!AppDataSource.isInitialized) await AppDataSource.initialize();
|
||||
const gotSettings = await settingsRepo.findOne({ where: {} });
|
||||
console.log({ gotSettings });
|
||||
setSettings(gotSettings);
|
||||
setAppTheme(gotSettings.theme);
|
||||
if (gotSettings.lightColor) setLightColor(gotSettings.lightColor);
|
||||
if (gotSettings.darkColor) setDarkColor(gotSettings.darkColor);
|
||||
setInitialized(true);
|
||||
setAppSettings({
|
||||
startup: gotSettings.startup,
|
||||
theme: gotSettings.theme,
|
||||
lightColor: gotSettings.lightColor,
|
||||
darkColor: gotSettings.darkColor,
|
||||
});
|
||||
})();
|
||||
|
||||
const descriptions = [
|
||||
emitter.addListener(TOAST, ({ value }: { value: string }) => {
|
||||
setSnackbar(value);
|
||||
}),
|
||||
emitter.addListener("tick", (event: TickEvent) => {
|
||||
setProgress((Number(event.minutes) * 60 + Number(event.seconds)) / 210);
|
||||
}),
|
||||
];
|
||||
return () => descriptions.forEach((description) => description.remove());
|
||||
}, []);
|
||||
|
||||
const paperTheme = useMemo(() => {
|
||||
const darkTheme = lightColor
|
||||
const darkTheme = appSettings.lightColor
|
||||
? {
|
||||
...CombinedDarkTheme,
|
||||
colors: { ...CombinedDarkTheme.colors, primary: darkColor },
|
||||
colors: {
|
||||
...CombinedDarkTheme.colors,
|
||||
primary: appSettings.darkColor,
|
||||
},
|
||||
}
|
||||
: CombinedDarkTheme;
|
||||
const lightTheme = lightColor
|
||||
const lightTheme = appSettings.lightColor
|
||||
? {
|
||||
...CombinedDefaultTheme,
|
||||
colors: { ...CombinedDefaultTheme.colors, primary: lightColor },
|
||||
colors: {
|
||||
...CombinedDefaultTheme.colors,
|
||||
primary: appSettings.lightColor,
|
||||
},
|
||||
}
|
||||
: CombinedDefaultTheme;
|
||||
let value = phoneTheme === "dark" ? darkTheme : lightTheme;
|
||||
if (appTheme === "dark") value = darkTheme;
|
||||
else if (appTheme === "light") value = lightTheme;
|
||||
if (appSettings.theme === "dark") value = darkTheme;
|
||||
else if (appSettings.theme === "light") value = lightTheme;
|
||||
return value;
|
||||
}, [phoneTheme, appTheme, lightColor, darkColor]);
|
||||
}, [phoneTheme, appSettings]);
|
||||
|
||||
return (
|
||||
<PaperProvider
|
||||
|
@ -105,46 +93,26 @@ const App = () => {
|
|||
settings={{ icon: (props) => <MaterialIcon {...props} /> }}
|
||||
>
|
||||
<NavigationContainer theme={paperTheme}>
|
||||
{initialized && (
|
||||
{appSettings.startup !== undefined && (
|
||||
<ThemeContext.Provider
|
||||
value={{
|
||||
theme: appTheme,
|
||||
setTheme: setAppTheme,
|
||||
lightColor,
|
||||
setLightColor,
|
||||
darkColor,
|
||||
setDarkColor,
|
||||
theme: appSettings.theme,
|
||||
setTheme: (theme) => setAppSettings({ ...appSettings, theme }),
|
||||
lightColor: appSettings.lightColor,
|
||||
setLightColor: (color) =>
|
||||
setAppSettings({ ...appSettings, lightColor: color }),
|
||||
darkColor: appSettings.darkColor,
|
||||
setDarkColor: (color) =>
|
||||
setAppSettings({ ...appSettings, darkColor: color }),
|
||||
}}
|
||||
>
|
||||
<AppStack settings={settings} />
|
||||
<AppStack startup={appSettings.startup} />
|
||||
</ThemeContext.Provider>
|
||||
)}
|
||||
</NavigationContainer>
|
||||
|
||||
<Snackbar
|
||||
duration={3000}
|
||||
onDismiss={() => setSnackbar("")}
|
||||
visible={!!snackbar}
|
||||
action={{
|
||||
label: "Close",
|
||||
onPress: () => setSnackbar(""),
|
||||
textColor: paperTheme.colors.background,
|
||||
}}
|
||||
>
|
||||
{snackbar}
|
||||
</Snackbar>
|
||||
|
||||
{progress > 0 && (
|
||||
<ProgressBar
|
||||
style={{
|
||||
position: "absolute",
|
||||
bottom: MARGIN / 2,
|
||||
left: MARGIN,
|
||||
right: MARGIN,
|
||||
}}
|
||||
progress={progress}
|
||||
/>
|
||||
)}
|
||||
<AppSnack textColor={paperTheme.colors.background} />
|
||||
<TimerProgress />
|
||||
</PaperProvider>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { createDrawerNavigator } from "@react-navigation/drawer";
|
||||
import { StackScreenProps } from "@react-navigation/stack";
|
||||
import { IconButton } from "react-native-paper";
|
||||
import { DrawerParams } from "./drawer-param-list";
|
||||
import ExerciseList from "./ExerciseList";
|
||||
import GraphsList from "./GraphsList";
|
||||
import InsightsPage from "./InsightsPage";
|
||||
|
@ -8,20 +8,19 @@ import PlanList from "./PlanList";
|
|||
import SetList from "./SetList";
|
||||
import SettingsPage from "./SettingsPage";
|
||||
import TimerPage from "./TimerPage";
|
||||
import useDark from "./use-dark";
|
||||
import WeightList from "./WeightList";
|
||||
import Settings from "./settings";
|
||||
import { StackScreenProps } from "@react-navigation/stack";
|
||||
import { DrawerParams } from "./drawer-param-list";
|
||||
import useDark from "./use-dark";
|
||||
|
||||
const Drawer = createDrawerNavigator<DrawerParams>();
|
||||
|
||||
interface AppDrawerParams {
|
||||
settings: Settings;
|
||||
startup: string;
|
||||
}
|
||||
|
||||
export default function AppDrawer({
|
||||
route,
|
||||
}: StackScreenProps<{ settings: AppDrawerParams }>) {
|
||||
}: StackScreenProps<{ startup: AppDrawerParams }>) {
|
||||
const dark = useDark();
|
||||
|
||||
return (
|
||||
|
@ -31,9 +30,7 @@ export default function AppDrawer({
|
|||
swipeEdgeWidth: 1000,
|
||||
headerShown: false,
|
||||
}}
|
||||
initialRouteName={
|
||||
(route.params.settings.startup || "Home") as keyof DrawerParams
|
||||
}
|
||||
initialRouteName={(route.params.startup || "Home") as keyof DrawerParams}
|
||||
>
|
||||
<Drawer.Screen
|
||||
name="Home"
|
||||
|
|
33
AppSnack.tsx
Normal file
33
AppSnack.tsx
Normal file
|
@ -0,0 +1,33 @@
|
|||
import React, { useEffect, useState } from "react";
|
||||
import { Snackbar } from "react-native-paper";
|
||||
import { emitter } from "./emitter";
|
||||
import { TOAST } from "./toast";
|
||||
|
||||
export default function AppSnack({ textColor }: { textColor: string }) {
|
||||
const [snackbar, setSnackbar] = useState("");
|
||||
|
||||
useEffect(() => {
|
||||
const description = emitter.addListener(
|
||||
TOAST,
|
||||
({ value }: { value: string }) => {
|
||||
setSnackbar(value);
|
||||
}
|
||||
);
|
||||
return description.remove;
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Snackbar
|
||||
duration={3000}
|
||||
onDismiss={() => setSnackbar("")}
|
||||
visible={!!snackbar}
|
||||
action={{
|
||||
label: "Close",
|
||||
onPress: () => setSnackbar(""),
|
||||
textColor,
|
||||
}}
|
||||
>
|
||||
{snackbar}
|
||||
</Snackbar>
|
||||
);
|
||||
}
|
|
@ -50,7 +50,7 @@ export type StackParams = {
|
|||
|
||||
const Stack = createStackNavigator<StackParams>();
|
||||
|
||||
export default function AppStack({ settings }: { settings: Settings }) {
|
||||
export default function AppStack({ startup }: { startup: string }) {
|
||||
return (
|
||||
<Stack.Navigator
|
||||
screenOptions={{ headerShown: false, animationEnabled: false }}
|
||||
|
@ -58,7 +58,7 @@ export default function AppStack({ settings }: { settings: Settings }) {
|
|||
<Stack.Screen
|
||||
name="Drawer"
|
||||
component={AppDrawer}
|
||||
initialParams={{ settings }}
|
||||
initialParams={{ startup }}
|
||||
/>
|
||||
<Stack.Screen name="EditSet" component={EditSet} />
|
||||
<Stack.Screen name="EditSets" component={EditSets} />
|
||||
|
|
30
TimerProgress.tsx
Normal file
30
TimerProgress.tsx
Normal file
|
@ -0,0 +1,30 @@
|
|||
import { useEffect, useState } from "react";
|
||||
import { emitter } from "./emitter";
|
||||
import { TickEvent } from "./TimerPage";
|
||||
import { ProgressBar } from "react-native-paper";
|
||||
|
||||
export default function TimerProgress() {
|
||||
const [progress, setProgress] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
const description = emitter.addListener(
|
||||
"tick",
|
||||
({ minutes, seconds }: TickEvent) => {
|
||||
setProgress((Number(minutes) * 60 + Number(seconds)) / 210);
|
||||
}
|
||||
);
|
||||
return description.remove;
|
||||
}, []);
|
||||
|
||||
if (progress === 0) return null;
|
||||
|
||||
return (
|
||||
<ProgressBar
|
||||
style={{
|
||||
position: "absolute",
|
||||
bottom: 0,
|
||||
}}
|
||||
progress={progress}
|
||||
/>
|
||||
);
|
||||
}
|
|
@ -85,8 +85,8 @@ android {
|
|||
applicationId "com.massive"
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode 36207
|
||||
versionName "1.181"
|
||||
versionCode 36208
|
||||
versionName "1.182"
|
||||
}
|
||||
signingConfigs {
|
||||
release {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "massive",
|
||||
"version": "1.181",
|
||||
"version": "1.182",
|
||||
"private": true,
|
||||
"license": "GPL-3.0-only",
|
||||
"scripts": {
|
||||
|
|
Loading…
Reference in New Issue
Block a user