0

I am converting web service from Angular to React. Angular version I worked with was 6.0.x and nodejs version was 10.18.x. React version that I am currently working with is 16.14.0 and nodejs is upgraded to 12.16.2.

In Angular, I used HttpClient module (for all CRUD), and it was simple and fast. I just had to write query and send request.

I thought it would be just as simple in React as well, but apparently not. I am using fetch for all CRUD, since it does not require third-party library. I want to keep number of third-party libraries as low as possible, since I have to run the service in the cloud (1 CPU and 1GB RAM with 50GB Disk size, which is not much to work with).

What I have so far is like below:

// page.jsx
class Page extends React.Component {
    toNext() {
        const postData = async() => {
            const postResponse = await fetch('/post-data', { 
                method: 'POST', 
                headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' }, 
                body: JSON.stringify(this.state.data)
            });
            return await postResponse;
        }
        // after uploading successfully, move to anotherpage and load data including the one just loaded.
        postData().then(res => res.json()).then((data) => { if (!data.result) this.props.history.push('/anotherpage'); });
    }

    render() {
        return(
            <TouchableOpacity onPress={this.toNext}>
        )
    }
}
// index.js where fetch post is defined with url, query, etc
const express = require('express');
const mysql = require('mysql');

const host = 'host';
const user = 'user';
const password = 'password';

const conn = mysql.createPool({
    host: host,
    user: user,
    password: password,
    database: 'database'
});

app.post('/post-data', function (req, res) {
    let body = req.body;
    let isError = false;
    const checkError = () => {
        isError = true;
    }

    for (let row of body) {
        console.log('one loop started: ', new Date()) // check if the request itself takes too long
        conn.getConnection(function (err, connection) {
            connection.query(`INSERT INTO TABLE (COL1, COL2, COL3, ...) VALUES ("${row.COL1}", "${row.COL2}", "${row.COL3}", ...)`,
            function (error, results, fields) {
                if (error) {
                    console.log(row)
                    checkError();
                    throw error;
                };
            });
        });
        console.log('one loop ended: ', new Date()) // check if the request itself takes too long
    } 

    res.send({
        'result': isError
    });
})

Logs that I added shows that request itself takes only like 1 ms per row, but it takes about 4 minutes to upload all the data (44 rows, 17 columns, each cell with about 10 characters). In Angular, it only took seconds (2 seconds at most).

I tried to find what the actual post code looks like (app.post part in index.js), but all I got was the function code (jsx or tsx code). How should I go about posting data to DB? Does it take this long to post data via fetch?

UPDATE: As Phil suggested in the comment, Why can't we do multiple response.send in Express.js? explains that res.send() should be used only once, since it includes res.end(), and only the first res.send() is executed. So, I changed my code, and although at first, it looked like it fixed the original issue, the delay still exists in posting data to DB (about 4 minutes).

  • 1
    What do dev tools say the request takes? It is *very* weird that fetch would behave any differently since its the same browser apis under the hood. – Nick Bailey May 23 '22 at 01:05
  • @NickBailey Yes, that is what I thought. Because it is the same node js and express js after all. By "what do dev tools say the request takes?" you mean, the time it takes for each loop? If that is the case, it is like 0.001seconds (loop starts at 2022-05-23T01:31:04.867Z. loop ends at 2022-05-23T01:31:04.868Z). If not, could you clarify a bit more? – beginnercoder May 23 '22 at 01:34
  • @Phil Yes, originally in Angular, I used conditional variable, like let isError = false to see if error occurs in the middle of loop, and based on that, I returned result in one res.send(). But, in React, if I do that, it throws warning saying a variable is changed inside for loop. I tried to find a way to work around that, but I did not get a satisfying result. I know that it is out of this question's scope, but is there any way to fix that? – beginnercoder May 23 '22 at 01:37
  • @Phil in index.js, if I add ```let isError = false``` below ```let body = req.body;``` and add ```isError = true``` inside if (error), then I get a warning **Function declared in a loop contains unsafe references to variable 'isError'** – beginnercoder May 23 '22 at 03:44
  • That would be your linter warning you about some bad code, not React. See https://eslint.org/docs/rules/no-loop-func – Phil May 23 '22 at 03:51
  • @Phil Yes, I know that it would not affect React, frontend, backend or anything performance-wise, but I just wanted to avoid bad practice if possible. But, I created a function to check and update isError in index.js inside app.post(), and now it does not give warning, and it also fixed the delay issue that I had. So, I think it was multiple res.send() that caused the issue. Thanks! If you want to rewrite that as an answer I will definitely pick it as an answer! – beginnercoder May 23 '22 at 04:07
  • Does this answer your question? [Why can't we do multiple response.send in Express.js?](https://stackoverflow.com/questions/25542521/why-cant-we-do-multiple-response-send-in-express-js) – Phil May 23 '22 at 04:08
  • @Phil Actually, it did not fix the original issue. It did help me come up with a function and use res.send() just once, but it did not fix the delay in posting data to db. Sorry for the confusion. – beginnercoder May 23 '22 at 04:21

1 Answers1

2

If there is anyone experiencing a similar problem, here is what I have found.

When I was working with Node 10.18.x, mysql package 2.17.1 and Angular, I inserted row by row in for-loop, and it worked without any problems.

But now I am working with Node 12.16.2, mysql package 2.18.1 and React, and it seems bulk-insertion is preferred to row-by-row insertion. Although row-by-row insertion works, it gives delay and data are inserted over a period of time (like few minutes). I still have to find out why, but in the meantime, I used bulk-insertion.

I followed this link on bulk-insertion.

My updated code looks like:

// index.js
app.post('/post-data', (req, res) => {
    let body = req.body;

    // define sql query
    let sql = `INSERT INTO TABLE (COL1, COL2, COL3, ...) VALUES ?`;

    // below two lines can be done in jsx(tsx)
    let values = new Array(body.length).fill(null).map(() => { return [] });
    for (let i = 0; i < body.length; i++) {
        for (let col of ['COL1', 'COL2', 'COL3', ...]) {
            values[i].push(body[i][col]);
        }
    }

    // it should be [values]. So, basically [[[values1, values2, values3, ...], [values1, values2, values3, ...]]]
    // bulk-insertion
    modConn.query(sql, [values], (error, results, fields) => {
        if (!error) {
            res.send(results)
        } else {
            res.send(error)
        }
    });
});

res.send() is inside if else, so I do not think there is a problem since only one of them is executed at any time. And, there is no delay in posting, so all my data (44 rows by 17 columns) are inserted under a second.

  • You keep mentioning React vs Angular but your choice of front-end framework has nothing to do with what your server-side code does with request data. If anything, I'd say your major change would have been the Node version and possibly `mysql` package – Phil May 23 '22 at 05:41
  • @Phil True, React and Angular are front-end framework and have nothing to do with what back-end does. Also true that node version is upgraded from v10 to v12 and mysql from v2.17.1 to v2.18.1. But, I just wanted to share my situation so that anyone converting from Angular to React or vice versa may have some references. Whether it is node, mysql, or some other underlying causes that we overlooked, it may help them. But I really appreciate for guiding me on how to fix res.send issues and pointing out that it may be due to Node and mysql package version. I actually overlooked node versions :) – beginnercoder May 23 '22 at 06:07