React DOMException 관련 질문 드립니다.

안녕하십니까. React로 현재 회원가입 페이지를 만들고 있는데요. 한 가지 의문이 들어서 글 올립니다. 크롬 한국어 번역 기능을 활성화 하고 input 창에 텍스트를 입력하면 페이지가 날라갑니다. 콘솔 탭을 확인해보니 이런 에러 문구가 떴습니다.

DOMException: Failed to execute ‘insertBefore’ on ‘Node’: The node before which the new node is to be inserted is not a child of this node

이 에러에 대해 확인해보니 해당 노드가 부모 노드에 포함된 자식 노드가 아니어서 발생한 에러인 듯 보입니다. 그렇다면 한국어 자동 번역 기능을 활성화하지 않았을 때도 이런 에러가 발생해야 하는데 한국어 자동 번역 기능을 활성화 하지 않으면 아무 문제 없이 동작합니다.

혹시 이런 에러를 겪어 보신 분이 계신가요? 혹시 이 사항에 대해 아시는 분이 계시다면 고견을 구합니다.

부족한 글 읽어주셔서 감사 드립니다.

저 문제를 직접 확인할 수 있는 개발하고 계신 사이트 주소를 함께 알려주시면 해결 방법을 찾는데 도움이 됩니다.

네 제가 그 부분을 빼먹었네요. 커뮤니티 회원분들이 저의 질문을 제대로 이해하기 위한 자료를 더 제공하겠습니다. 먼저 개발하고 있는 사이트 URL주소 입니다.
http://docuer.co.s3-website.ap-northeast-2.amazonaws.com/register

그리고 코드 입니다.

import React, {useState} from "react"

import checkImg from "../assets/Check.png"

import axios from "axios"

import cookie from "react-cookies"

import "../css/RegisterForm.css"

import { config } from "../configs/Types.config"

import clearImg from "../assets/Close-bt.png"

let vision : string = "hidden"

let vision2 : string = "hidden"

let vision3 : string = "hidden"

let vision4 : string = "hidden"

let vision5 : string = "hidden"

let vision6 : string = "hidden" // password field

let vision7 : string = "hidden"

const RegisterComponent : React.FC = () => {

    let [view, setView] = useState(false)

    let [view2, setView2] = useState(false)

    let [view3, setView3] = useState(false)

    let [view4, setView4] = useState(false)

    let nickName : string = ""

    function ClearEmail() {

        console.log(view)

        vision = "hidden"

        vision3 = "hidden"

        setView((view) => !view)

        // @ts-ignore

        document.getElementById("emailInput").value = ""

    }

    function ClearName() {

        vision4 = "hidden"

        vision5 = "hidden"

        setView3((view) => !view)

        // @ts-ignore

        document.getElementById("nickNameInput").value = ""

    }

    function ClearPW() {

        vision6 = "hidden"

        vision7 = "hidden"

        setView4((view4) => !view4)

        // @ts-ignore

        document.getElementById("passwordInput").value = ""

    }

    async function emailCheck() {

        const regEmail = /^[0-9a-zA-Z]([-_\.]?[0-9a-zA-Z])*@[0-9a-zA-Z]([-_\.]?[0-9a-zA-Z])*\.[a-zA-Z]{2,3}$/i

        try {

            const res = await axios.post(`${config.host}/users/login/exist`, {

                // @ts-ignore

                account : document.getElementById("emailInput").value

            })

            // @ts-ignore

            console.log(regEmail.test(document.getElementById("emailInput").value))

            // @ts-ignore

            if (res.data === true && regEmail.test(document.getElementById("emailInput").value) ) { // 사용 가능한 email

                vision2 = "visible"

                vision = "hidden"

                vision3 = "hidden"

                setView2((view2) => !view2)

            }// @ts-ignore

            else if (regEmail.test(document.getElementById("emailInput").value) === false) {

                vision2 = "hidden"

                vision = "visible"

                // @ts-ignore

                if (document.getElementById("emailInput").value.length < 1) {

                    vision = "hidden"

                    console.log("here")

                    setView((view) => !view)

                }

                setView2((view2) => !view2)

            }

            // @ts-ignore

            else if (document.getElementById("emailInput").value.length < 1) {

                vision = "hidden"

                console.log("here")

                setView((view2) => !view2)

            }

        } catch(e) {

            console.log("ERROR IS: "+e)

            vision2 = "hidden"

            vision = "visible"

            vision3 = "visible"

            setView((view) => !view)

        }

    }

    async function nickNameCheck() {

        const regNick = /^[a-zA-Z0-9._]{5,20}$/

        try {

            const res = await axios.post(`${config.host}/users/nickname`, {

                // @ts-ignore

                nickName : document.getElementById("nickNameInput").value

            })

            // nickName이 존재 할 경우

            // @ts-ignore

            if (res.data != "" && regNick.test(document.getElementById("nickNameInput").value)) {

                console.log("here")

                console.log(res.data)

                vision4 = "visible"

                vision5 = "hidden"

                setView3((view3) => !view3)

            }

            // nickName이 존재하지 않고 ID양식에 부합하는 경우

            // @ts-ignore

            else if (regNick.test(document.getElementById("nickNameInput").value) && res.data === ""){

                vision4 = "hidden"

                vision5 = "visible"

                setView3((view3) => !view3)

            } else {

                vision4 = "visible"

                vision5 = "hidden"

                // @ts-ignore

                if (document.getElementById("nickNameInput").value.length < 1) {

                    vision4 = "hidden"

                }

                setView3((view3) => !view3)

            }

        } catch (e){

            console.log("ERROR IS: "+e)

        }

    }

    function checkPW() {

        const regPW = /(?=.*\d{1,16})(?=.*[~`!@#$%\^&*()-+=]{1,16})(?=.*[a-zA-Z]{1,16}).{8,16}$/;

        // @ts-ignore

        if (regPW.test(document.getElementById("passwordInput").value)) { // 비밀번호가 규칙에 맞을 때

            vision6 = "hidden"

            vision7 = "visible"

            setView4((view4) => !view4)

        } else{

            vision6 = "visible"

            vision7 = "hidden"

            // @ts-ignore

            if (document.getElementById("passwordInput").value.length < 1) vision6 = "hidden"

            setView4((view4) => !view4)

        }

    }

    async function turnterms() {

        if (vision7 === "visible" && vision5 === "visible" && vision2 === "visible") {

            try {

                // @ts-ignore

                cookie.save("email", document.getElementById("emailInput").value , {

                    path: "/",

                })

                // @ts-ignore

                const PW = document.getElementById("passwordInput").value

                cookie.save("password", PW, {

                    path: "/register-terms"

                })

                // @ts-ignore

                cookie.save("nickname", document.getElementById("nickNameInput").value, {

                    path: "/register-terms"

                })

                const res = await axios.post(`${config.host}/users/register/validation`, {

                    // @ts-ignore

                    account : document.getElementById("emailInput").value

                })

                if (res.data) {

                    document.location.href = "/register/validation"

                }

            } catch (e){

                console.log("ERROR IS: "+e)

            }

           

        } else if (vision7 === "hidden"){

            alert("비밀번호 양식이 맞지 않습니다.")

        } else if (vision5 === "hidden") {

            alert("현재 입력된 username은 사용하실 수 없습니다.")

        } else if (vision2 === "hidden"){

            alert("현재 입력된 email은 사용하실 수 없습니다.")

        } else {

            alert(vision2 + vision5 + vision7)

        }

    }

    return (

        <div id="regform" style={{height: "0px", display: "inherit", position: "relative", top: "-630px", left: "494px"}}>

            <input type="email" id="emailInput" placeholder="Email" onInput={() => emailCheck()} style={{color: vision==="hidden" ? "#FFFFFF" : "#B7312E", position: "relative", left: "-465px", top: "197px", width: "255px", background: "transparent", border: "0px", fontSize: "17px"}} autoComplete="off"></input>

            <div id="regLine1" style={{border: vision==="hidden" ? "0.5px solid #FFFFFF80" : "0.5px solid #B7312E"}}></div>

            <div id="oksign" style={{visibility : vision2 === "hidden" ? "hidden" : "visible"}}><img src={checkImg} id="okimg"></img></div>

            <img id="clearButton" src={clearImg} onClick={() => ClearEmail()} style={{visibility : vision === "hidden" ? "hidden" : "visible" ,clear:"both", position: "relative", height: "22px", width: "22px", left: "-185px", top: "152px", borderRadius: "20px",  cursor: "pointer"}}></img>

            <div id="alertMent" style={{position: "relative", left: "-465px",top: "166px", visibility: vision3 === "hidden" ? "hidden" : "visible", color: "#B7312E"}}>사용 불가능한 메일주소입니다.</div>

            <input type="text" style={{color : vision4==="hidden" ? "#FFFFFF" : "#B7312E"}} id="nickNameInput" placeholder="User Name" onChange={() => nickNameCheck()} autoComplete="off"></input>

            <div id="regLine2" style={{border: vision4==="hidden" ? "0.5px solid #FFFFFF80" : "0.5px solid #B7312E"}}></div>

            <div id="oksign2" style={{visibility : vision5 === "hidden" ? "hidden" : "visible"}}><img src={checkImg} id="okimg"></img></div>

            <img id="clearButton2" src={clearImg} onClick={() => ClearName()} style={{visibility : vision4 === "hidden" ? "hidden" : "visible", clear:"both", position: "relative", height: "22px", width: "22px", left: "-185px", top: "140px", borderRadius: "20px", cursor: "pointer"}}></img>

            {/* @ts-ignore */}

            <div id="alertMent2" style={{position: "relative", left: "-465px",top: "150px", visibility: vision4 === "hidden" ? "hidden" : "visible", color: "#B7312E"}}>사용자 이름 {document.getElementById("nickNameInput") === null ? "" : document.getElementById("nickNameInput").value}을(를) 사용할 수 없습니다.</div>

            <input type="password" style={{color : vision6==="hidden" ? "#FFFFFF" : "#B7312E"}} id="passwordInput" placeholder="Password" onInput={() => checkPW()}></input>

            <div id="regLine3" style={{border: vision6==="hidden" ? "0.5px solid #FFFFFF80" : "0.5px solid #B7312E"}}></div>

            <div id="oksign3" style={{visibility : vision7 === "hidden" ? "hidden" : "visible"}}><img src={checkImg} id="okimg"></img></div>

            <img id="clearButton3" src={clearImg} onClick={() => ClearPW()} style={{visibility : vision6 === "hidden" ? "hidden" : "visible", clear:"both", position: "relative", height: "22px", width: "22px", left: "-185px", top: "123px", borderRadius: "20px", cursor: "pointer"}}></img>

            <div id="pwrule">* 8~16자 영문, 숫자, 특수문자를 사용하세요.</div>

            <div id="nextBtn" onClick={() => turnterms()}>Next</div>

        </div>

    )

}

export default RegisterComponent

일단 현재는 이렇게
<span className="notranslate"><input /></span>
스팬태그로 감싸서 크롬 자동번역기능을 활성화 시켜도 번역이 안되게 해서 에러를 막고 있습니다.
그런데 정확한 에러의 원인을 아직도 모르겠습니다. 한국어 자동번역 기능을 사용하면 DOM에 어떤 영향이 가는 건지, 아니면 다른 부분의 문제인지 궁금합니다.

감사합니다.

크롬 번역기능 활성화 시 에러난다는 것과 무관하긴 하지만 올려주신 react 코드에서 react 답게 사용하지 못한 부분이 보여 댓글 남깁니다.

컴포넌트가 return하는 <input에 id를 지정하고 이를 document api로 직접 value를 바꾸지기 보다는 ref prop을 이용해서 접근한다거나 value를 state로 둬서 보여지는 값을 조작하는 것이 좋습니다.

다음 react 공식 문서에 해당 예가 있습니다…

네, value를 state로 설정해서 값을 줄 수도 있네요. 하나 배웠습니다. 감사합니다! ㅎㅎ.