Search code examples
javascriptreactjsjsxwordpress-gutenberg

I get object instead of array after setting an attribute with setAttributes in React (WordPress Block Editor). What's wrong with my code?


I'm trying to dynamically create and change values of components with mapping an array. Everything works fine initially (when I map through default values) until I get to setPadding function which is supposed to set an attribiute. Then my array is changed into object making the second mapping to throw an error - react-dom.min.js?ver=16.9.0:103 TypeError: attributes.padding.map is not a function . Here is the code:

The attribute:

padding: {
    type: 'array',
    default: [
        {   name: 'top',
            image: `${ url }images/padding-top.svg`,
            v: 10,
        },
        {
            name: 'bottom',
            image: `${ url }images/padding-bottom.svg`,
            v: 10,
        },
    ],
},

The component render (note attribiutes.padding being mapped - this works fine with default values):

<PanelBody
    title="Test"
    initialOpen={ true }
>
    { attributes.padding.map( ( attr ) => (
    <div className="component-row-wrapper margin-padding">
        <PanelRow>
            <RangeControl
                label={
                    <img src={ attr.image } alt="" />
                }
                value={ attr.v }
                onChange={ ( value ) => setPadding( attr.name, value ) }
                min={ 0 }
                max={ 300 }
            />
        </PanelRow>
    </div>
    ), ) }
</PanelBody>

And finally setPadding function (with console.log before the function itself - this is placed somewhere between edit( props ) and component render):

console.log( attributes.padding ); // initially it works fine, after setPadding it logs object instead of array.

const setPadding = ( name, value ) => {
    const paddingAttr = attributes.padding;

    {paddingAttr.map( r => {
        if ( name === r.name ) {
            r.v = value;
        }
    } );}

    console.log( paddingAttr ); // works fine, being displayed as array every time!

    props.setAttributes( {
        padding: { paddingAttr }, // saves 'padding' attribute as object 'paddingAttr: Array(2)...' instead of array ??
    } );
};

What am I doing wrong here?

Thank you very much!


Solution

  • Where you call props.setAttributes, the reason the attribute is an object is because you are creating an object! You need the following:

    props.setAttributes( {
      padding: paddingAttr
    } );
    

    Read more about property shorthand notation on MDN.


    Additionally, as I said, you'll need to fix that call to Array#map. Change it to the following:

    paddingAttr = paddingAttr.map( r => {
      if ( name === r.name ) {
        r.v = value;
      }
      return r;
    } );