next-drupal icon indicating copy to clipboard operation
next-drupal copied to clipboard

getResource() in a nested for loop and props not updated with fetched data

Open ansdb opened this issue 3 years ago • 7 comments

Hi

Please I have this issue when fetching Layout Builder, I have the following code.

export default function LB(props){

    const LB: Array<any> = props.LBPage.layout_builder__layout;

    /*const pageStructure = {
        sectionsNum: LB.length,
        sectionsSetting: [],
        contentTypes: [],
    };

    // Add each section setting to the pageStructure

    LB.forEach(section => {
        const sectionSetting = {
            columns: null,
            column_widths: section.section.layout_settings.column_widths,
            context_mapping: section.section.layout_settings.context_mapping,
            label: section.section.layout_settings.label,
        };

        sectionSetting.columns = sectionSetting.column_widths ? sectionSetting.column_widths.split('-').length : null;

        pageStructure.sectionsSetting.push(sectionSetting);
    });*/

    console.log(LB, props.resource, props.resource[1], props);

    return (
        <Fragment>
            {
                LB.map(section => {
                    console.log(props.resource);
                    return <section className={
                                section.section.layout_settings.column_widths
                                    ?
                                section.section.layout_settings.column_widths.split('-').length + '-col' + ' ' + 'col-' +section.section.layout_settings.column_widths
                                    :
                                '1-col'
                                }
                            >
                            </section>;
                })
            }
        </Fragment>
    );
}
export async function getStaticProps(){

    let resource = [];
    let resources = [];

    const  LBPage = await getResource('node--page', '6acb560b-f999-4011-9bab-160856d21f9f')

    LBPage.layout_builder__layout.forEach((section, i) => {

        resource.push({section: []});

        //console.log('sections: ', section.section.components)

        // console.log('section.section.components: ', section.section.components, section.section);

        section.section.components.forEach(async (comp, j) => {
            //console.log('resource[i]: ', i, j);
            //console.log('component: ', comp.provider);
            //console.log('params: ', comp.configuration.provider + "--basic", comp.configuration.id, comp.configuration.id.replace(comp.configuration.provider + ':', ''));

            if(comp.configuration.provider === 'block_content'){
                const nodeType = comp.configuration.provider + "--basic";
                const nodeUid = comp.configuration.id.replace(comp.configuration.provider + ':', '');

                resources.push('response');
                const blocks = await getResource(nodeType, nodeUid);
                console.log(i, 'Response: ', resource[i].section, blocks);
                //resource[i].section.push(blocks);
                setTimeout(() => {
                    resource[i].section.push(blocks);
                }, 15000);
                resource[i].section.push('blocks');
                resources.push(blocks);
            }
        });

    });

    return {
        props: {
            LBPage,
            resource,
            resources,
        },
    };
}

LBPage fetched normally but resource has empty arrays here is it hen logged on the devtool

resource: [
    {
        "section": []
    },
    {
        "section": []
    },
    {
        "section": []
    },
    {
        "section": []
    }
]

every section there should has it's own blocks inside the array, by the way, the blocks fetched has been logged on the server nodejs but not passed to props

resources is just to know whether the block inside the if condition work or not

Thanks in advance.

ansdb avatar Jun 22 '22 12:06 ansdb

Hello, each interation call in:

section.section.components.forEach(async (comp, j) => {...}

returns a Promise that is not resolved, try to wrap this loop with "await Promise.all(...)".

soft4net avatar Jun 22 '22 12:06 soft4net

Hello, each interation call in:

section.section.components.forEach(async (comp, j) => {...}

returns a Promise that is not resolved, try to wrap this loop with "await Promise.all(...)".

Hi

Thanks for your reply

I did what you say but it doesn't work, it's really weird image

ansdb avatar Jun 22 '22 14:06 ansdb

"async" returned from forEach returns an unresolved Promise, that receives data back after execution getStaticProps function body. await Promise.all(section.section.components.forEach(async (comp, j) => {...});

Anyway do you need to call const blocks = await getResource(nodeType, nodeUid); inside loop? This is not a good practise, because you spin every request for each iteration. Can't you get those data before loop, and avoid await/async within loop?

soft4net avatar Jun 22 '22 14:06 soft4net

@ansdb which module are you using for layout builder and JSON:API?

shadcn avatar Jun 22 '22 16:06 shadcn

You're probably using the layout builder patch.

@soft4net is right. You should wrap the top forEach in a Promise.all.

await Promise.all(LBPage.layout_builder__layout.forEach())

You could also use a for ... of ...

const  page = await getResource('node--page', '6acb560b-f999-4011-9bab-160856d21f9f')

for (const section of page.layout_builder__layout) {
  for (const component of section.components) {
    // .....
    // Do your getResource call here.
    const blocks = await getResource(nodeType, nodeUid);
   // ....
  }
}

shadcn avatar Jun 22 '22 16:06 shadcn

Hi

@shadcn Yes I use that layout builder patch

Okay thanks a lot, I will test what you say and come back to you with the result

Thanks a lot for both of you.

ansdb avatar Jun 22 '22 19:06 ansdb

Hi @shadcn

Thanks a lot I've got the block using for loop .

I've tried Promise.all it has to work but maybe I did a mistake, anyway.

Please I have a question why I'm not able to push blocks fetched using the first approach with .forEach method and i can push using the for loop?

Thanks a lot.

ansdb avatar Jul 04 '22 18:07 ansdb