re-reselect proof of concept + fix Date selector as first example
## Issue `makeSelectDataForUri` always returns a new reference, so `ClaimPreview` was constantly being rendered. It's pretty expensive since `ClaimPreview`'s rendering checks against a huge blocklist, which is another issue on it's own. ## Changes - This commit tests the usage of `re-reselect` as the solution to the multi-instance memoization problem (https://github.com/toomuchdesign/re-reselect/blob/master/examples/1-join-selectors.md)
This commit is contained in:
parent
9bbd72d179
commit
0c2c21b67e
6 changed files with 63 additions and 17 deletions
|
@ -50,7 +50,6 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@ungap/from-entries": "^0.2.1",
|
||||
"proxy-polyfill": "0.1.6",
|
||||
"auto-launch": "^5.0.5",
|
||||
"electron-dl": "^1.11.0",
|
||||
"electron-log": "^2.2.12",
|
||||
|
@ -61,6 +60,8 @@
|
|||
"if-env": "^1.0.4",
|
||||
"match-sorter": "^6.3.0",
|
||||
"parse-duration": "^1.0.0",
|
||||
"proxy-polyfill": "0.1.6",
|
||||
"re-reselect": "^4.0.0",
|
||||
"react-datetime-picker": "^3.2.1",
|
||||
"react-plastic": "^1.1.1",
|
||||
"react-top-loading-bar": "^2.0.1",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { connect } from 'react-redux';
|
||||
import {
|
||||
makeSelectClaimForUri,
|
||||
selectClaimForUri,
|
||||
makeSelectIsUriResolving,
|
||||
makeSelectClaimIsMine,
|
||||
makeSelectClaimIsPending,
|
||||
|
@ -9,7 +9,7 @@ import {
|
|||
makeSelectClaimWasPurchased,
|
||||
makeSelectClaimIsStreamPlaceholder,
|
||||
makeSelectTitleForUri,
|
||||
makeSelectDateForUri,
|
||||
selectDateForUri,
|
||||
} from 'redux/selectors/claims';
|
||||
import { makeSelectStreamingUrlForUri } from 'redux/selectors/file_info';
|
||||
import {
|
||||
|
@ -32,14 +32,14 @@ import ClaimPreview from './view';
|
|||
import formatMediaDuration from 'util/formatMediaDuration';
|
||||
|
||||
const select = (state, props) => {
|
||||
const claim = props.uri && makeSelectClaimForUri(props.uri)(state);
|
||||
const claim = props.uri && selectClaimForUri(state, props.uri);
|
||||
const media = claim && claim.value && (claim.value.video || claim.value.audio);
|
||||
const mediaDuration = media && media.duration && formatMediaDuration(media.duration, { screenReader: true });
|
||||
|
||||
return {
|
||||
claim,
|
||||
mediaDuration,
|
||||
date: props.uri && makeSelectDateForUri(props.uri)(state),
|
||||
date: props.uri && selectDateForUri(state, props.uri),
|
||||
title: props.uri && makeSelectTitleForUri(props.uri)(state),
|
||||
pending: props.uri && makeSelectClaimIsPending(props.uri)(state),
|
||||
reflectingProgress: props.uri && makeSelectReflectingClaimForUri(props.uri)(state),
|
||||
|
@ -47,7 +47,6 @@ const select = (state, props) => {
|
|||
claimIsMine: props.uri && makeSelectClaimIsMine(props.uri)(state),
|
||||
isResolvingUri: props.uri && makeSelectIsUriResolving(props.uri)(state),
|
||||
isResolvingRepost: props.uri && makeSelectIsUriResolving(props.repostUrl)(state),
|
||||
repostClaim: props.uri && makeSelectClaimForUri(props.uri)(state),
|
||||
nsfw: props.uri && makeSelectClaimIsNsfw(props.uri)(state),
|
||||
blackListedOutpoints: selectBlackListedOutpoints(state),
|
||||
filteredOutpoints: selectFilteredOutpoints(state),
|
||||
|
|
|
@ -7,7 +7,7 @@ import {
|
|||
makeSelectChannelForClaimUri,
|
||||
makeSelectClaimIsNsfw,
|
||||
makeSelectClaimIsStreamPlaceholder,
|
||||
makeSelectDateForUri,
|
||||
selectDateForUri,
|
||||
} from 'redux/selectors/claims';
|
||||
import { doFileGet } from 'redux/actions/file';
|
||||
import { doResolveUri } from 'redux/actions/claims';
|
||||
|
@ -26,7 +26,7 @@ const select = (state, props) => {
|
|||
return {
|
||||
claim,
|
||||
mediaDuration,
|
||||
date: props.uri && makeSelectDateForUri(props.uri)(state),
|
||||
date: props.uri && selectDateForUri(state, props.uri),
|
||||
channel: props.uri && makeSelectChannelForClaimUri(props.uri)(state),
|
||||
isResolvingUri: props.uri && makeSelectIsUriResolving(props.uri)(state),
|
||||
thumbnail: props.uri && makeSelectThumbnailForUri(props.uri)(state),
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { makeSelectDateForUri } from 'redux/selectors/claims';
|
||||
import { selectDateForUri } from 'redux/selectors/claims';
|
||||
import * as SETTINGS from 'constants/settings';
|
||||
import { makeSelectClientSetting } from 'redux/selectors/settings';
|
||||
import DateTime from './view';
|
||||
|
||||
const select = (state, props) => ({
|
||||
date: props.date || makeSelectDateForUri(props.uri)(state),
|
||||
date: props.date || selectDateForUri(state, props.uri),
|
||||
clock24h: makeSelectClientSetting(SETTINGS.CLOCK_24H)(state),
|
||||
});
|
||||
export default connect(select)(DateTime);
|
||||
|
|
|
@ -2,20 +2,22 @@
|
|||
import { normalizeURI, parseURI, isURIValid } from 'util/lbryURI';
|
||||
import { selectSupportsByOutpoint } from 'redux/selectors/wallet';
|
||||
import { createSelector } from 'reselect';
|
||||
import { createCachedSelector } from 're-reselect';
|
||||
import { isClaimNsfw, filterClaims } from 'util/claim';
|
||||
import * as CLAIM from 'constants/claim';
|
||||
|
||||
type State = { claims: any };
|
||||
|
||||
const selectState = (state) => state.claims || {};
|
||||
|
||||
export const selectById = createSelector(selectState, (state) => state.byId || {});
|
||||
|
||||
export const selectPendingClaimsById = createSelector(selectState, (state) => state.pendingById || {});
|
||||
export const selectById = (state: State) => selectState(state).byId || {};
|
||||
export const selectPendingClaimsById = (state: State) => selectState(state).pendingById || {};
|
||||
|
||||
export const selectClaimsById = createSelector(selectById, selectPendingClaimsById, (byId, pendingById) => {
|
||||
return Object.assign(byId, pendingById); // do I need merged to keep metadata?
|
||||
});
|
||||
|
||||
export const selectClaimIdsByUri = createSelector(selectState, (state) => state.claimsByUri || {});
|
||||
export const selectClaimIdsByUri = (state: State) => selectState(state).claimsByUri || {};
|
||||
|
||||
export const selectCurrentChannelPage = createSelector(selectState, (state) => state.currentChannelPage || 1);
|
||||
|
||||
|
@ -74,6 +76,43 @@ export const selectReflectingById = createSelector(selectState, (state) => state
|
|||
|
||||
export const makeSelectClaimForClaimId = (claimId: string) => createSelector(selectClaimsById, (byId) => byId[claimId]);
|
||||
|
||||
export const selectClaimForUri = createCachedSelector(
|
||||
selectClaimIdsByUri,
|
||||
selectClaimsById,
|
||||
(state, uri) => uri,
|
||||
(state, uri, returnRepost = true) => returnRepost,
|
||||
(byUri, byId, uri, returnRepost) => {
|
||||
const validUri = isURIValid(uri);
|
||||
|
||||
if (validUri && byUri) {
|
||||
const claimId = uri && byUri[normalizeURI(uri)];
|
||||
const claim = byId[claimId];
|
||||
|
||||
// Make sure to return the claim as is so apps can check if it's been resolved before (null) or still needs to be resolved (undefined)
|
||||
if (claimId === null) {
|
||||
return null;
|
||||
} else if (claimId === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const repostedClaim = claim && claim.reposted_claim;
|
||||
if (repostedClaim && returnRepost) {
|
||||
const channelUrl =
|
||||
claim.signing_channel && (claim.signing_channel.canonical_url || claim.signing_channel.permanent_url);
|
||||
|
||||
return {
|
||||
...repostedClaim,
|
||||
repost_url: normalizeURI(uri),
|
||||
repost_channel_url: channelUrl,
|
||||
repost_bid_amount: claim && claim.meta && claim.meta.effective_amount,
|
||||
};
|
||||
} else {
|
||||
return claim;
|
||||
}
|
||||
}
|
||||
}
|
||||
)((state, uri, returnRepost = true) => `${uri}:${returnRepost ? '1' : '0'}`);
|
||||
|
||||
export const makeSelectClaimForUri = (uri: string, returnRepost: boolean = true) =>
|
||||
createSelector(selectClaimIdsByUri, selectClaimsById, (byUri, byId) => {
|
||||
const validUri = isURIValid(uri);
|
||||
|
@ -245,8 +284,9 @@ export const makeSelectMetadataItemForUri = (uri: string, key: string) =>
|
|||
export const makeSelectTitleForUri = (uri: string) =>
|
||||
createSelector(makeSelectMetadataForUri(uri), (metadata) => metadata && metadata.title);
|
||||
|
||||
export const makeSelectDateForUri = (uri: string) =>
|
||||
createSelector(makeSelectClaimForUri(uri), (claim) => {
|
||||
export const selectDateForUri = createCachedSelector(
|
||||
selectClaimForUri, // input: (state, uri, ?returnRepost)
|
||||
(claim) => {
|
||||
const timestamp =
|
||||
claim &&
|
||||
claim.value &&
|
||||
|
@ -260,7 +300,8 @@ export const makeSelectDateForUri = (uri: string) =>
|
|||
}
|
||||
const dateObj = new Date(timestamp);
|
||||
return dateObj;
|
||||
});
|
||||
}
|
||||
)((state, uri) => uri);
|
||||
|
||||
export const makeSelectAmountForUri = (uri: string) =>
|
||||
createSelector(makeSelectClaimForUri(uri), (claim) => {
|
||||
|
|
|
@ -13317,6 +13317,11 @@ rc@^1.0.1, rc@^1.1.6, rc@^1.2.8:
|
|||
minimist "^1.2.0"
|
||||
strip-json-comments "~2.0.1"
|
||||
|
||||
re-reselect@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/re-reselect/-/re-reselect-4.0.0.tgz#9ddec4c72c4d952f68caa5aa4b76a9ed38b75cac"
|
||||
integrity sha512-wuygyq8TXUlSdVXv2kigXxQNOgdb9m7LbIjwfTNGSpaY1riLd5e+VeQjlQMyUtrk0oiyhi1AqIVynworl3qxHA==
|
||||
|
||||
react-async-script@^1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/react-async-script/-/react-async-script-1.1.1.tgz#f481c6c5f094bf4b94a9d52da0d0dda2e1a74bdf"
|
||||
|
|
Loading…
Reference in a new issue