[๋ฆฌ์•กํŠธ] ๋‚ด๋น„๊ฒŒ์ด์…˜ ๋ฐ” ๊ฒ€์ƒ‰ ๊ตฌํ˜„ (feat. <form> ํƒœ๊ทธ , ํ•„์š”ํ•œ ์ˆœ๊ฐ„์€?)

2025. 8. 19. 20:14ใ†React

๋‚ด๋น„๊ฒŒ์ด์…˜ ๋ฐ”์—์„œ ํŠน์ • ํ‚ค์›Œ๋“œ๋กœ ๊ฒ€์ƒ‰์„ ์‹œ๋„ํ•˜๋ฉด, ๊ฒ€์ƒ‰ ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•œ ๋’ค ํ•ด๋‹น ํ‚ค์›Œ๋“œ์— ๋งž๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ํ™”๋ฉด์— ํ‘œ์‹œํ•˜๋Š” ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ–ˆ์Šต๋‹ˆ๋‹ค.

์ด๋ฒˆ ํฌ์ŠคํŠธ์—์„œ๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ ๊ฒ€์ƒ‰์–ด๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ API ์š”์ฒญ์„ ๋ณด๋‚ด๊ณ , ์‘๋‹ต ๋ฐ์ดํ„ฐ๋ฅผ ํ™”๋ฉด์— ์ถœ๋ ฅํ•˜๋Š” ๊ณผ์ •์—์„œ ๋งˆ์ฃผ์ณค๋˜ ๋ฌธ์ œ๋“ค๊ณผ ์ด๋ฅผ ํ†ตํ•ด ์–ป์€ ์ธ์‚ฌ์ดํŠธ๋ฅผ ์ •๋ฆฌํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

 

์ตœ์ข… UI

๊ฒ€์ƒ‰ ๊ณผ์ •

์ด๋ฒคํŠธ ๋™์ž‘ ์ •์˜ํ•˜๊ธฐ

์ž…๋ ฅ ๊ฐ’์— ๋”ฐ๋ฅธ ๋ณ‘์› ์ •๋ณด ์ถœ๋ ฅ

์‚ฌ์šฉ์ž๊ฐ€ input ํƒœ๊ทธ์— ๊ฐ’์„ ์ž…๋ ฅํ•œ ๋’ค ๊ฒ€์ƒ‰ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๊ฑฐ๋‚˜ Enter ํ‚ค๋ฅผ ๋ˆ„๋ฅด๋ฉด, ํ•ด๋‹น ์ด๋ฒคํŠธ๋ฅผ ๊ธฐ์ค€์œผ๋กœ ํŽ˜์ด์ง€๊ฐ€ ์ด๋™ํ•˜๊ณ  ์ž…๋ ฅํ•œ ํ‚ค์›Œ๋“œ๋ฅผ ์ด์šฉํ•ด API ์š”์ฒญ์ด ์ˆ˜ํ–‰๋˜์–ด ํŠน์ • ๋ณ‘์› ๋ฐ์ดํ„ฐ๋ฅผ ๊ฒ€์ƒ‰ํ•ฉ๋‹ˆ๋‹ค.

 

์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ ๊ตฌํ˜„ํ•˜๊ธฐ 

๋ฐ์ดํ„ฐ ์ž…๋ ฅํ•˜๊ธฐ 

 

๐Ÿ“— ์ฐธ๊ณ  ์ž๋ฃŒ

 

input ํƒœ๊ทธ ์‚ฌ์šฉ ์‹œ form ํƒœ๊ทธ ์‚ฌ์šฉ ์—ฌ๋ถ€ - ์ธํ”„๋Ÿฐ | ์ปค๋ฎค๋‹ˆํ‹ฐ ์งˆ๋ฌธ&๋‹ต๋ณ€

๋ˆ„๊ตฌ๋‚˜ ํ•จ๊ป˜ํ•˜๋Š” ์ธํ”„๋Ÿฐ ์ปค๋ฎค๋‹ˆํ‹ฐ. ๋ชจ๋ฅด๋ฉด ๋ฌป๊ณ , ํ•ด๋‹ต์„ ์ฐพ์•„๋ณด์„ธ์š”.

www.inflearn.com

 

๊ธฐ์กด์— ๊ฒ€์ƒ‰ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•  ๋•Œ์—๋Š” ๊ฒ€์ƒ‰์€ ๊ณง submit์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜์—ฌ input ํƒœ๊ทธ๋ฅผ form ํƒœ๊ทธ ์•ˆ์— ๋„ฃ์–ด ๊ตฌํ˜„ํ–ˆ์Šต๋‹ˆ๋‹ค.

 

๊ทธ๋Ÿฌ๋˜ ์ค‘, input ํƒœ๊ทธ์— ์ž…๋ ฅ๋œ ๊ฐ’์„ form ํƒœ๊ทธ์—์„œ ์–ด๋–ป๊ฒŒ ์ฝ์–ด์˜ค๋Š”์ง€ ๊ถ๊ธˆํ•˜์—ฌ ๊ด€๋ จ ์ž๋ฃŒ๋ฅผ ์ฐพ์•„๋ณด๋˜ ์ค‘ ์ธํ”„๋Ÿฐ ์ปค๋ฎค๋‹ˆํ‹ฐ์—์„œ ์œ ์šฉํ•œ ๋‚ด์šฉ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ๋‚ด์šฉ์€ ์•„๋ž˜์™€ ๊ฐ™์•˜์Šต๋‹ˆ๋‹ค. 

 

form ํƒœ๊ทธ ์‚ฌ์šฉ ์‹œ ์žฅ์ 

input ํƒœ๊ทธ์— id๊ฐ€ ํ• ๋‹น๋˜์–ด ์žˆ์œผ๋ฉด, State์— ๋”ฐ๋กœ ๊ฐ’์„ ์ €์žฅํ•˜์ง€ ์•Š์•„๋„ submit ์ด๋ฒคํŠธ ๋ฐœ์ƒ ์‹œ ์ž๋™์œผ๋กœ ๊ฐ’์„ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. (์•„๋ž˜ ์ฝ”๋“œ ์ฐธ๊ณ )

 

โžก๏ธ ์ฆ‰, ํšŒ์›๊ฐ€์ž…์ฒ˜๋Ÿผ ๋งŽ์€ input์ด ํฌํ•จ๋˜์–ด ์žˆ๊ณ  ๊ตณ์ด ๊ฐ’์„ State์— ์ €์žฅํ•  ํ•„์š”๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ์— form ๋ฐ์ดํ„ฐ๋ฅผ ํ™œ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค.

 

๐Ÿ‘‰๐Ÿป ์ฝ”๋“œ ๋ณด๊ธฐ

๋”๋ณด๊ธฐ
import "./styles.css";

export default function App() {
  const onSubmit = (e) => {
    const firstValue = e.target.first.value;
    const secondValue = e.target.second.value;

    console.log({ firstValue, secondValue });
    e.preventDefault();
  };

  return (
    <form onSubmit={onSubmit}>
      <div>
        <input id="first" />
      </div>
      <div>
        <input id="second" />
      </div>
      <div>
        <button type="submit">Submit</button>
      </div>
    </form>
  );
}

 

 

์„ ํƒํ•œ ๋ฐฉ๋ฒ•

์ด๋ฒˆ ๊ฒ€์ƒ‰ ๊ธฐ๋Šฅ ๊ตฌํ˜„์—์„œ๋Š” ์˜ค์ง ํ•˜๋‚˜์˜ input๋งŒ ํฌํ•จ๋˜์–ด ์žˆ์—ˆ๊ธฐ ๋•Œ๋ฌธ์— form ํƒœ๊ทธ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  input ํƒœ๊ทธ๋งŒ ํ™œ์šฉํ•˜์—ฌ ๊ตฌํ˜„ํ•˜๊ธฐ๋กœ ๊ฒฐ์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.

 

 

๊ฒ€์ƒ‰์–ด ์ž…๋ ฅ ๋ฐ ํŽ˜์ด์ง€ ์ด๋™

์‚ฌ์šฉ์ž๊ฐ€ ๋„ค๋น„๊ฒŒ์ด์…˜ ๋ฐ”์—์„œ ๊ฒ€์ƒ‰์–ด๋ฅผ ์ž…๋ ฅํ•˜๋ฉด ํ•ด๋‹น ๊ฒ€์ƒ‰์–ด์™€ ํ•จ๊ป˜ ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค.

function handleSearchSubmit(searchKeyword, navigate) {
        navigate(`/search?q=${searchKeyword}`) //ํŽ˜์ด์ง€ ์ด๋™
}

 

๐Ÿ’ก Enter ์ธ์‹ ๋ฐฉ๋ฒ•

๋”๋ณด๊ธฐ

onKeyDown์€ ํ‚ค ๋ˆ„๋ฆ„ ์ด๋ฒคํŠธ๋ฅผ ๊ฐ์ง€ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋Š” ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ์ž…๋‹ˆ๋‹ค.  

 

๐Ÿ“— ์ฐธ๊ณ ์ž๋ฃŒ

 

React onKeyDown Event - GeeksforGeeks

Your All-in-One Learning Portal: GeeksforGeeks is a comprehensive educational platform that empowers learners across domains-spanning computer science and programming, school education, upskilling, commerce, software tools, competitive exams, and more.

www.geeksforgeeks.org

 

  • ํ‚ค ๋ˆ„๋ฆ„ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ ํ•ด๋‹น key๊ฐ€ Enter๋ผ๋ฉด ์ด๋ฒคํŠธ๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.
  • Enter ํ‚ค๋ฟ๋งŒ ์•„๋‹ˆ๋ผ Space, Tab ๋“ฑ์˜ ํ‚ค์—๋„ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. 
onKeyDown={(e) => e.key === "Enter" ? "์ด๋ฒคํŠธ ํ˜ธ์ถœ": null}

URL ํŒŒ๋ผ๋ฏธํ„ฐ ํ™œ์šฉํ•ด API ์š”์ฒญ

๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ํŽ˜์ด์ง€์—์„œ๋Š” useSearchParams๋ฅผ ์‚ฌ์šฉํ•ด URL์˜ ํŒŒ๋ผ๋ฏธํ„ฐ ๊ฐ’์„ ๊ฐ€์ ธ์˜ค๊ณ  ํ•ด๋‹น ๊ฐ’์œผ๋กœ API ์š”์ฒญ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

 

๐Ÿ’ก useSearchParams

URL์˜ ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ฝ๊ณ  ์„ค์ •ํ•˜๋Š” ๋„๊ตฌ์ž…๋‹ˆ๋‹ค. 

 

๐Ÿ“— ์ฐธ๊ณ  ์ž๋ฃŒ

 

[React.js] useSearchParams ํ›… (React Router)

useSearchParams ํ›… (React Router)๋“ค์–ด๊ฐ€๋ฉฐ๋ฆฌ์•กํŠธ ๋ผ์šฐํ„ฐ(React Router)์—์„œ ์ œ๊ณตํ•˜๋Š” @useSearchParams@ ํ›…์— ๋Œ€ํ•ด ์ •๋ฆฌํ•ด๋ณธ๋‹ค. useSearchParams๊ฐœ๋…๋ฆฌ์•กํŠธ ๋ผ์šฐํ„ฐ(React Router)๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ URL์˜ ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ฝ

dev-astra.tistory.com

 

์‚ฌ์šฉ๋ฒ•์€ ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์˜ˆ: /search?keyword=banana

import { useSearchParams  } from 'react-router-dom';

const [searchParams, setSearchParams] = useSearchParams();
const keyword = searchParams.get("keyword"); //URL์˜ ํŒŒ๋ผ๋ฏธํ„ฐ ๊ฐ’์„ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

 

๐Ÿ‘‰๐Ÿป ์ฝ”๋“œ 

๋”๋ณด๊ธฐ

ClinicSearchResultPage.jsx

import { useSearchParams  } from 'react-router-dom';
import { fetchSearchClinicByQuery } from '../api';

function ClinicSearchResultPage() {

    const [searchParams, setSearchParams] = useSearchParams();

    useEffect(() => {
            const keyword = searchParams.get("q");
            fetchSearchClinicByQuery(keyword, currentPage)
            .then((res) => {
                console.log(res.data);
                setTotalPages(res.data.page.totalPages)
                setSearchResult(res.data.content)
            })
        }, [searchParams, currentPage])

        ... ์ƒ๋žต

}

 

api.js (api ์š”์ฒญ์„ ๋‹ด๋‹นํ•˜๋Š” ํŒŒ์ผ)

export function fetchSearchClinicByQuery(searchKeyword, navigate) {
    const token = localStorage.getItem("accessToken")?.trim();
    
    return api.get(
        "/search",
        {
            params : {
                "p": `${searchKeyword}`
            },
            headers: {
                "Authorization": `Bearer ${token}`
            },
        },

    )
}

 

 

์‘๋‹ต ๋ฐ์ดํ„ฐ ๋ Œ๋”๋ง

API ์‘๋‹ต์œผ๋กœ ๋ฐ›์€ ๋ฐ์ดํ„ฐ๋ฅผ ํ™”๋ฉด์— ํ‘œ์‹œํ•˜์—ฌ ์‚ฌ์šฉ์ž๊ฐ€ ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ๋ฅผ ๋ณผ ์ˆ˜ ์žˆ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค. 

 

๊ฒ€์ƒ‰์–ด ๋ณ€๊ฒฝ ์‹œ ํŽ˜์ด์ง€๋Š” ์œ ์ง€, ํŒŒ๋ผ๋ฏธํ„ฐ๋งŒ ๋ณ€๊ฒฝ

์‚ฌ์šฉ์ž๊ฐ€ ๋„ค๋น„๊ฒŒ์ด์…˜ ๋ฐ”์—์„œ ์ƒˆ๋กœ์šด ํ‚ค์›Œ๋“œ๋ฅผ ์ž…๋ ฅํ•˜๋ฉด ํŽ˜์ด์ง€๋Š” ๊ทธ๋Œ€๋กœ ๋‘๊ณ  URL ํŒŒ๋ผ๋ฏธํ„ฐ๋งŒ ๋ณ€๊ฒฝ๋ฉ๋‹ˆ๋‹ค. 

 

ํŒŒ๋ผ๋ฏธํ„ฐ ๋ณ€๊ฒฝ ๊ฐ์ง€ ํ›„ API ์žฌํ˜ธ์ถœ

useEffect ํ›…์„ ์‚ฌ์šฉํ•˜์—ฌ ํŒŒ๋ผ๋ฏธํ„ฐ ๊ฐ’์ด ๋ณ€๊ฒฝ๋  ๋•Œ๋งŒ API๋ฅผ ๋‹ค์‹œ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.

์ด๋ฅผ ํ†ตํ•ด ํŽ˜์ด์ง€ ์ „์ฒด๊ฐ€ ์ƒˆ๋กœ ๋ Œ๋”๋ง ๋˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ๋ฐ์ดํ„ฐ๋งŒ ์—…๋ฐ์ดํŠธ๋ฉ๋‹ˆ๋‹ค.