From 9f9a37352e6a2103cd5110ea2f2fbeae526b4fac Mon Sep 17 00:00:00 2001 From: Andrew Smith Date: Sun, 18 Aug 2024 15:07:32 -0400 Subject: [PATCH] =?UTF-8?q?perf(ui):=20=E2=9A=A1=EF=B8=8F=20load=20games?= =?UTF-8?q?=20without=20hitting=20API=20upon=20page=20load?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After the first render, the graph API was being requested for game data. This was not intended and is unnecessary as the library's data is already available in the Apollo client's local cache. ✅ Relates to: #493 --- .../src/api/client/state/librarySlice.ts | 69 ++++++++----------- apps/playnite-web/src/routes/_index.tsx | 2 +- apps/playnite-web/src/routes/browse.tsx | 42 +++-------- 3 files changed, 38 insertions(+), 75 deletions(-) diff --git a/apps/playnite-web/src/api/client/state/librarySlice.ts b/apps/playnite-web/src/api/client/state/librarySlice.ts index c0df5b1ec..655b18062 100755 --- a/apps/playnite-web/src/api/client/state/librarySlice.ts +++ b/apps/playnite-web/src/api/client/state/librarySlice.ts @@ -1,10 +1,7 @@ import { createSelector, createSlice } from '@reduxjs/toolkit' import _ from 'lodash' -import And from '../../../domain/filters/And' -import NoFilter from '../../../domain/filters/NoFilter' -import MatchFeature from '../../../domain/filters/playnite/MatchFeature' -const { keyBy, memoize, merge } = _ +const { keyBy, merge } = _ const initialState: { activeNameFilters: string | null @@ -20,18 +17,6 @@ const initialState: { platformFilterValues: {}, } -const noFilter = new NoFilter() - -const getNameFilter = memoize((state: typeof initialState) => - !state.activeNameFilters ? {} : { name: state.activeNameFilters }, -) - -const getFeatureFilter = memoize((state: typeof initialState) => { - return state.activeFeatureFilters.length === 0 - ? noFilter - : new And(...state.activeFeatureFilters.map((id) => new MatchFeature(id))) -}) - const alphabeticalOrder = (a: { name: string }, b: { name: string }) => { return a.name.localeCompare(b.name) } @@ -40,30 +25,33 @@ const slice = createSlice({ name: 'library', initialState, selectors: { - getFilter: createSelector( - [getNameFilter, getFeatureFilter], - (nameFilter, featureFilter) => merge({}, nameFilter), + getFilterValues: createSelector( + (state) => state, + (state) => ({ + nameFilter: state.activeNameFilters ?? '', + featureFilter: + state.activeFeatureFilters.map( + (id) => state.featureFilterValues[id], + ) ?? [], + platformFilter: + state.activePlatformFilters.map( + (id) => state.platformFilterValues[id], + ) ?? [], + }), + ), + getAllPossibleFilterValues: createSelector( + (state) => state, + (state) => { + return Object.entries(state).reduce((acc, [key, value]) => { + if (key.endsWith('FilterValues')) { + acc[key.replace('FilterValues', '')] = Object.values( + value as Record, + ).sort(alphabeticalOrder) + } + return acc + }, {}) + }, ), - getFilterValues: (state) => ({ - nameFilter: state.activeNameFilters ?? '', - featureFilter: - state.activeFeatureFilters.map((id) => state.featureFilterValues[id]) ?? - [], - platformFilter: - state.activePlatformFilters.map( - (id) => state.platformFilterValues[id], - ) ?? [], - }), - getAllPossibleFilterValues: (state) => { - return Object.entries(state).reduce((acc, [key, value]) => { - if (key.endsWith('FilterValues')) { - acc[key.replace('FilterValues', '')] = Object.values( - value as Record, - ).sort(alphabeticalOrder) - } - return acc - }, {}) - }, }, reducers: { setFilterTypeValues(state, action) { @@ -91,5 +79,4 @@ const slice = createSlice({ export const { reducer } = slice export const { setFilterTypeValues, setSelectedFilter, activateFilters } = slice.actions -export const { getAllPossibleFilterValues, getFilter, getFilterValues } = - slice.selectors +export const { getAllPossibleFilterValues, getFilterValues } = slice.selectors diff --git a/apps/playnite-web/src/routes/_index.tsx b/apps/playnite-web/src/routes/_index.tsx index 9e8c4d81b..791c96315 100755 --- a/apps/playnite-web/src/routes/_index.tsx +++ b/apps/playnite-web/src/routes/_index.tsx @@ -19,7 +19,7 @@ function Index() { setGame(game) setRightDrawerOpen(true) }, []) - const { data, loading, refetch, error } = usePlaylists() + const { data, loading, error } = usePlaylists() const playlists = data?.playlists return ( diff --git a/apps/playnite-web/src/routes/browse.tsx b/apps/playnite-web/src/routes/browse.tsx index 99bd32d30..b9f555e5f 100755 --- a/apps/playnite-web/src/routes/browse.tsx +++ b/apps/playnite-web/src/routes/browse.tsx @@ -4,19 +4,11 @@ import { FilterAlt } from '@mui/icons-material' import { Button, styled } from '@mui/material' import type { LoaderFunctionArgs } from '@remix-run/node' import { json } from '@remix-run/node' -import { - Outlet, - useLoaderData, - useLocation, - useNavigate, -} from '@remix-run/react' -import { useCallback, useEffect, useState } from 'react' -import { useDispatch, useSelector } from 'react-redux' +import { Outlet, useLocation, useNavigate } from '@remix-run/react' +import { useCallback, useState } from 'react' +import { useSelector } from 'react-redux' import { Game } from '../../.generated/types.generated' -import { - getFilter, - setFilterTypeValues, -} from '../api/client/state/librarySlice' +import { getFilterValues } from '../api/client/state/librarySlice' import getGameApi from '../api/game/index.server' import Filters from '../components/Filters' import IconButton from '../components/IconButton' @@ -66,32 +58,16 @@ const All_Games_Query = gql` } ` function Browse() { - const { filterValues } = (useLoaderData() || {}) as unknown as { - filterValues: - | { - feature: { id: string; name: string }[] - } - | undefined - } - - const filter = useSelector(getFilter) - const { loading, data, error, refetch } = useQuery(All_Games_Query) - useEffect(() => { - refetch({ filter }) - }, [filter]) + const { nameFilter } = useSelector(getFilterValues) + const { loading, data, error } = useQuery(All_Games_Query, { + variables: { filter: { name: nameFilter } }, + }) - const games = !loading ? data?.games : [] + const games = !loading ? (data?.games ?? []) : [] if (error) { console.error(error, data) } - const dispatch = useDispatch() - useEffect(() => { - Object.entries(filterValues ?? {}).forEach(([key, value]) => { - dispatch(setFilterTypeValues({ filterTypeName: key, values: value })) - }) - }, [filterValues]) - const [trigger] = useNavigateInGrid() const handleScrollTop = (evt) => { trigger(0, 0)