wikipedia-query: "de" iron-ajax'ified
Tags: webcomponents, webdev, litelement, performance
Published: 2020-11-10 14:53:02

{% youtube 9smCfXgaH40 %}
This video shows how we got off of iron-ajax and replaced it with `fetch` + [IntersectionObserverMixin](https://www.npmjs.com/package/@lrnwebcomponents/intersection-element) to give us a performance optimized method of ONLY querying wikipedia when the user can see the element. Text explaining what's in the video follows.

## What's a "mix-in"?
A "mix-in" isn't a real thing but it's a methodology developers usually use to reference a JS development technique called `SuperClass`. SuperClass allows us to "mix" aspects of one object into another. So we start with one class based object and then we "mix-in" certain pieces of functionality, usually tying into hooks / life-cycle aspects of the underlying class.

## What IntersectionObserverMixin provides
- Automatically creates an [IntersectionObserver](https://caniuse.com/?search=IntersectionObserver)
- When the element is 25% visible, it sets a property called `elementVisible`
- Then it removes the listener for intersection for performance

This gives us the ability to automatically set a stateful property based on the thing being visible, where "thing" is literally any web component!

## How wikipedia-query leverages this capability
Full code for [wikipedia-query](https://github.com/elmsln/lrnwebcomponents/blob/master/elements/wikipedia-query/wikipedia-query.js) web component 
```js
// LitElement render function
  render() {
    return html`
      ${this.elementVisible ? html`
      <h3 .hidden="${this.hideTitle}">${this._title}</h3>
      <div id="result"></div>
      <citation-element
        creator="{Wikipedia contributors}"
        scope="sibling"
        license="by-sa"
        title="${this.search} --- {Wikipedia}{,} The Free Encyclopedia"
        source="https://en.wikipedia.org/w/index.php?title=${this.search}"
        date="${this.__now}"
      ></citation-element>` : ``}`;
  }
```
The `render` function (a LitElement convention to update the shadowRoot of our element) ONLY shows content IF we are currently visible! This keeps the DOM from having to present information until it's actually visible to the user's screen.

We also only request the element `citation-element` when we are visible as seen below.
```js
  /**
   * LitElement properties updated
   */
  updated(changedProperties) {
    changedProperties.forEach((oldValue, propName) => {
      // element is visible, now we can search
      if (propName == "elementVisible" && this[propName]) {
        import("@lrnwebcomponents/citation-element/citation-element.js");
      }
```
LitElement generates change records when properties are updated. Then we see if we are visible and if we are (meaning we were not hence change, and then true to be visible) we use `import()` which is a dynamic import for another element! HTML will automatically "hydrate" or populate the definition of the `citation-element` in the shadowRoot above. This means that we show the code for our element AND we only import the definitions of code in our element IF the element is currently on screen!

## Last, let's go get that yummy wikipedia data
```js
updateArticle(search) {
    fetch(
      `https://en.wikipedia.org/w/api.php?origin=*&action=query&titles=${search}&prop=extracts&format=json`
    )
      .then((response) => {
        if (response.ok) return response.json();
      })
      .then((json) => {
        this.handleResponse(json);
      });
  }
  /**
   * LitElement properties updated
   */
  updated(changedProperties) {
    changedProperties.forEach((oldValue, propName) => {
      // element is visible, now we can search
      if (propName == "elementVisible" && this[propName]) {
        import("@lrnwebcomponents/citation-element/citation-element.js");
      }
      if (
        ["elementVisible", "search"].includes(propName) &&
        this.search &&
        this.elementVisible
      ) {
        clearTimeout(this._debounce);
        this._debounce = setTimeout(() => {
          this.updateArticle(this.search);
        }, 25);
      }
```
We use `fetch` to replace `iron-ajax` but we don't just do that. We ONLY search for data if the element has something to search for AND it is currently visible. This gives us an ultra performant way of shipping a wikipedia-query tag across all browsers and platforms while only requesting data when the user has need for it.