From 53fe04a5724f657bb63ca94cc7ea95d5f8f9de7b Mon Sep 17 00:00:00 2001
From: Mothblocks <35135081+Mothblocks@users.noreply.github.com>
Date: Tue, 5 May 2026 20:36:00 -0700
Subject: [PATCH] Fix broken React usage with dropdowns causing unnecessary
re-renders in preferences (#95904)
Fixes
https://github.com/tgstation/tgstation/issues/95860#issuecomment-4320548139.
Thank you to @leaKsi for isolating it
React lints would've caught this--components not being components'd
properly and then an inline callback ended up causing a bunch of
re-renders.
I didn't test shit
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
---
.../character_preferences/body_type.tsx | 38 +++++++++++++------
.../preferences/features/dropdowns.tsx | 38 ++++++++++++++-----
2 files changed, 54 insertions(+), 22 deletions(-)
diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/body_type.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/body_type.tsx
index 058ecb2ebda..d874deb7c94 100644
--- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/body_type.tsx
+++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/body_type.tsx
@@ -1,7 +1,9 @@
+import { useCallback } from 'react';
import { Gender } from '../../gender';
-import type { FeatureChoiced } from '../base';
+import type { FeatureChoicedServerData, FeatureChoiced } from '../base';
import {
type DropdownInputProps,
+ type DropdownOptions,
FeatureDropdownInputCore,
generateOptions,
} from '../dropdowns';
@@ -12,17 +14,29 @@ export const body_type: FeatureChoiced = {
};
function FeatureBodyTypeDropdownInput(props: DropdownInputProps) {
- return FeatureDropdownInputCore(props, (serverData, setDropdownOptions) => {
- let options = generateOptions(serverData);
+ const currentGender = props.character_preferences.misc.gender;
- const current_gender = props.character_preferences.misc.gender;
- if (current_gender !== Gender.Male && current_gender !== Gender.Female) {
- options = options.filter(
- (option) =>
- option.value === Gender.Male || option.value === Gender.Female,
- );
- }
+ const populateOptions = useCallback(
+ (
+ serverData: FeatureChoicedServerData,
+ setDropdownOptions: (newValue: DropdownOptions) => void
+ ) => {
+ let options = generateOptions(serverData);
- setDropdownOptions(options);
- });
+ if (currentGender !== Gender.Male && currentGender !== Gender.Female) {
+ options = options.filter(
+ (option) =>
+ option.value === Gender.Male || option.value === Gender.Female,
+ );
+ }
+
+ setDropdownOptions(options);
+ },
+ [currentGender],
+ );
+
+ return
}
diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/dropdowns.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/dropdowns.tsx
index 5cbe2a8697d..fbc9f4dc690 100644
--- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/dropdowns.tsx
+++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/dropdowns.tsx
@@ -1,6 +1,7 @@
import {
type ComponentProps,
type ReactNode,
+ useCallback,
useEffect,
useState,
} from 'react';
@@ -32,7 +33,7 @@ type IconnedDropdownInputProps = FeatureValueProps<
export type FeatureWithIcons = Feature;
-type DropdownOptions = ComponentProps['options'];
+export type DropdownOptions = ComponentProps['options'];
type DropdownEntry = {
displayText: ReactNode;
@@ -60,20 +61,20 @@ export function generateOptions(
return newOptions;
}
-export function FeatureDropdownInput(props: DropdownInputProps) {
- return FeatureDropdownInputCore(props, (serverData, setDropdownOptions) =>
- setDropdownOptions(generateOptions(serverData)),
- );
-}
-
-export function FeatureDropdownInputCore(
- props: DropdownInputProps,
+export type FeatureDropdownInputCoreProps = {
+ dropdownProps: DropdownInputProps,
populateOptions: (
serverData: FeatureChoicedServerData,
setDropdownOptions: (newValue: DropdownOptions) => void,
) => void,
+}
+
+export function FeatureDropdownInputCore(
+ props: FeatureDropdownInputCoreProps
) {
- const { serverData, disabled, buttons, handleSetValue, value } = props;
+ const { dropdownProps, populateOptions } = props;
+ const { serverData, disabled, buttons, handleSetValue, value } =
+ dropdownProps;
const [dropdownOptions, setDropdownOptions] = useState([]);
@@ -98,6 +99,23 @@ export function FeatureDropdownInputCore(
);
}
+export function FeatureDropdownInput(props: DropdownInputProps) {
+ const populateOptions = useCallback(
+ (
+ serverData: FeatureChoicedServerData,
+ setDropdownOptions: (newValue: DropdownOptions) => void
+ ) => {
+ setDropdownOptions(generateOptions(serverData));
+ },
+ [],
+ );
+
+ return
+}
+
export function FeatureIconnedDropdownInput(props: IconnedDropdownInputProps) {
const { serverData, handleSetValue, value } = props;