Javascript return statement doesn’t stop rest of function from completing

I am using Docuware’s API to staple (merge) documents together. I have written my question as simple as I can so people with no Docuware knowledge should be able to understand.

So in my main function, I call another function and check the return value of the called function. If the value equals zero, it should return null – meaning the rest of the function should not run.

const lastStored = await searchDocument("Invoice", ORDER_NUMBER = '', cookie)
console.log("Full id func: " + id)
console.log("id[0]: " + id[0])

if (lastStored[0] === 0) {
    console.log("id[0]: " + id[0])
    return null;
};

I am getting weird errors with my code, so I have a lot of console.logs. Here are the console.logs when the code successfully works.

 cookie set
 Document is Invoice (Invoice)
 Invoice order #: ORD83001
 Current ID: 52724 Order #: ORD83001
 cookie set
 Document is DELIVERY SLIP (DELIVERY SLIP)
 Invoice order #: ORD83001
 DELIVERY SLIP Doc ID: 52553
 Current ID: 52553 Order #: ORD83001
 Full id func: 52553,ORD83001
 id[0]: 52553
 New Tray Doc ID: 1410
 Document's successfully merged.

Now, with the error, the console.logs are:

 //.....
 Current ID: 0 Order #: ORD83009
 Full id func: 0,ORD83009
 id[0]: 0
 id[0]: 0
 Document's successfully merged.

The thing about this error, is that if id[0] was truly zero, then the document’s wouldn’t be able to be merged. But the documents ARE merged if I look at them. So why is my code returning 0, even INSIDE my if statement, yet continues to run?

Is it some sort of timing issue? Like id[0] === 0 but .00000001 seconds later it gets updated so the return null doesn’t follow through?

Angular Electron not working on first load

I have tried building an Angular application with Electron and I have the following issue: When the app starts, the browser window is empty, nothing in the console. The whole body tag is empty as well. However, after I manually press reload in the Electron browser, it works – everything runs as expected. Any ideas why this might happen?

This is my main.js file:

const {app, BrowserWindow} = require('electron');
const {autoUpdater} = require("electron-updater");
const log = require('electron-log');

const url = require("url");
const path = require("path");
var webpackTargetElectronRenderer = require('webpack-target-electron-renderer');


autoUpdater.logger = log;
autoUpdater.logger.transports.file.level = 'info';
log.info('App starting...');

let win;

function sendStatusToWindow(text) {
  log.info(text);
  console.log(text);
  mainWindow.console.log(text);
  win.webContents.send('message', text);
}
// function createDefaultWindow() {
//   win = new BrowserWindow();
//   win.webContents.openDevTools();
//   win.on('closed', () => {
//     win = null;
//   });
//   win.loadURL(`file://${__dirname}/version.html#v${app.getVersion()}`);
//   return win;
// }

app.on('certificate-error', (event, webContents, url, error, certificate, callback) => {
  // On certificate error we disable default behaviour (stop loading the page)
  // and we then say "it is all fine - true" to the callback
  console.log(JSON.stringify(certificate));
  event.preventDefault();
  callback(true);
});

let mainWindow


var options = {
  // webPreferences: {
  //   webSecurity: false
  // },
  node: {
    __dirname: false
  }
}

options.target = webpackTargetElectronRenderer(options)

function createWindow () {
  mainWindow = new BrowserWindow({
    width: 1000,
    height: 800,
    webPreferences: {
      nodeIntegration: true
    }
    // webPreferences: {
      // plugins: true,
      // nodeIntegration: true,
      // webSecurity: false
    // }
  })

  // log.info('Hello, log');
  // log.info(log.transports.console);
  // console.log(log.transports.console);
  // log.warn('Some problem appears');
  // // log.info("Test");
  // console.log = log.info;
  console.log("TEst");
  // log.info(log.transports.file.getFile());
  mainWindow.loadURL(
    url.format({
      pathname: path.join(__dirname, `/dist/index.html`),
      protocol: "file:", 
      slashes: true
    })
  );
  // mainWindow.webContents.devToolsWebContents("Test");
  // var x = path.join(__dirname, `/dist/index.html`);
  // console.log(x);
  // mainWindow.loadURL(`file://${__dirname}/version.html#v${app.getVersion()}`);

  // Open the DevTools.
  mainWindow.webContents.openDevTools();
  // console.log("Test");

  mainWindow.on('closed', function () {
    mainWindow = null
  })

  autoUpdater.on('checking-for-update', () => {
    sendStatusToWindow('Checking for update...');
  })
  autoUpdater.on('update-available', (ev, info) => {
    sendStatusToWindow('Update available.');
  })
  autoUpdater.on('update-not-available', (ev, info) => {
    sendStatusToWindow('Update not available.');
  })
  autoUpdater.on('error', (ev, err) => {
    sendStatusToWindow('Error in auto-updater.');
  })
  autoUpdater.on('download-progress', (ev, progressObj) => {
    sendStatusToWindow('Download progress...');
  })
  autoUpdater.on('update-downloaded', (ev, info) => {
    sendStatusToWindow('Update downloaded; will install in 5 seconds');
  });

}

// app.on('ready', createWindow)
app.on('ready', function()  {
  createWindow();
  autoUpdater.checkForUpdatesAndNotify();
});

app.on('window-all-closed', function () {
  if (process.platform !== 'darwin') app.quit()
})

app.on('activate', function () {
  if (mainWindow === null) createWindow()
})

javascript JSON.stringify converts zodjs boolean to a number (1 or 0)

I am building an app with Typescript/nextjs/reactjs and I am using zodjs schema and types to validate user input in my frontend and backend. One of my problem is that when I JSON.stringify my user input (an object with a zod boolean) to send it to my backend/api, the boolean will be changed in 1 for true and 0 for false. That ends in an validation error in my backend.

The validation error looks like this:

“code”: “invalid_type”,
“expected”: “boolean”,
“received”: “number”,

“message”: “Expected boolean, received number”

My Zodjs Object/Schema and type looks like this:

export const SomeObject = z
  .object({
  ...
  active: z.boolean().default(true),
  ...
 }).strict();
export type SomeObject = z.infer<typeof SomeObject>;

what am I doing wrong?

Are there any libraries to make Chrome work like IE?

I know there used to be libraries to get IE to work like Chrome but I want the opposite. I guess you could say I’m throwing a hail marry trying to find a script that I can just drop in and have this legacy application work. Yes, IE has special permissions on Windows but I’m not worried about that right this second. First thing I want to try is just adding an IEify script.

Have you ever heard of such a thing?

How to display multiple y axis titles on seperate lines and rotated 90 degrees clockwise in chart.js

My goal is to display several y axis titles on separate lines rotated 90 degrees clockwise in chartjs.


The first code snippet illustrates how to display multiple y axis titles on seperate lines and is inspired by: Add multiple lines as Y axis title in chartJs

Relevant section for 1st code snippet of displaying multiple y axis titles on separate lines:

y: {
   stacked: true,
   title: {
      text: ['Project1', 'Number of defects', 'Project2'],
      display: true
   }
}

const labels = ['2021-06-07 00:00:00', '2021-06-08 00:00:00', '2021-06-09 00:00:00'];

const data = {
    labels: labels,
    datasets: [{
        label: 'Fixed defects',
        backgroundColor: 'rgb(0, 255, 0)',
        borderColor: 'rgb(0, 255, 0)',
        data: ['2', '73', '34'],
        barThickness: 5
    }, {
        label: 'Open defects',
        backgroundColor: 'rgb(255, 0, 0)',
        borderColor: 'rgb(255, 0, 0)',
        data: ['0', '5', '2'],
        barThickness: 5

    }]
};

const config = {
    type: 'bar',
    data: data,
    options: {
        scales: {
            x: {
                min: '2021-06-07 00:00:00',
                max: '2021-09-10 00:00:00',
                type: 'time',
                time: {
                    unit: 'week'
                },
                stacked: true,
                title: {
                    text: 'Dates (weeks)',
                    display: true
                }
            },
            y: {
                stacked: true,
                title: {
                    text: ['Project1', 'Number of defects', 'Project2'],
                    display: true
                }
            }
        }
    }
};

const myChart = new Chart(
    document.getElementById('myChart'),
    config
);
<!DOCTYPE html>
<meta charset="utf-8">

<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="https://cdn.jsdelivr.net/npm/moment@^2"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-moment@^1"></script>
<link rel="stylesheet" type="text/css" href="../styles.css">

<body>
    
    <div>
        <canvas height="100px" id="myChart"></canvas>
    </div>
</body>

The second snippet shows one solution for rotating the y axis title 90 degrees clockwise inspired by: Ability to rotate y axis title in chart.js

Relevant section for 2nd code snippet of rotating y axis title 90 degrees clockwise:

ctx.fillText(text, 3, (top + bottom) / 2)

and

plugins: {
      customTitle: {
        display: true,
        text: 'Number of defects',
        color: 'blue'
      }
    }

const customTitle = {
    id: 'customTitle',
    beforeLayout: (chart, args, opts) => {
        const {display,font} = opts;
        if (!display) {
            return;
        }
        const {ctx} = chart;
        ctx.font = font || '12px "Helvetica Neue", Helvetica, Arial, sans-serif'
        const {width} = ctx.measureText(opts.text);
        chart.options.layout.padding.left = width * 1.1;
    },
    afterDraw: (chart, args, opts) => {
        const {font,text,color} = opts;
        const {ctx,chartArea: {top,bottom,left,right}} = chart;
        if (opts.display) {
            ctx.fillStyle = color || Chart.defaults.color
            ctx.font = font || '12px "Helvetica Neue", Helvetica, Arial, sans-serif'
            ctx.fillText(text, 3, (top + bottom) / 2)
        }
    }
}

const labels = ['2021-06-07 00:00:00', '2021-06-08 00:00:00', '2021-06-09 00:00:00'];

const data = {
    labels: labels,
    datasets: [{
        label: 'Fixed defects',
        backgroundColor: 'rgb(0, 255, 0)',
        borderColor: 'rgb(0, 255, 0)',
        data: ['2', '73', '34'],
        barThickness: 5
    }, {
        label: 'Open defects',
        backgroundColor: 'rgb(255, 0, 0)',
        borderColor: 'rgb(255, 0, 0)',
        data: ['0', '5', '2'],
        barThickness: 5

    }]
};

const config = {
    type: 'bar',
    data: data,
    options: {
        scales: {
            x: {
                min: '2021-06-07 00:00:00',
                max: '2021-09-10 00:00:00',
                type: 'time',
                time: {
                    unit: 'week'
                },
                stacked: true,
            },
            y: {
                stacked: true,
            }
        },
        plugins: {
            customTitle: {
                display: true,
                text: 'Number of defects',
                color: 'blue'
            }
        }
    },
    plugins: [customTitle]
};

const myChart = new Chart(
    document.getElementById('myChart'),
    config
);
<!DOCTYPE html>
<meta charset="utf-8">

<script src="https://cdn.jsdelivr.net/npm/chart.js@^3"></script>
<script src="https://cdn.jsdelivr.net/npm/moment@^2"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-moment@^1"></script>

<body>
  <div>
    <canvas height="100px" id="myChart"></canvas>
  </div>
</body>

However when I try to combine both solutions together I can either get the correct rotated 90 degrees title (but not on seperate lines) or the multiple titles on seperate lines (but not rotated 90 degrees clockwise) as shown in this fiddle: Example fiddle

I also tried adding new lines in the rotated title:

['Project1nNumber of defectsnProject2']

But that didn’t work either.

Any help would be appreciated.

To be clear: I want the title to be on separate lines and rotated 90 degrees clockwise, not the ticks/labels.

Setting a state using spread operator updates the state vs setting the same object not updating the state

I have an initial object called as initUser, it consists of initial fields of the user as follows

const initUser: UserProfile = {
    firstName: '',
    lastName: '',
    phone: '',
    email: '',
    // and so on
};

The object is very big, it has more than 30 fields in it. So while re initialising the state to its initial state, I did this

setUser(initUser);

Which didn’t work.

But when I did this

setUser({...initUser});

It started to work, although the spread operator is very expensive as it makes the copy of the variable, so any idea why passing the variable is not working? Thank you in advance.

PS: The initUser is placed in another file and is imported correctly since its working properly in the spread operator.

Render BitTorrent/Transmission bitfield

I’m trying to render a BitTorrent (transmission) bitfield into a chart like the following:

enter image description here

I’m getting my bitfield from the pieces field of the Transmission RPC API.

My code right now looks like the following:

function renderPieces(pieces: string, pieceCount: number) {
  const w = 100;
  const h = 100;

  const ppp = pieceCount / w; // pieceCount per pixel

  pieces = Buffer.from(pieces, "base64").toString("utf8");

  const cells = [];
  let bitIndex = 0.0;
  let sb, eb, db;
  let b, c;
  let j = 0;
  for (let i = 0, len = pieces.length; i < len; ++i) {
    b = (b << 8) | pieces.charCodeAt(i);
    bitIndex += 8.0;
    sb = Math.round(bitIndex);
    while (bitIndex > ppp) {
      bitIndex -= ppp;
      eb = Math.round(bitIndex);
      db = sb - eb;

      c = b >> eb;
      c <<= 32 - db;
      c = c - ((c >> 1) & 0x55555555);
      c = (c & 0x33333333) + ((c >> 2) & 0x33333333);
      c = (((c + (c >> 4)) & 0x0f0f0f0f) * 0x01010101) >> 24;

      cells.push({
        alpha: c / db,
        moveTo: [j, 0],
        lineTo: [j++, h],
      });

      sb = eb;
    }
  }
  return cells;
}

I’d like to then use the array of { alpha: number, moveTo: [number, number], lineTo: [number, number] } to render an SVG:

const printTorrentDetails = (torrent: Torrent) => {
  return `<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
      ${renderPieces(torrent.pieces, torrent.pieceCount)
        .map(
          ({ moveTo, lineTo, alpha }) =>
            `<line x1="${moveTo[0]}" y1="${moveTo[1]}" x2="${lineTo[0]}" y2="${lineTo[1]}" stroke="rgba(0, 0, 0, ${alpha})" />`
        )
        .join("")}
    </svg>`;
}

The problem is that my code is only rendering a list of vertical lines instead of something resembling the image I posted.

This is my base64 encoded bitfield:

Ph/d7r/f/fN///xwVv///v///+/Y7///54QH///ePc///vt///D//3/8fgDvf/////8f3n+CH+f+TI///DwA//9MAGMAfB/P4BYAAcf2AaHjj//+D+eAAf/v/+HiAH4f/x/hAAP//8PEBkAAf8AxEEcAPwCMIEB4j4AFAQAAAQBDgAAAoAAATAAAsAAAAYAAAAAAAAAABAAAAACAAHgAAAAQAABAAJAAAAEAASAAAAACAAAYAAgAAAAAAmAAABAAAAgAAAAAAAAAEAgAAAAIACAAACEEAAAAAEwIAAABAAAAAAAQAAAARADIACAACCAgAgAAAQAAAABAIAACEBAAAAAAAAAAAEAAEAAAAEAgCAAAAAIIAAIAAAIAAAEIAAAAiBAAAAEAAAAAAAAAAAAAAAAAAAAAgAAAAAAAEgAAEQAAAoAAEAAEEAAAAAAAIAAAAoAIQgAAAAGBBAgAAAIABADABGAARAAIAAAABAAAEAAAAAAAAIAAAAAiAgABAAAAAAAAkQAECCBQAAAAAAAAAAAIAAAAABgAEAIwAAABBAIABABARQAAAAQAIgAgAAAQBEAAAAAgEAAABAAAAAAAgwAAEABBAIAAAAAAAAAAAAAAAAgABKAAAAAAAgACAAgIAQAAAAAAEBAAAAEAAAAADAAMAAAAAYAAAAABAAACAAAAEIQQIAAABAABAAAAAAAAAAAAAAEAAQAAgAAAQAAAAAAIBAAAAQEAAAAAgAQQAAAIAgAAAABAAAAAAAgAAAgAAAAAAAAAAACAAAAAACAAAAAAAAAAAAACAAAAAJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAIAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAABSAAAAAAAAAAACAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIA=

How to render html page base on api response

I’m just trying to display a simple text “No matching lyrics is found” in the UI When ever a user search a song and there is not matching song in the database but not really sure how can I modify it so I would be really appreciated it.

<?php
require_once '../config.php';


if (isset($_POST['submit'])) {
  $title = $_POST['search'];

  $sql = 'SELECT * FROM song WHERE title = :title';
  $stmt = $conn->prepare($sql);
  $stmt->execute(['title' => $title]);
  $row = $stmt->fetch();
} else {
  header('location: .');
  echo 'Not matching found';
  exit();
 
}
?>

<!DOCTYPE html>
<head>Search song</head>
<body>
     <div>
          // Here will be all the content of the song
     </div>
    
     //Show this div if there is no matching song
     <div>
           <p>No matching lyrics is found<p>
     </div>

</body>
</html>

I have tried to do with .show() and hide() but still not working.

Unable to manipulate the object to a specific format in Javascript

I am trying to manipulate the object into my format of object but it’s not working.

I want to convert this array of objects:

let details =
[
 { tower_name: 'T1', flats: '["99", "96"]' },
 { tower_name: 'T2', flats: '["98"]' },
 { tower_name: 'T3', flats: '["505"]' }
]

And turn it into below format:

let towerFlatDetails = 
{
"T1": ["99", "96"],
"T2": ["98"],
"T3": ["505"],
}

I tried it this way, but it didn’t work:

let towerFlatDetails = {}
for (let i in details)
{
    towerFlatDetails.details[i].tower_name = JSON.parse(towerFlatDetails.details[i].flats)
}

Sorting object array by a property value

I have this array ob objects that I need to sort by their number

var products = [
{
 name: 'Gift Box',
 productNumber: '44',
 SKU: 'ABCD'
},
{
 name: 'Tabletop Game',
 productNumber: '63',
 SKU: 'DEFG'
},
{
 name: 'Poker Deck',
 productNumber: '25s',
 SKU: 'HIJK'
},
{
 name: 'Box of chocolates',
 productNumber: '96p',
 SKU: 'LMNO'
},
{
 name: 'Box of Swiss chocolates',
 productNumber: '96s',
 SKU: 'PQRS'
},
{
 name: 'Gift card',
 productNumber: '81',
 SKU: 'TUVW'
}];

As you can see, some of the productNumber properties have a letter in them, and as such, I think is not going to be as easy as just doing a products.sort((a, b) => parseInt(b.productNumber) - parseInt(a.productNumber));, so, how can I solve this?

Jest – Test Suite Failed to Run “x.default is not a constructor”

Two of my jest test suites are failing to run, I receive the errors “_player.default is not a constructor” and “_gameboard.default is not a constructor”.

I have a player class that I want to test:

export default class Player {
 constructor(name) {
  this.name = name;
  this.isTurn = false;
  this.isConsideringAttack = false;
  this.gameboard = new Gameboard();
  }
 }

And a gameboard class:

export default class Gameboard {
 constructor() {
  this.board = [];
  this.initialiseBoard();
  }
 }

The error I receive when I try to run the player test suite:

  ● Test suite failed to run

TypeError: _player.default is not a constructor

  3 |
  4 | const players = {
> 5 |   user: new Player('user'),
    |         ^
  6 |   computer: new Player('computer'),
  7 | };
  8 |

  at Object.<anonymous> (src/game.js:5:9)
  at Object.<anonymous> (src/dragAndDrop.js:2:1)

The error I receive when I try to run the gameboard test suite:

  ● Test suite failed to run

TypeError: _gameboard.default is not a constructor

   7 |     this.isTurn = false;
   8 |     this.isConsideringAttack = false;
>  9 |     this.gameboard = new Gameboard();
     |                      ^
  10 |   }
  11 |
  12 |   attack(x, y, gameboard) {

  at new Player (src/factories/player.js:9:22)
  at Object.<anonymous> (src/game.js:5:9)
  at Object.<anonymous> (src/dragAndDrop.js:2:1)

I’m very new to Jest, I couldn’t find a fix for this despite spending a few hours searching. Any help would be appreciated.

Use mouseover to add animation on hover

I’m trying to add an animation to an element when someone hover on it.

My thought is to add a class with keyframes that attach to the element by adding a mouseover event listener to it.

The reason I don’t use CSS is because I want the animation to be finished even the mouse leave the element before the animation is finished. For example, the mouse is moved out of element when rotating on 180 degree (full animation is 360 degree)

But sadly it’s not working and I don’t know why…

const item = document.querySelector('#rotate');

item.addEventListener('mouseover' function(e) {
  if(item) e.classList.add('rotate');
});
#div {
  width: 120px;
  height: 120px;
  background-color: orange;
}

.rotate {
  animation: rotating 1s ease 0s 1 normal forwards;
}

@keyframes rotating {
  0% {
    transform: rotate(0);
  }

  100% {
    transform: rotate(360deg);
  }
}
<div id='rotate'></div>

How to call HTML attribute ‘minlength’ in JavaSript

I have this code snippet:

<div>
      <label for="requiredSize">Required Size 5 : </label>
      <input type="text" name="requiredSize" id="requiredSize" class="required_size" minlength="5" />
</div>

I am doing a form validation exercise, and I need to have one of the requirements be based on required size. How can I call the minlength into my Javascript file to be used since it does change throughout the form.

I have tried documnet.querySelector("minlength") to try and save it as a variable, but it wasn’t being recognized.

How can i use createPortal in NextJS when using typescript?

I’m using Nextjs + Typescript to make a toy project
and I’m having a problem when using createPortal to create a Modal.
I got a problem with render in Browser.
why doesn’t it work?
I have done a lot of trying googling but i couldn’t solve it.
Plz help me.

enter image description here

HOC/Portal.tsx

import { useState, useEffect, useRef } from "react";
import { createPortal } from "react-dom";

interface Props {
  children: any;
}
const Portal: React.FC<Props> = ({ children }) => {
  const ref = useRef<HTMLDivElement | null>(null);
  const [mounted, setMounted] = useState(false);

  useEffect(() => {
    ref.current = document.querySelector("overlay-root");
    setMounted(true);
    return () => setMounted(false);
  }, []);

  return mounted ? createPortal(children, ref.current!) : null;
};

export default Portal;

src/Components/layout/Header.tsx

...
 {isLoginModal && (
            <Portal>
              <Login
                onChangeLoginModal={onChangeLoginModal}
                onChangeLoginState={onChangeLoginState}
                isLoginState={isLoginState}
                isLoginModal
              />
            </Portal>
          )}
...

pages/_documents.tsx

 ...
  render() {
    return (
      <Html>
        <Head>
          <meta charSet="utf-8" />
          <meta
            name="viewport"
            content="target-densitydpi=device-dpi, user-scalable=0, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, width=device-width"
          ></meta>
          <link
            href="https://fonts.googleapis.com/css2?family=Dongle&family=Noto+Sans+KR:wght@500&family=Roboto:wght@500&display=swap"
            rel="stylesheet"
          />
        </Head>
        <body>
          <Main />
          {/* here */}
          <div id="overlay-root"></div>
          <NextScript />
        </body>
      </Html>
    );
  }
}

export default MyDocument;