개발자

엔터키를 감지를 두번하는것같아요

2023년 07월 17일조회 616

로그인 창을 만들고 있는데요 id인풋칸에서 엔터를 눌렀을때 pw칸으로 또 엔터를 눌렀을때 로그인 함수를 실행시키려 합니다 하지만 id 인풋칸에서 엔터를 누를시 로그인 함수가 실행됩니다. id칸에서 글자를 입력후 다시 id칸을 마우스로 터치해야 먹히더라고요 왜인지 코드 한번만 봐주세요 제발 부탁드립니다

1import Head from 'next/head'
2import styles from '@/styles/Login.module.css'
3import Link from "next/link";
4import {useRef, useState} from "react";
5import axios from "axios";
6import {toast, ToastContainer} from "react-toastify"
7import "react-toastify/dist/ReactToastify.css"
8
9export default function Login() {
10    const [id, setId] = useState('')
11
12    const [pw, setPw] = useState('')
13
14    const inputRef = useRef<HTMLInputElement>(null)
15
16    const login = () => {
17        inputRef.current?.blur()
18        axios.post('/api/login', {
19            id: id,
20            pw: pw
21        }).then((res) => {
22            if (!res.data.success) return;
23            window.location.href = '/'
24        }).catch((err) => {
25            if (err.response.data.message) {
26                toast.error(err.response.data.message);
27            } else {
28                toast.error('서버에 오류가 발생했습니다.');
29            }
30        })
31        setId('')
32        setPw('')
33    }
34
35    return (
36        <>
37            <Head>
38                <meta name="viewport" content="width=device-width, initial-scale=1"/>
39                <link rel="icon" href="/favicon.ico"/>
40                <title>문시장 - 문학을 시작하는 장소</title>
41                <meta property="og:title" content="문시장!"/>
42                <meta property="og:description" content="다양한 문학을 접하고 시작하는 장소!"/>
43                <meta property="og:image" content="/background.png"/>
44                <meta property="og:type" content="website"/>
45                <meta property="og:site_name" content="문시장"/>
46                <meta property="og:locale" content="ko_KR"/>
47            </Head>
48
49            <main>
50                <div className={styles.background}>
51                    <ToastContainer
52                        position="top-right"
53                        autoClose={1000}
54                    />
55                    <div className={styles.card}>
56                        <div className={styles.flex_left}>
57                            <Link className={`${styles.back} ${styles.flex_left}`} href={'/'}>◀ 뒤로가기</Link>
58                            <Link className={`${styles.back} ${styles.flex_right}`} href={'/register'}>회원가입 ▶</Link>
59                        </div>
60                        <div className={styles.padding}>
61                            <div className={styles.flex_center}>
62                                <h1 className={styles.title}>문시장</h1>
63                            </div>
64
65                            <div className={styles.flex_column_center}>
66                                <h1 className={styles.input_message}>아이디</h1>
67                                <input className={`${styles.input}`}
68                                       onChange={(e) => setId(e.target.value)}
69                                       value={id}
70                                       onKeyDown={(e) => {
71                                           e.preventDefault();
72                                           if (e.key === 'Enter') {
73                                               inputRef.current?.focus()
74                                           }
75                                       }}
76                                />
77                            </div>
78
79                            <div className={styles.flex_column_center}>
80                                <h1 className={styles.input_message}>비밀번호</h1>
81                                <input className={`${styles.input}`}
82                                       ref={inputRef}
83                                       onChange={(e) => setPw(e.target.value)}
84                                       value={pw}
85                                       onKeyDown={(e) => {
86                                           e.preventDefault();
87                                           if (e.key === 'Enter') {
88                                               login()
89                                           }
90                                       }}
91                                />
92                            </div>
93
94                            <div className={styles.flex_column_center}>
95                                <button className={styles.button}
96                                        onClick={() => {
97                                            login()
98                                        }}
99                                >로그인
100                                </button>
101                            </div>
102                        </div>
103                    </div>
104                </div>
105            </main>
106        </>
107    )
108}
이 질문이 도움이 되었나요?
'추천해요' 버튼을 누르면 좋은 질문이 더 많은 사람에게 노출될 수 있어요. '보충이 필요해요' 버튼을 누르면 질문자에게 질문 내용 보충을 요청하는 알림이 가요.

답변 4

조용구님의 프로필 사진

안녕하세요 :) 왠지 onKeyDown쪽이 의심되는데, 아이디에 onKeyDown을 onKeyUp으로 바꿔서 해보실래요??

조용구님의 프로필 사진

조용구

Senior Front-end Engineer2023년 07월 18일

헛 그렇군여 ㅠㅠ 이렇게 했을때 아이디 입력 박스에서 엔터하면 비밀번호 입력 박스로 이동되는데, 확인 부탁드립니다 :) https://jsfiddle.net/ykb12vrh/3/

민규님의 프로필 사진

민규

작성자

코리아it아카데미 웹2023년 07월 18일

해당사이트도 똑같은 증상이 일어나네요 ㅠㅠ

민규님의 프로필 사진

민규

작성자

코리아it아카데미 웹2023년 07월 18일

다른분 의견을 따라 한글 영어 체크를 해봤는데 한글만 일어나는 증상이네요 한글로 했을때도 정상작동되게 하는방법 없을까요

조용구님의 프로필 사진

조용구

Senior Front-end Engineer2023년 07월 18일

아마도 제 데스크톱이랑 환경이 다른가보군여 ㅠㅠ 한글 이슈라면 onChange를 onInput으로 바꿔서 테스트 해보실래여?? 이것 말고는 떠오르는게 없네여

김하림님의 프로필 사진

엔터키를 연동하는 대신에 form 태그 사용을 제안드립니다. `<form>` 태그를 사용하면 엔터키를 눌렀는지 감지할 필요가 없으며, 로그인과 같이 사용자가 입력한 양식을 서버에 제출하는 상황에서 웹 표준으로 권장되는 방식입니다. 요구사항을 코드로 옮길 때는 W3C에서 합의한 웹표준을 지키며 코드를 구현하도록 작성하는 것이 좋습니다. 첨부한 코드는 작성하신 코드를 `form` 기반으로 변경한 코드입니다.

1import Head from 'next/head'
2import styles from '@/styles/Login.module.css'
3import Link from "next/link";
4import {useRef, useState} from "react";
5import axios from "axios";
6import {toast, ToastContainer} from "react-toastify"
7import "react-toastify/dist/ReactToastify.css"
8
9export default function Login() {
10    const [id, setId] = useState('')
11    const [pw, setPw] = useState('')
12
13    const inputRef = useRef<HTMLInputElement>(null)
14
15    const handleLogin = (event) => {
16        event.preventDefault();
17        inputRef.current?.blur()
18        axios.post('/api/login', {
19            id: id,
20            pw: pw
21        }).then((res) => {
22            if (!res.data.success) return;
23            window.location.href = '/'
24        }).catch((err) => {
25            if (err.response.data.message) {
26                toast.error(err.response.data.message);
27            } else {
28                toast.error('서버에 오류가 발생했습니다.');
29            }
30        })
31        setId('')
32        setPw('')
33    }
34
35    return (
36        <>
37            <Head>
38                <meta name="viewport" content="width=device-width, initial-scale=1"/>
39                <link rel="icon" href="/favicon.ico"/>
40                <title>문시장 - 문학을 시작하는 장소</title>
41                <meta property="og:title" content="문시장!"/>
42                <meta property="og:description" content="다양한 문학을 접하고 시작하는 장소!"/>
43                <meta property="og:image" content="/background.png"/>
44                <meta property="og:type" content="website"/>
45                <meta property="og:site_name" content="문시장"/>
46                <meta property="og:locale" content="ko_KR"/>
47            </Head>
48
49            <main>
50                <div className={styles.background}>
51                    <ToastContainer
52                        position="top-right"
53                        autoClose={1000}
54                    />
55                    <div className={styles.card}>
56                        <div className={styles.flex_left}>
57                            <Link className={`${styles.back} ${styles.flex_left}`} href={'/'}>◀ 뒤로가기</Link>
58                            <Link className={`${styles.back} ${styles.flex_right}`} href={'/register'}>회원가입 ▶</Link>
59                        </div>
60                        <form onSubmit={handleLogin} className={styles.padding}>
61                            <div className={styles.flex_center}>
62                                <h1 className={styles.title}>문시장</h1>
63                            </div>
64
65                            <div className={styles.flex_column_center}>
66                                <h1 className={styles.input_message}>아이디</h1>
67                                <input className={`${styles.input}`}
68                                       onChange={(e) => setId(e.target.value)}
69                                       value={id}
70                                />
71                            </div>
72
73                            <div className={styles.flex_column_center}>
74                                <h1 className={styles.input_message}>비밀번호</h1>
75                                <input className={`${styles.input}`}
76                                       ref={inputRef}
77                                       onChange={(e) => setPw(e.target.value)}
78                                       value={pw}
79                                />
80                            </div>
81
82                            <div className={styles.flex_column_center}>
83                                <button className={styles.button}
84                                        type="submit"
85                                >로그인
86                                </button>
87                            </div>
88                        </form>
89                    </div>
90                </div>
91            </main>
92        </>
93    )
94}
민규님의 프로필 사진

민규

작성자

코리아it아카데미 웹2023년 07월 18일

해당코드로 하면 패스워드칸에서 엔터시 보내기가 안되지 않나요 네이버처럼 엔터시 보내기 같은 기능을 하고싶어서요

최승윤님의 프로필 사진

최승윤

모션원 프론트엔드 개발자2023년 07월 19일

<form>을 쓰면 자동으로 엔터키 감지가 됩니다.

삭제된 사용자님의 프로필 사진

삭제된 사용자

2023년 07월 18일

혹시 id 값으로 한글 사용하실까요?

민규님의 프로필 사진

민규

작성자

코리아it아카데미 웹2023년 07월 18일

네 한글로 사용중입니다 영어로 해보니깐 잘되네요 ;ㅅ; 한글했을때도 똑같이 하고싶은데 방법이 없을까요

커리어리 AI 봇님의 프로필 사진

문제가 발생하는 이유는 `id` 인풋칸에서 엔터를 눌렀을 때 `inputRef.current?.focus()`를 호출하여 다시 `id` 인풋칸에 포커스를 맞추기 때문입니다. 이로 인해 `id` 인풋칸에 다시 엔터를 눌러도 로그인 함수가 실행되지 않고 포커스만 다시 맞춰지게 됩니다. 해결하기 위해서는 `id` 인풋칸에서 엔터를 눌렀을 때 다음 인풋칸인 `pw` 인풋칸으로 포커스를 이동하고, `pw` 인풋칸에서 엔터를 눌렀을 때 로그인 함수를 실행하도록 수정해야 합니다. 이를 위해 다음과 같이 코드를 수정할 수 있습니다: 아래와 같이 수정하면 `id` 인풋칸에서 엔터를 누르면 `pw` 인풋칸으로 포커스가 이동하고, `pw` 인풋칸에서 엔터를 누르면 로그인 함수가 실행됩니다. 주의할 점은 `e.preventDefault()`를 사용하여 엔터 키의 기본 동작인 폼 제출을 막아야 한다는 것입니다. 이를 통해 엔터 키를 눌렀을 때 원치 않는 동작이 발생하는 것을 방지할 수 있습니다.

1<input className={`${styles.input}`}
2    onChange={(e) => setId(e.target.value)}
3    value={id}
4    onKeyDown={(e) => {
5        if (e.key === 'Enter') {
6            e.preventDefault();
7            inputRef.current?.focus(); // pw 인풋칸으로 포커스 이동
8        }
9    }}
10/>
11
12<input className={`${styles.input}`}
13    ref={inputRef}
14    onChange={(e) => setPw(e.target.value)}
15    value={pw}
16    onKeyDown={(e) => {
17        if (e.key === 'Enter') {
18            e.preventDefault();
19            login(); // 로그인 함수 실행
20        }
21    }}
22/>

커리어리 AI 봇의 답변을 평가해 주세요!

지금 가입하면 모든 질문의 답변을 볼 수 있어요!

현직자들의 명쾌한 답변을 얻을 수 있어요.

또는

이미 회원이신가요?

목록으로

지금 가입하면 모든 질문의 답변을 볼 수 있어요!