Skip to content

Commit

Permalink
Memoize useSelect for usePatterns (#54588)
Browse files Browse the repository at this point in the history
* Memoize useSelect for usePatterns

* Revert memoized selector in resolver
  • Loading branch information
kevin940726 authored and mikachan committed Sep 25, 2023
1 parent cd358e4 commit bbdcba0
Showing 1 changed file with 187 additions and 133 deletions.
320 changes: 187 additions & 133 deletions packages/edit-site/src/components/page-patterns/use-patterns.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/**
* External dependencies
*/
import createSelector from 'rememo';

/**
* WordPress dependencies
*/
Expand Down Expand Up @@ -43,108 +48,136 @@ const templatePartToPattern = ( templatePart ) => ( {
templatePart,
} );

const selectTemplatePartsAsPatterns = (
select,
{ categoryId, search = '' } = {}
) => {
const { getEntityRecords, getIsResolving } = select( coreStore );
const { __experimentalGetDefaultTemplatePartAreas } = select( editorStore );
const query = { per_page: -1 };
const rawTemplateParts =
getEntityRecords( 'postType', TEMPLATE_PART_POST_TYPE, query ) ??
EMPTY_PATTERN_LIST;
const templateParts = rawTemplateParts.map( ( templatePart ) =>
templatePartToPattern( templatePart )
);
const selectTemplatePartsAsPatterns = createSelector(
( select, categoryId, search = '' ) => {
const { getEntityRecords, getIsResolving } = select( coreStore );
const { __experimentalGetDefaultTemplatePartAreas } =
select( editorStore );
const query = { per_page: -1 };
const rawTemplateParts =
getEntityRecords( 'postType', TEMPLATE_PART_POST_TYPE, query ) ??
EMPTY_PATTERN_LIST;
const templateParts = rawTemplateParts.map( ( templatePart ) =>
templatePartToPattern( templatePart )
);

// In the case where a custom template part area has been removed we need
// the current list of areas to cross check against so orphaned template
// parts can be treated as uncategorized.
const knownAreas = __experimentalGetDefaultTemplatePartAreas() || [];
const templatePartAreas = knownAreas.map( ( area ) => area.area );
// In the case where a custom template part area has been removed we need
// the current list of areas to cross check against so orphaned template
// parts can be treated as uncategorized.
const knownAreas = __experimentalGetDefaultTemplatePartAreas() || [];
const templatePartAreas = knownAreas.map( ( area ) => area.area );

const templatePartHasCategory = ( item, category ) => {
if ( category !== TEMPLATE_PART_AREA_DEFAULT_CATEGORY ) {
return item.templatePart.area === category;
}
const templatePartHasCategory = ( item, category ) => {
if ( category !== TEMPLATE_PART_AREA_DEFAULT_CATEGORY ) {
return item.templatePart.area === category;
}

return (
item.templatePart.area === category ||
! templatePartAreas.includes( item.templatePart.area )
);
};
return (
item.templatePart.area === category ||
! templatePartAreas.includes( item.templatePart.area )
);
};

const isResolving = getIsResolving( 'getEntityRecords', [
'postType',
TEMPLATE_PART_POST_TYPE,
query,
] );

const isResolving = getIsResolving( 'getEntityRecords', [
'postType',
TEMPLATE_PART_POST_TYPE,
query,
] );
const patterns = searchItems( templateParts, search, {
categoryId,
hasCategory: templatePartHasCategory,
} );

const patterns = searchItems( templateParts, search, {
categoryId,
hasCategory: templatePartHasCategory,
} );
return { patterns, isResolving };
},
( select ) => [
select( coreStore ).getEntityRecords(
'postType',
TEMPLATE_PART_POST_TYPE,
{
per_page: -1,
}
),
select( coreStore ).getIsResolving( 'getEntityRecords', [
'postType',
TEMPLATE_PART_POST_TYPE,
{ per_page: -1 },
] ),
select( editorStore ).__experimentalGetDefaultTemplatePartAreas(),
]
);

return { patterns, isResolving };
};
const selectThemePatterns = createSelector(
( select ) => {
const { getSettings } = unlock( select( editSiteStore ) );
const settings = getSettings();
const blockPatterns =
settings.__experimentalAdditionalBlockPatterns ??
settings.__experimentalBlockPatterns;

const selectThemePatterns = ( select ) => {
const { getSettings } = unlock( select( editSiteStore ) );
const settings = getSettings();
const blockPatterns =
settings.__experimentalAdditionalBlockPatterns ??
settings.__experimentalBlockPatterns;
const restBlockPatterns = select( coreStore ).getBlockPatterns();

const restBlockPatterns = select( coreStore ).getBlockPatterns();
const patterns = [
...( blockPatterns || [] ),
...( restBlockPatterns || [] ),
]
.filter(
( pattern ) => ! PATTERN_CORE_SOURCES.includes( pattern.source )
)
.filter( filterOutDuplicatesByName )
.filter( ( pattern ) => pattern.inserter !== false )
.map( ( pattern ) => ( {
...pattern,
keywords: pattern.keywords || [],
type: PATTERN_TYPES.theme,
blocks: parse( pattern.content, {
__unstableSkipMigrationLogs: true,
} ),
} ) );

const patterns = [
...( blockPatterns || [] ),
...( restBlockPatterns || [] ),
return { patterns, isResolving: false };
},
( select ) => [
select( coreStore ).getBlockPatterns(),
unlock( select( editSiteStore ) ).getSettings(),
]
.filter(
( pattern ) => ! PATTERN_CORE_SOURCES.includes( pattern.source )
)
.filter( filterOutDuplicatesByName )
.filter( ( pattern ) => pattern.inserter !== false )
.map( ( pattern ) => ( {
...pattern,
keywords: pattern.keywords || [],
type: PATTERN_TYPES.theme,
blocks: parse( pattern.content, {
__unstableSkipMigrationLogs: true,
} ),
} ) );

return { patterns, isResolving: false };
};
const selectPatterns = (
select,
{ categoryId, search = '', syncStatus } = {}
) => {
const { patterns: themePatterns } = selectThemePatterns( select );
const { patterns: userPatterns } = selectUserPatterns( select );
);

let patterns = [ ...( themePatterns || [] ), ...( userPatterns || [] ) ];
const selectPatterns = createSelector(
( select, categoryId, syncStatus, search = '' ) => {
const { patterns: themePatterns } = selectThemePatterns( select );
const { patterns: userPatterns } = selectUserPatterns( select );

if ( syncStatus ) {
patterns = patterns.filter(
( pattern ) => pattern.syncStatus === syncStatus
);
}
let patterns = [
...( themePatterns || [] ),
...( userPatterns || [] ),
];

if ( categoryId ) {
patterns = searchItems( patterns, search, {
categoryId,
hasCategory: ( item, currentCategory ) =>
item.categories?.includes( currentCategory ),
} );
} else {
patterns = searchItems( patterns, search, {
hasCategory: ( item ) => ! item.hasOwnProperty( 'categories' ),
} );
}
return { patterns, isResolving: false };
};
if ( syncStatus ) {
patterns = patterns.filter(
( pattern ) => pattern.syncStatus === syncStatus
);
}

if ( categoryId ) {
patterns = searchItems( patterns, search, {
categoryId,
hasCategory: ( item, currentCategory ) =>
item.categories?.includes( currentCategory ),
} );
} else {
patterns = searchItems( patterns, search, {
hasCategory: ( item ) => ! item.hasOwnProperty( 'categories' ),
} );
}
return { patterns, isResolving: false };
},
( select ) => [
selectThemePatterns( select ),
selectUserPatterns( select ),
]
);

const patternBlockToPattern = ( patternBlock, categories ) => ( {
blocks: parse( patternBlock.content.raw, {
Expand All @@ -166,44 +199,65 @@ const patternBlockToPattern = ( patternBlock, categories ) => ( {
patternBlock,
} );

const selectUserPatterns = ( select, { search = '', syncStatus } = {} ) => {
const { getEntityRecords, getIsResolving, getUserPatternCategories } =
select( coreStore );
const selectUserPatterns = createSelector(
( select, syncStatus, search = '' ) => {
const { getEntityRecords, getIsResolving, getUserPatternCategories } =
select( coreStore );

const query = { per_page: -1 };
const records = getEntityRecords( 'postType', PATTERN_TYPES.user, query );
const userPatternCategories = getUserPatternCategories();
const categories = new Map();
userPatternCategories.forEach( ( userCategory ) =>
categories.set( userCategory.id, userCategory )
);
let patterns = records
? records.map( ( record ) =>
patternBlockToPattern( record, categories )
)
: EMPTY_PATTERN_LIST;

const isResolving = getIsResolving( 'getEntityRecords', [
'postType',
PATTERN_TYPES.user,
query,
] );

if ( syncStatus ) {
patterns = patterns.filter(
( pattern ) => pattern.syncStatus === syncStatus
const query = { per_page: -1 };
const records = getEntityRecords(
'postType',
PATTERN_TYPES.user,
query
);
}
const userPatternCategories = getUserPatternCategories();
const categories = new Map();
userPatternCategories.forEach( ( userCategory ) =>
categories.set( userCategory.id, userCategory )
);
let patterns = records
? records.map( ( record ) =>
patternBlockToPattern( record, categories )
)
: EMPTY_PATTERN_LIST;

patterns = searchItems( patterns, search, {
// We exit user pattern retrieval early if we aren't in the
// catch-all category for user created patterns, so it has
// to be in the category.
hasCategory: () => true,
} );
const isResolving = getIsResolving( 'getEntityRecords', [
'postType',
PATTERN_TYPES.user,
query,
] );

return { patterns, isResolving, categories: userPatternCategories };
};
if ( syncStatus ) {
patterns = patterns.filter(
( pattern ) => pattern.syncStatus === syncStatus
);
}

patterns = searchItems( patterns, search, {
// We exit user pattern retrieval early if we aren't in the
// catch-all category for user created patterns, so it has
// to be in the category.
hasCategory: () => true,
} );

return {
patterns,
isResolving,
categories: userPatternCategories,
};
},
( select ) => [
select( coreStore ).getEntityRecords( 'postType', PATTERN_TYPES.user, {
per_page: -1,
} ),
select( coreStore ).getIsResolving( 'getEntityRecords', [
'postType',
PATTERN_TYPES.user,
{ per_page: -1 },
] ),
select( coreStore ).getUserPatternCategories(),
]
);

export const usePatterns = (
categoryType,
Expand All @@ -213,20 +267,20 @@ export const usePatterns = (
return useSelect(
( select ) => {
if ( categoryType === TEMPLATE_PART_POST_TYPE ) {
return selectTemplatePartsAsPatterns( select, {
return selectTemplatePartsAsPatterns(
select,
categoryId,
search,
} );
search
);
} else if ( categoryType === PATTERN_TYPES.theme ) {
return selectPatterns( select, {
categoryId,
search,
syncStatus,
} );
return selectPatterns( select, categoryId, syncStatus, search );
} else if ( categoryType === PATTERN_TYPES.user ) {
return selectUserPatterns( select, { search, syncStatus } );
return selectUserPatterns( select, syncStatus, search );
}
return { patterns: EMPTY_PATTERN_LIST, isResolving: false };
return {
patterns: EMPTY_PATTERN_LIST,
isResolving: false,
};
},
[ categoryId, categoryType, search, syncStatus ]
);
Expand Down

0 comments on commit bbdcba0

Please sign in to comment.