DEV Community

Mark Cockram
Mark Cockram

Posted on

Prevent reinitialization of React tooltip component to prevent API calls

I load profile data from API to be displayed when the client hovers over a profile name. When the client stops hovering and then hovers again, the tooltip component gets reinitialized and an API call is done again. Currently I am using localStorage to cache the data but this seems like an improper fix.

My question is how do I prevent the tooltip component from being thrown away and reinitialized?

Image description

  const renderTooltip = (props) => (
    <Tooltip>
      <UserInfoFetchData uuid={props} />
    </Tooltip>
  );

  <OverlayTrigger
    placement="top"
    uuid={gamer.uuid}
    delay={{ show: 250, hide: 400 }}
    overlay={renderTooltip(gamer.uuid)}
  >
      <a href={"/user/" + gamer.uuid}>{gamer.username}</a>
  </OverlayTrigger>
Enter fullscreen mode Exit fullscreen mode

The above code is used to call the React Component. Below you see the code of the component itself.

import React, { useEffect, useState } from "react";
import Backend from "../../data/Backend";

export default class UserInfoFetchData extends React.Component {
  constructor(props) {
    super(props);
    console.log("test");
    this.state = {};
  }

  componentDidMount() {
    const cacheLocation = "profile " + this.props.uuid;
    let data = localStorage.getItem(cacheLocation);

    if (!data) {
      this.controller = new AbortController();
      new Backend()
        .getUser({ uuid: this.props.uuid }, { signal: this.controller.signal })
        .then((response) => {
          console.log("fetched data");
          this.setState(response.data);
          localStorage.setItem(cacheLocation, JSON.stringify(response.data));
          this.controller = null;
        });
    } else {
      this.setState(JSON.parse(data));
    }
  }

  componentWillUnmount() {
    if (this.controller) {
      this.controller.abort();
    }
  }

  render() {
    const capitalize = (str) => {
      return `${str[0].toUpperCase()}${str.slice(1)}`;
    };
    return (
      <div className="card border-dark ">
        <div className="card-body">
          <table className="table table-hover">
            <tbody>
              {Object.keys(this.state)
                .filter(
                  (o) =>
                    o !== "uuid" &&
                    o !== "username" &&
                    !o.includes("weekly") &&
                    !o.includes("monthly")
                )
                .map((e, i) => {
                  return (
                    <tr key={e}>
                      <th scope="row">{capitalize(e.replace("_", " "))}</th>

                      <td>{this.state[e]}</td>
                    </tr>
                  );
                })}
            </tbody>
          </table>
        </div>
      </div>
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

The console logs "test" each time I hover over a username, which means the component is being reinitialized each time. Is there a way I can make this only initialize once? Or is there a way to properly store the API retrieved data in the class?

Note: new Backend().getUser() simply returns an AxioInstance.

Top comments (0)