0

I had a page which loaded a list of applications, then ran a request for each of those applications to ping them. I wanted to ensure this page updated the status on a periodic basis in the background.

I decided to add a setTimeout to getApplications, so it reloaded them every 30 seconds.

The issue is, the table I originally rendered in HTML doesn't update to reflect the changes to applications such as the name or ping status.

import axios from "axios";
import React from "react";

class Applications extends React.Component<any, any> {
    constructor() {
        super({});

        this.state = {
            applications: []
        }

        this.logout = this.logout.bind(this);
    }

    async pingApplications() {
        for (const application of this.state.applications) {
            await this.checkPing(application.id);
        }
    }

    async componentDidUpdate(prevProps: any, prevState: any) {
        if (this.state.isLoading) return;
        if (this.state.error) return;

        await this.pingApplications();
    }

    async checkPing(applicationId : number) {
        console.log('[data-application-id=\'' + applicationId + '\']');
        axios.get(process.env.REACT_APP_API_URL + '/applications/' + applicationId + '/ping')
            .then(function (response) {
                if (response.status == 404) {
                    document.querySelectorAll('[data-application-id=\'' + applicationId + '\']')[0].innerHTML = '<div class="h-2.5 w-2.5 rounded-full bg-green-500 mr-2"></div> Offline';
                }
                else {
                    document.querySelectorAll('[data-application-id=\'' + applicationId + '\']')[0].innerHTML = '<div class="h-2.5 w-2.5 rounded-full bg-green-500 mr-2"></div> Running';
                }
            })
            .catch(function (error) {
                document.querySelectorAll('[data-application-id=\'' + applicationId + '\']')[0].innerHTML = '<div class="h-2.5 w-2.5 rounded-full bg-red-500 mr-2"></div> Offline';
            });
    }

    async getApplications() {
        var component = this;

        await axios.get(process.env.REACT_APP_API_URL + '/applications')
            .then(async function (response) {
                await component.setState({
                    applications: response.data,
                });
            })
            .catch(function (error) {
                // handle error
                console.log(error);
            })
            .finally(function () {
                // always executed
            });

        for (let i = 0; i < component.state.applications.length; i++) {
            console.log(i);
            await component.checkPing(component.state.applications[i].id);
        }

        setTimeout(component.getApplications, 30000);
    }

    logout() {
        localStorage.removeItem('access_token');
        document.location.reload()
    }

    async componentDidMount() {
        await this.getApplications();
    }

    render() {
        return (<div className={"p-4"}>
            <div className="flex">
                <a href="/applications/create"
                   className="bg-green-500 hover:bg-green-400 text-white px-5 py-2 mb-6 rounded shadow text-center mr-4 block">
                    Create
                </a>
                <div className="bg-red-500 hover:bg-red-400 text-white px-5 py-2 mb-6 rounded shadow text-center"
                     onClick={this.logout}>
                    Logout
                </div>
            </div>
            <div className="relative overflow-x-auto shadow-md sm:rounded-lg">
                <table className="w-full text-sm text-left text-gray-500">
                    <thead className="text-xs text-gray-700 uppercase bg-gray-50">
                    <tr>
                        <th scope="col" className="px-6 py-3">
                            Name
                        </th>
                        <th scope="col" className="px-6 py-3">
                            Repository
                        </th>
                        <th scope="col" className="px-6 py-3">
                            Status
                        </th>
                    </tr>
                    </thead>
                    <tbody>
                    {this.state.applications.map(function(application: any, index: any) {
                        return (<tr key={index} className="bg-white border-b">
                            <th scope="row" className="px-6 py-4 font-medium text-gray-900 whitespace-nowrap">
                                <a href={'/applications/' + application.id}>{application.name}</a>
                            </th>
                            <td className="px-6 py-4">
                                {application.repository.url.split("/").pop()}
                            </td>
                            <td className="px-6 py-4">
                                <div data-application-id={application.id} className="flex items-center">
                                    <div className="h-2.5 w-2.5 rounded-full bg-orange-400 mr-2"></div>
                                    Pinging...
                                </div>
                            </td>
                        </tr>);
                    })}
                    </tbody>
                </table>
            </div>

        </div>)
    }
}

export default Applications;
3zy2umk22n
  • 39
  • 6
  • You should never modify html directly in react – Konrad Apr 11 '23 at 13:46
  • No, I am not using setState here? I understand state is queued. – 3zy2umk22n Apr 11 '23 at 14:01
  • I understand state is queued. The issue is, when state has finished for the second time, reactive elements of the component aren't updating or being re-rendered when its state changes for a 2nd time. – 3zy2umk22n Apr 11 '23 at 14:06

0 Answers0