Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Memoize useSelect for usePatterns #54588

Merged
merged 2 commits into from
Sep 22, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading