0

I have a block that references a custom post type named faq that has a taxonomy named faq_group. This block has one attribute and makes multiple getEntityRecords calls. One of the calls has an argument that depends on the previous one:

The attribute:

// the group attribute stores the slug of the selected faq_group slug from a SelectControl component
attributes: {
    group: {
        type: 'string',
        default: '',
    },
}

The calls:

// Get all terms from the faq_group taxonomy to fill a SelectControl component (name and slug)
const groups = useSelect( ( select ) =>
    select( 'core' ).getEntityRecords( 'taxonomy', 'faq_group', { per_page: -1, orderby: 'name', order: 'asc', _fields: 'id,name,slug' } ),
    []
);

// Get the term object with the same slug as the group attribute
const selectedGroup = useSelect( ( select ) =>
    select( 'core' ).getEntityRecords( 'taxonomy', 'faq_group', { per_page: -1, orderby: 'name', order: 'asc', _fields: 'id,name,slug' } )?.find( ( term ) => term.slug === attributes.group ),
    [ attributes.group ]
);

// Get posts from the faq custom post type with a faq_group term with id = selectedGroup.id
const faqs = useSelect( ( select ) =>
    select( 'core' ).getEntityRecords( 'postType', 'faq', { faq_group: [ selectedGroup?.id ] } ),
    [ selectedGroup?.id ]
);

My question is, can this be simplified somehow? Can the multiple calls be combined inside just one useSelect selector?

1 Answer 1

2

Can the multiple calls be combined inside just one useSelect selector?

Yes, and here's an example where my useSelect() returns an object that I unpack using the destructuring assignment (e.g. const { a, b } = myFunc() where myFunc() returns { a: 'foo', b: 123 }):

const { groups, selectedGroup, faqs } = useSelect( ( select ) => {
    const { getEntityRecords } = select( 'core' );

    // The args are identical for both "groups" and selectedGroup, so I put them in a constant.
    const groupsArgs = { per_page: -1, orderby: 'name', order: 'asc', _fields: 'id,name,slug' };

    const selectedGroup = getEntityRecords( 'taxonomy', 'faq_group', groupsArgs )?.find(
        ( term ) => term.slug === attributes.group
    );

    return {
        groups: getEntityRecords( 'taxonomy', 'faq_group', groupsArgs ),
        faqs: getEntityRecords( 'postType', 'faq', { faq_group: [ selectedGroup?.id ] } ),
        selectedGroup,
    };
}, [ attributes.group ] );

If you do not actually need to access the selectedGroup from outside the useSelect() callback, then you can omit selectedGroup from the list, i.e. use just const { groups, faqs } = useSelect( ... ), and then remove the selectedGroup, (the third line) from the return value.

And actually, instead of calling getEntityRecords() twice with the same args, you could call it just once:

const { groups, selectedGroup, faqs } = useSelect( ( select ) => {
    const { getEntityRecords } = select( 'core' );

    const groupsArgs = { per_page: -1, orderby: 'name', order: 'asc', _fields: 'id,name,slug' };
    const groups = getEntityRecords( 'taxonomy', 'faq_group', groupsArgs );

    const selectedGroup = groups?.find( ( term ) => term.slug === attributes.group );

    return {
        groups,
        selectedGroup,
        faqs: getEntityRecords( 'postType', 'faq', { faq_group: [ selectedGroup?.id ] } ),
    };
}, [ attributes.group ] );

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.