diff --git a/src/app/WardrobePage/Item.js b/src/app/WardrobePage/Item.js
index 139b7d06..94cd82b2 100644
--- a/src/app/WardrobePage/Item.js
+++ b/src/app/WardrobePage/Item.js
@@ -29,12 +29,15 @@ const LoadableItemSupportDrawer = loadable(() =>
* In fact, this component can't trigger wear or unwear events! When you click
* it in the app, you're actually clicking a
diff --git a/src/app/WardrobePage/SearchPanel.js b/src/app/WardrobePage/SearchPanel.js
index 44a87c66..d37565cd 100644
--- a/src/app/WardrobePage/SearchPanel.js
+++ b/src/app/WardrobePage/SearchPanel.js
@@ -4,7 +4,7 @@ import { Box, Text, VisuallyHidden } from "@chakra-ui/core";
import { useQuery } from "@apollo/client";
import { Delay, Heading1, useDebounce } from "../util";
-import { Item, ItemListContainer, ItemListSkeleton } from "./Item";
+import Item, { ItemListContainer, ItemListSkeleton } from "./Item";
import { itemAppearanceFragment } from "../components/useOutfitAppearance";
/**
@@ -173,7 +173,8 @@ function SearchResults({
/>
diff --git a/src/app/WardrobePage/index.js b/src/app/WardrobePage/index.js
index e1057c65..c7b7e520 100644
--- a/src/app/WardrobePage/index.js
+++ b/src/app/WardrobePage/index.js
@@ -4,7 +4,7 @@ import loadable from "@loadable/component";
import ItemsAndSearchPanels from "./ItemsAndSearchPanels";
import OutfitPreview from "../components/OutfitPreview";
-import useOutfitState from "./useOutfitState.js";
+import useOutfitState, { OutfitStateContext } from "./useOutfitState.js";
import { usePageTitle } from "../util";
const OutfitControls = loadable(() =>
@@ -44,58 +44,64 @@ function WardrobePage() {
}, [error, toast]);
return (
-
-
+
-
-
-
+
+
+
+
+
+
+
+
-
-
+
-
-
-
-
-
-
+
+
+
);
}
diff --git a/src/app/WardrobePage/support/ItemSupportDrawer.js b/src/app/WardrobePage/support/ItemSupportDrawer.js
index 81f42e1e..9077a9e0 100644
--- a/src/app/WardrobePage/support/ItemSupportDrawer.js
+++ b/src/app/WardrobePage/support/ItemSupportDrawer.js
@@ -28,6 +28,7 @@ import { CheckCircleIcon, EditIcon, ExternalLinkIcon } from "@chakra-ui/icons";
import ItemLayerSupportModal from "./ItemLayerSupportModal";
import { OutfitLayers } from "../../components/OutfitPreview";
import useOutfitAppearance from "../../components/useOutfitAppearance";
+import { OutfitStateContext } from "../useOutfitState";
import useSupportSecret from "./useSupportSecret";
/**
@@ -36,7 +37,7 @@ import useSupportSecret from "./useSupportSecret";
* This component controls the drawer element. The actual content is imported
* from another lazy-loaded component!
*/
-function ItemSupportDrawer({ item, outfitState, isOpen, onClose }) {
+function ItemSupportDrawer({ item, isOpen, onClose }) {
const placement = useBreakpointValue({
base: "bottom",
lg: "right",
@@ -75,10 +76,7 @@ function ItemSupportDrawer({ item, outfitState, isOpen, onClose }) {
-
+
@@ -231,7 +229,15 @@ function ItemSupportSpecialColorFields({ item }) {
);
}
-function ItemSupportAppearanceFields({ item, outfitState }) {
+/**
+ * NOTE: This component takes `outfitState` from context, rather than as a prop
+ * from its parent, for performance reasons. We want `Item` to memoize
+ * and generally skip re-rendering on `outfitState` changes, and to make
+ * sure the context isn't accessed when the drawer is closed. So we use
+ * it here, only when the drawer is open!
+ */
+function ItemSupportAppearanceFields({ item }) {
+ const outfitState = React.useContext(OutfitStateContext);
const { speciesId, colorId, pose } = outfitState;
const { error, visibleLayers } = useOutfitAppearance({
speciesId,
diff --git a/src/app/WardrobePage/useOutfitState.js b/src/app/WardrobePage/useOutfitState.js
index 22488743..e9ff0a77 100644
--- a/src/app/WardrobePage/useOutfitState.js
+++ b/src/app/WardrobePage/useOutfitState.js
@@ -7,6 +7,8 @@ import { itemAppearanceFragment } from "../components/useOutfitAppearance";
enableMapSet();
+export const OutfitStateContext = React.createContext(null);
+
function useOutfitState() {
const apolloClient = useApolloClient();
const initialState = parseOutfitUrl();