Item page perf: memoize species faces

This is a pretty easy change, that makes re-renders faster when something about the item preview state changes!

That said, the initial render is still pretty slow, too, and that's the one that's bothering me more lol
This commit is contained in:
Emi Matchu 2021-06-11 06:45:11 -07:00
parent 07bf555a02
commit ab2dbeb02a
2 changed files with 242 additions and 222 deletions

View file

@ -528,9 +528,9 @@ function ItemPageOutfitPreview({ itemId }) {
null null
); );
const setPetStateFromUserAction = (newPetState) => { const setPetStateFromUserAction = React.useCallback(
setPetState(newPetState); (newPetState) =>
setPetState((prevPetState) => {
// When the user _intentionally_ chooses a species or color, save it in // When the user _intentionally_ chooses a species or color, save it in
// local storage for next time. (This won't update when e.g. their // local storage for next time. (This won't update when e.g. their
// preferred species or color isn't available for this item, so we update // preferred species or color isn't available for this item, so we update
@ -539,10 +539,16 @@ function ItemPageOutfitPreview({ itemId }) {
// Re the "ifs", I have no reason to expect null to come in here, but, // Re the "ifs", I have no reason to expect null to come in here, but,
// since this is touching client-persisted data, I want it to be even more // since this is touching client-persisted data, I want it to be even more
// reliable than usual! // reliable than usual!
if (newPetState.speciesId && newPetState.speciesId !== petState.speciesId) { if (
newPetState.speciesId &&
newPetState.speciesId !== prevPetState.speciesId
) {
setPreferredSpeciesId(newPetState.speciesId); setPreferredSpeciesId(newPetState.speciesId);
} }
if (newPetState.colorId && newPetState.colorId !== petState.colorId) { if (
newPetState.colorId &&
newPetState.colorId !== prevPetState.colorId
) {
if (colorIsBasic(newPetState.colorId)) { if (colorIsBasic(newPetState.colorId)) {
// When the user chooses a basic color, don't index on it specifically, // When the user chooses a basic color, don't index on it specifically,
// and instead reset to use default colors. // and instead reset to use default colors.
@ -551,7 +557,11 @@ function ItemPageOutfitPreview({ itemId }) {
setPreferredColorId(newPetState.colorId); setPreferredColorId(newPetState.colorId);
} }
} }
};
return newPetState;
}),
[setPreferredColorId, setPreferredSpeciesId]
);
// We don't need to reload this query when preferred species/color change, so // We don't need to reload this query when preferred species/color change, so
// cache their initial values here to use as query arguments. // cache their initial values here to use as query arguments.
@ -694,6 +704,21 @@ function ItemPageOutfitPreview({ itemId }) {
const isCompatible = itemLayers.length > 0; const isCompatible = itemLayers.length > 0;
const usesHTML5 = itemLayers.every(layerUsesHTML5); const usesHTML5 = itemLayers.every(layerUsesHTML5);
const onChange = React.useCallback(
({ speciesId, colorId }) => {
const validPoses = getValidPoses(valids, speciesId, colorId);
const pose = getClosestPose(validPoses, idealPose);
setPetStateFromUserAction({
speciesId,
colorId,
pose,
isValid: true,
appearanceId: null,
});
},
[valids, idealPose, setPetStateFromUserAction]
);
const borderColor = useColorModeValue("green.700", "green.400"); const borderColor = useColorModeValue("green.700", "green.400");
const errorColor = useColorModeValue("red.600", "red.400"); const errorColor = useColorModeValue("red.600", "red.400");
@ -824,17 +849,7 @@ function ItemPageOutfitPreview({ itemId }) {
selectedColorId={petState.colorId} selectedColorId={petState.colorId}
compatibleBodies={compatibleBodies} compatibleBodies={compatibleBodies}
couldProbablyModelMoreData={couldProbablyModelMoreData} couldProbablyModelMoreData={couldProbablyModelMoreData}
onChange={({ speciesId, colorId }) => { onChange={onChange}
const validPoses = getValidPoses(valids, speciesId, colorId);
const pose = getClosestPose(validPoses, idealPose);
setPetStateFromUserAction({
speciesId,
colorId,
pose,
isValid: true,
appearanceId: null,
});
}}
isLoading={loadingGQL || loadingValids} isLoading={loadingGQL || loadingValids}
/> />
</Box> </Box>
@ -1087,7 +1102,8 @@ function SpeciesFacesPicker({
); );
} }
function SpeciesFaceOption({ const SpeciesFaceOption = React.memo(
({
speciesId, speciesId,
speciesName, speciesName,
colorId, colorId,
@ -1098,7 +1114,7 @@ function SpeciesFaceOption({
couldProbablyModelMoreData, couldProbablyModelMoreData,
onChange, onChange,
isLoading, isLoading,
}) { }) => {
const selectedBorderColor = useColorModeValue("green.600", "green.400"); const selectedBorderColor = useColorModeValue("green.600", "green.400");
const selectedBackgroundColor = useColorModeValue("green.200", "green.600"); const selectedBackgroundColor = useColorModeValue("green.200", "green.600");
const focusBorderColor = "blue.400"; const focusBorderColor = "blue.400";
@ -1276,6 +1292,7 @@ function SpeciesFaceOption({
</ClassNames> </ClassNames>
); );
} }
);
function ItemZonesInfo({ compatibleBodiesAndTheirZones, restrictedZones }) { function ItemZonesInfo({ compatibleBodiesAndTheirZones, restrictedZones }) {
// Reorganize the body-and-zones data, into zone-and-bodies data. Also, we're // Reorganize the body-and-zones data, into zone-and-bodies data. Also, we're

View file

@ -309,7 +309,8 @@ export function useLocalStorage(key, initialValue) {
const [storedValue, setStoredValue] = React.useState(loadValue); const [storedValue, setStoredValue] = React.useState(loadValue);
const setValue = (value) => { const setValue = React.useCallback(
(value) => {
try { try {
setStoredValue(value); setStoredValue(value);
window.localStorage.setItem(key, JSON.stringify(value)); window.localStorage.setItem(key, JSON.stringify(value));
@ -317,7 +318,9 @@ export function useLocalStorage(key, initialValue) {
} catch (error) { } catch (error) {
console.error(error); console.error(error);
} }
}; },
[key]
);
const reloadValue = React.useCallback(() => { const reloadValue = React.useCallback(() => {
setStoredValue(loadValue()); setStoredValue(loadValue());