Search code examples
javascriptreactjswordpress-gutenberg

ReactJS update simple array onChange of inputs


I have the following property with social icons:

items: {
    type: 'array',
    default: [
      { icon: 'twitter', url: '#' },
      { icon: 'facebook-square', url: '#' },
      { icon: 'youtube', url: '#' },
    ],
 },

I have some controls:

<InspectorControls>
    <PanelBody title={ __( 'Social Network Settings' ) } initialOpen={ true }>

    {items.map( ( item, index ) => (

        <Fragment>

          <SelectControl
            label="Social Network"
            value={ item.icon }
            options={ [
                { label: __( 'Twitter' ), value: 'twitter' },
                { label: __( 'Facebook' ), value: 'facebook-square' },
                { label: __( 'Instagram' ), value: 'instagram' },
                { label: __( 'YouTube' ), value: 'youtube' },
            ] }
            onChange={ ( value ) => setAttributes( { items: [ ...items, { icon: value } ] } ) }
          />

          <TextControl
            label={ __( 'Social Link' ) }
            value={ item.url }
            onChange={ ( value ) => setAttributes( { items: [ ...items, { url: value } ] } ) }
           />

        </Fragment>

    ) ) }

    </PanelBody>
</InspectorControls>

And I'm rendering social icons:

{items.map( ( item, index ) => (
  <a key={ index }
     href={ item.url || '#' }
     target="_blank"
  >
    <FontAwesomeIcon icon={['fab', item.icon]} />
  </a>
) ) }

3 icons are showing. The correct icon name is showing in each select control. However when I change the icon in the select control, a new icon is added, instead of updating. The same goes when adding URLs, blank tags are being added.

How can I update the array when changing the select and text input?


Solution

  • The onChange logic above implies that a new item will be added on each update.

    Your onChangeshould find the correct element and update it accordingly. As example the onChange forSocial Network would look something similar to below. You should implement similar logic for the other onChange too.

    onChange={( value ) => {
      const newItem = {...item, icon: value };
      const newItems = [...items];
      newItems[index] = newItem;
      setAttributes({ items: newItems });
    }}