From b4665d07f29e517e0a81d99d907bea889e64ecbb Mon Sep 17 00:00:00 2001 From: Justin Wyne <1986068+wyne@users.noreply.github.com> Date: Sun, 5 May 2024 21:19:30 -0700 Subject: [PATCH] Correct playerColor selectors to prevent unnecessary renders --- redux/GamesSlice.ts | 28 +++++++++++++------- src/components/Boards/FlexboxTile.tsx | 8 +++--- src/components/PlayerListItem.tsx | 5 ++-- src/components/ScoreLog/PlayerNameColumn.tsx | 6 +++-- 4 files changed, 30 insertions(+), 17 deletions(-) diff --git a/redux/GamesSlice.ts b/redux/GamesSlice.ts index f59096b4..dc902159 100644 --- a/redux/GamesSlice.ts +++ b/redux/GamesSlice.ts @@ -270,20 +270,27 @@ export const selectSortSelectorKey = (state: RootState, gameId: string) => { return key !== undefined ? key : SortSelectorKey.ByScore; }; -export const selectPlayerColors = createSelector( +export const makeSelectPlayerColors = () => createSelector( [ - (state: RootState, playerId: string) => { - const gameId = selectAllGames(state).filter((game) => game.playerIds.includes(playerId))[0].id; - const paletteName = state.games.entities[gameId]?.palette; + (state: RootState, gameId: string | undefined): GameState | undefined => { + if (!gameId) { + return undefined; + } + return state.games.entities[gameId]; + }, + (state: RootState, gameId: string | undefined, playerId: string): string => playerId, + (state: RootState, gameId: string | undefined, playerId: string): string | undefined => state.players.entities[playerId]?.color, + ], + (game, playerId, playerColor) => { + if (!game || !playerId) { + return ['#000000', '#FFFFFF']; + } - const playerColor = state.players.entities[playerId]?.color; + const paletteName = game.palette; + const playerIds = game.playerIds; - const playerIndex = state.games.entities[gameId]?.playerIds.indexOf(playerId) || 0; + const playerIndex = playerIds.indexOf(playerId); - return { paletteName, playerColor, playerIndex }; - }, - ], - ({ paletteName, playerColor, playerIndex }) => { const palette = getPalette(paletteName || 'original') || getPalette('original'); const paletteBG = palette[playerIndex % palette.length]; @@ -299,6 +306,7 @@ export const selectPlayerColors = createSelector( } ); + export const { updateGame, roundNext, diff --git a/src/components/Boards/FlexboxTile.tsx b/src/components/Boards/FlexboxTile.tsx index 54fc9d03..fe14be57 100644 --- a/src/components/Boards/FlexboxTile.tsx +++ b/src/components/Boards/FlexboxTile.tsx @@ -3,9 +3,9 @@ import React from 'react'; import { DimensionValue, StyleSheet } from 'react-native'; import Animated, { Easing, FadeIn } from 'react-native-reanimated'; -import { selectPlayerColors } from '../../../redux/GamesSlice'; +import { makeSelectPlayerColors } from '../../../redux/GamesSlice'; import { useAppSelector } from '../../../redux/hooks'; -import { selectInteractionType } from '../../../redux/selectors'; +import { selectCurrentGame, selectInteractionType } from '../../../redux/selectors'; import { interactionComponents } from '../Interactions/InteractionComponents'; import { InteractionType } from '../Interactions/InteractionType'; import AdditionTile from '../PlayerTiles/AdditionTile/AdditionTile'; @@ -32,8 +32,10 @@ const FlexboxTile: React.FunctionComponent = React.memo(({ if (!(width > 0 && height > 0)) return null; if (Number.isNaN(width) || Number.isNaN(height)) return null; + const currentGameId = useAppSelector(state => selectCurrentGame(state)?.id); const playerIndexLabel = useAppSelector(state => state.settings.showPlayerIndex); - const playerColors = useAppSelector(state => selectPlayerColors(state, playerId)); + const selectPlayerColors = makeSelectPlayerColors(); + const playerColors = useAppSelector(state => selectPlayerColors(state, currentGameId, playerId)); const [bg, fg] = playerColors; const widthPerc: DimensionValue = `${(100 / cols)}%`; diff --git a/src/components/PlayerListItem.tsx b/src/components/PlayerListItem.tsx index 581ca685..931fab8e 100644 --- a/src/components/PlayerListItem.tsx +++ b/src/components/PlayerListItem.tsx @@ -6,7 +6,7 @@ import { NativeStackNavigationProp } from '@react-navigation/native-stack'; import { Alert, StyleSheet, Text, TouchableOpacity, View } from 'react-native'; import { Icon, ListItem } from 'react-native-elements'; -import { selectGameById, selectPlayerColors, updateGame } from '../../redux/GamesSlice'; +import { makeSelectPlayerColors, selectGameById, updateGame } from '../../redux/GamesSlice'; import { useAppDispatch, useAppSelector } from '../../redux/hooks'; import { removePlayer, selectPlayerById } from '../../redux/PlayersSlice'; import { selectCurrentGame } from '../../redux/selectors'; @@ -31,7 +31,8 @@ const PlayerListItem: React.FunctionComponent = ({ const currentGameId = useAppSelector(state => selectCurrentGame(state)?.id); const playerIds = useAppSelector(state => selectGameById(state, currentGameId || '')?.playerIds); const player = useAppSelector(state => selectPlayerById(state, playerId)); - const playerColors = useAppSelector(state => selectPlayerColors(state, playerId)); + const selectPlayerColors = makeSelectPlayerColors(); + const playerColors = useAppSelector(state => selectPlayerColors(state, currentGameId, playerId)); if (currentGameId == '' || currentGameId === undefined) return null; if (playerIds === undefined) return null; diff --git a/src/components/ScoreLog/PlayerNameColumn.tsx b/src/components/ScoreLog/PlayerNameColumn.tsx index a71bcd3c..e6785d06 100644 --- a/src/components/ScoreLog/PlayerNameColumn.tsx +++ b/src/components/ScoreLog/PlayerNameColumn.tsx @@ -3,7 +3,7 @@ import React from 'react'; import { StyleSheet, Text, View } from 'react-native'; import { Icon } from 'react-native-elements/dist/icons/Icon'; -import { selectPlayerColors } from '../../../redux/GamesSlice'; +import { makeSelectPlayerColors } from '../../../redux/GamesSlice'; import { useAppSelector } from '../../../redux/hooks'; import { selectPlayerById } from '../../../redux/PlayersSlice'; import { selectCurrentGame } from '../../../redux/selectors'; @@ -17,7 +17,9 @@ interface CellProps { } const PlayerNameCell: React.FunctionComponent = ({ index, playerId }) => { - const playerColors = useAppSelector(state => selectPlayerColors(state, playerId)); + const selectPlayerColors = makeSelectPlayerColors(); + const currentGameId = useAppSelector(state => selectCurrentGame(state)?.id); + const playerColors = useAppSelector(state => selectPlayerColors(state, currentGameId, playerId)); const playerName = useAppSelector(state => selectPlayerById(state, playerId)?.playerName); return (