From c8e77ea5f58932962a0a947fd2ba11eada12a9dc Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Sat, 22 Dec 2018 10:29:17 -0800 Subject: [PATCH] Use reselect --- package.json | 1 + src/redux/selectors.js | 83 +++++++++++++++++++++++++----------------- yarn.lock | 4 ++ 3 files changed, 54 insertions(+), 34 deletions(-) diff --git a/package.json b/package.json index 84b62e52..3ba3748d 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "react-scripts": "2.0.3", "redux": "^4.0.1", "redux-observable": "^1.0.0", + "reselect": "^4.0.0", "rxjs": "^6.3.3", "shell-escape": "^0.2.0", "webamp": "^1.3.0-beta.1" diff --git a/src/redux/selectors.js b/src/redux/selectors.js index 6091594d..c622b427 100644 --- a/src/redux/selectors.js +++ b/src/redux/selectors.js @@ -1,3 +1,4 @@ +import { createSelector } from "reselect"; import * as Utils from "../utils"; import { ABOUT_PAGE } from "../constants"; @@ -13,25 +14,39 @@ export function overlayShouldAnimate(state) { return getSelectedSkinPosition(state) != null; } -export function getSelectedSkinUrl(state) { - const hash = getSelectedSkinHash(state); - return hash == null ? null : Utils.screenshotUrlFromHash(hash); -} +export const getSelectedSkinUrl = createSelector( + getSelectedSkinHash, + hash => { + return hash == null ? null : Utils.screenshotUrlFromHash(hash); + } +); export function getSearchQuery(state) { return state.searchQuery; } -// TODO: Memoize this very expensive function -export function getMatchingSkinHashes(state) { - const skinHashes = getSkinHashes(state); - const searchQuery = getSearchQuery(state); - if (searchQuery == null || state.matchingHashes == null) { - return skinHashes; - } - return skinHashes.filter(hash => state.matchingHashes.has(hash)); +export function getMatchingHashes(state) { + return state.matchingHashes; } +export const getSkinHashes = createSelector( + getSkins, + skins => Object.keys(skins) +); + +export const getMatchingSkinHashes = createSelector( + getSkinHashes, + getSearchQuery, + getMatchingHashes, + (skinHashes, searchQuery, matchingHashes) => { + if (searchQuery == null || matchingHashes == null) { + return skinHashes; + } + return skinHashes.filter(hash => matchingHashes.has(hash)); + } +); + +// We should be careful _not_ to memoize this function since it's non determinisitc export function getRandomSkinHash(state) { const skinHashes = getSkinHashes(state); const numberOfSkins = skinHashes.length; @@ -39,39 +54,39 @@ export function getRandomSkinHash(state) { return skinHashes[randomIndex]; } -export function getUrl(state) { - if (state.activeContentPage === ABOUT_PAGE) { - return "/about/"; +export const getUrl = createSelector( + getActiveContentPage, + getSelectedSkinHash, + getSearchQuery, + (activeContentPage, hash, query) => { + if (activeContentPage === ABOUT_PAGE) { + return "/about/"; + } + if (hash) { + // TODO: Add a human readable version + return Utils.getPermalinkUrlFromHash(hash); + } else if (query) { + return `/?query=${encodeURIComponent(query)}`; + } + return "/"; } - const hash = getSelectedSkinHash(state); - const query = getSearchQuery(state); - if (hash) { - // TODO: Add a human readable version - return Utils.getPermalinkUrlFromHash(hash); - } else if (query) { - return `/?query=${encodeURIComponent(query)}`; - } - return "/"; -} +); export function getPageTitle(state) { return "Winamp Skin Museum"; } -export function getPreviewImageUrl(state) { - const hash = getSelectedSkinHash(state); - return hash == null ? null : Utils.screenshotUrlFromHash(hash); -} +export const getPreviewImageUrl = createSelector( + getSelectedSkinHash, + hash => { + return hash == null ? null : Utils.screenshotUrlFromHash(hash); + } +); export function getActiveContentPage(state) { return state.activeContentPage; } -// TODO: This could be memoized -export function getSkinHashes(state) { - return Object.keys(getSkins(state)); -} - export function getSkins(state) { return state.skins; } diff --git a/yarn.lock b/yarn.lock index 94980f04..03196167 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7544,6 +7544,10 @@ requires-port@1.0.x, requires-port@1.x.x, requires-port@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" +reselect@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.0.0.tgz#f2529830e5d3d0e021408b246a206ef4ea4437f7" + resolve-cwd@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a"