fetch call render update lit webcomponent

I tried below to make fetch call and render data , I can see fetch call happening and data coming back in network tab , but never see dom updated.

import { html, unsafeCSS, nothing, css } from 'lit';
import { customElement, property, state } from 'lit/decorators.js';
import { AllEtfs } from './queries/all-etfs.js';
import { DsIvsApiBaseComponent } from '../ds-base/ds-base.api.js';
/**
 * @tag ds-etf-listing-table
 *
 */
@customElement('ds-etf-listing-table')
export class DsEtfListingTable extends DsIvsApiBaseComponent {
  static get styles() {
    return css`
          :host {
            display: inline-flex;
            align-items: center;
            background: blue;
          }
        `;
  }

  /**
   * @internal
   */
  query = AllEtfs.ALL_ETFS_QUERY;


  constructor() {
    super();
  }

  protected processResponse(_response): void {
    this.componentObject = _response.data;
    this.requestUpdate();
  }

  renderDataGrid() {
   if (this.componentObject?.allExchangeTradedFunds) {
      const allETFs = this.componentObject.allExchangeTradedFunds;
      return html`
        ${allETFs.forEach((etf) =>
          html`
            <div class="etf-listing">
              <div class="etf-listing__ticker">${etf.ticker}</div>
            </div>
          `,
        )}
      `;
    }

    return html``;
  }

  updated(changedProperties : Map<string, any>) {
    console.log('updated', changedProperties);
    console.log('componentObject', this.componentObject);
    super.updated(changedProperties);
  }

  render() {
    return this.renderComponent(html`
      <section class="content">
      <div>${this.renderDataGrid()}</div>
      </section>
    `);
  }
}


import { property, customElement } from 'lit/decorators.js';
import { DsBase } from './ds-base';

/**
 * Base class for components that fetch data from the IVS API.
 */
@customElement('ds-ivs-api-base-component')
export class DsIvsApiBaseComponent extends DsBase {

  private static readonly IVS_SERVICE_ENDPOINT = "https://api.dev.awstrp.net/investment-vehicle-svc/service/graphql";
  /**
   * The fragment used to fetch the data for the component.
   */
  @property({
    attribute: false,
  })
  protected query!: string;
  /**
   * The request query variables.
   */
  @property({ attribute: 'data-query-variables', type: String})
  protected variables?: string;



  constructor() {
    super();
  }

  connectedCallback() {
    super.connectedCallback();

    this.fetchData().then((response) => {
      console.log("IVS response" + response.data);
      this.processResponse(response);
    }).catch((error) => {
       console.error('Error fetching IVS data:', error);
    });
  }


  // eslint-disable-next-line @typescript-eslint/no-unused-vars
  protected processResponse(_response) {
    // Component must override
    console.warn('processResponse must be overridden');
  }

  protected getQueryVariables(): Record<string, unknown> {
    try {
      return JSON.parse(this.variables || '{}');
    } catch (e) {
      console.warn('Invalid or No query variables', e);
      return {};
    }
 }

  protected getQuery(): string {
    return this.query;
  }

  /** write code to make a fetch request to the IVS API using the getApiUrl, getQuery, and getQueryVariables methods. **/
    protected async fetchData(): Promise<any> {
      const response = await fetch(DsIvsApiBaseComponent.IVS_SERVICE_ENDPOINT, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'X-TRP-Requested-With': 'XMLHttpRequest',
          'apikey': 'pJex4NUuoEVkZ6ohvw5nR8Yfa27vcXI2'
        },
        body: JSON.stringify({
          query: this.getQuery(),
          variables: this.getQueryVariables(),
        }),
      });
      return response.json();
    }



}


import { LitElement, html, unsafeCSS } from 'lit';
import { property, customElement, state } from 'lit/decorators.js';
import { ComponentLoaderMixin } from '@trp-dms-digital-shared/ds-ui-library-components/src/lib/component-loader/component-loader.js';
import { DigitalSharedAnalytics } from '@trp-dms-digital-shared/ds-ui-library-common/src/utils/analytics/analytics.js';
import mixin from '@trp-dms-digital-shared/ds-ui-library-common/src/lib/mixin.js';

import { Constants } from './ds-base.constants';

type TTrackingHTMLElement = HTMLElement &
  Record<string, (originalEvent: Event) => void>;

/**
 * Base class for components that includes Beacon
 * @tag ds-base
 */
@customElement(Constants.TAG_NAME)
export class DsBase extends mixin(LitElement, ComponentLoaderMixin) {
  /**
   * @internal
   */
  static styles = [unsafeCSS(`/// styles imported via <link>n`)];

  /**
   * @internal
   */
  @state()
  tagName = '';

  /**
   * The current version of the pop component, used for version specific scoping
   * @internal
   */
  @property({ attribute: Constants.DS_VERSION, reflect: true })
  version = Constants.VERSION;

  /**
   * The current version of the pop component, used for version specific scoping
   * @internal
   */
  @property({ attribute: Constants.DS_VERSION, reflect: true })
  stylesheetUrl = Constants.VERSION;

  @property({
    type: Object,
    attribute: false,
  })
  componentObject?: unknown;

  constructor() {
    super();
  }

  connectedCallback() {
    super.connectedCallback();
    DigitalSharedAnalytics.unsetHostEventHandlerForAnalytics(
      this as unknown as TTrackingHTMLElement,
    );

    DigitalSharedAnalytics.setHostEventHandlerForAnalytics(
      this as unknown as TTrackingHTMLElement,
      Constants.DS_VERSION,
      this.version,
    );
  }

  /**
   * If the component is disconnected from the DOM, remove the analytics event listeners.
   */
  disconnectedCallback() {
    DigitalSharedAnalytics.unsetHostEventHandlerForAnalytics(
      this as unknown as TTrackingHTMLElement,
    );
    super.disconnectedCallback();
  }

  /*
   * This method is called from the Component Loader Mixin once any Defer conditions are met.
   * No need to override this method when extending the Base Component.
   * Wrapper to be used inside of the `render()` method
   * @example
   * render() {
   *  return this.renderComponent(html`<p>meow</p>`)
   * }
   */
  protected renderComponent(
    content: unknown,
    classes = 'beacon-theme-modern-outlook',
  ) {
    return !this.initialized
      ? html`<!--- Not Initialized --->`
      : html`
          <div data-base-container class="b-reset ${classes}">${content}</div>
        `;
  }

  render() {
    return this.renderComponent(html`<!--- Base Render Content --->`);
  }
}

As you can see, I have ds-base.ts, ds-base.api.ts and , etf-listing-table.ts . I have fetch call inside connectedCallBack and processResponse method setting componentObject.

What I don’t see , rederDataGrid html not appearing on the page, even though when I debug , I see all the code getting called.