NodeJS ๋ฐ React ๐๋ฅผ ์ฌ์ฉํ์ฌ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ๋์ ๊ฒ์ ์๋ ์์ฑ ์ถ๊ฐ
์๊ฐ
Google์ ์๋ ์์ฑ ๊ฒ์ ํ์์ค์ด ์ ๋ ฅํ ๋ ๋ค์ ํค ์ ๋ ฅ์ ์์ธกํ๋ ๊ฒ์ ๋ณด์ จ์ ๊ฒ์ ๋๋ค.
๊ทธ๋์ ์ ๋ ํ๋๋ฅผ ๋ง๋ค๊ณ ์ ๊ฐ ๋ฐ๊ฒฌํ ๊ฒ์ ์ฌ๋ฌ๋ถ ๋ชจ๋์ ๊ณต์ ํ ์๊ฐ์ ํ์ต๋๋ค.
์์ํ์ ๐
Google์ ๊ฒ์ ์๋์์ฑ API
๋๋ ์ฌ์ฉ์๊ฐ ํ์ดํ์ ์์ํ๊ณ ์ผ๋ถ ๊ฒ์ ์ ์์ด ๊ทธ์ ์ผ๊ตด(๋ฌผ๋ก div์์)์ ๋ ์์ค๋ ์ด๋ฐ ์ข ๋ฅ์ ๊ฒ์ ๊ตฌํํด์ผ ํ๋ ์ฑ์ ๋ง๋ค๊ณ ์์์ต๋๋ค. ๊ทธ๋์ ๋ช ๊ฐ์ง ๋ฌด๋ฃ API๋ฅผ ์ฐพ๊ธฐ ์ํด Google์์ ๋ฐฉํฉํ๊ธฐ ์์ํ์ต๋๋ค. ํ์คํธ์์ this ์คํ ์ค๋ฒํ๋ก ํ ๋ก ์ ์ฐ์ฐํ ๋ฐ๊ฒฌํ์ต๋๋ค. ์ฌ์ฉํ๋๋ก ์ ์๋ ๋ต๋ณ ์ค ํ๋๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
https://www.google.com/complete/search?client=hp&hl=en&sugexp=msedr&gs_rn=62&gs_ri=hp&cp=1&gs_id=9c&q=a&xhr=t&callback=hello
์ด๊ฒ์ ๊ธฐ๋ณธ์ ์ผ๋ก google.com ์์ฒด๊ฐ ๊ฒ์ ์ ์์ ์ฌ์ฉํ๋ URL์ ๋๋ค.
API ๋์
์ด์ ํ ์คํธ ๋ธ๋ผ์ฐ์ ํ๊ฒฝ์์ Google์ API์ ๋ํ ์ผ๋ถ GET ์์ฒญ์ ์์ฑํด ๋ณด๊ฒ ์ต๋๋ค. ์ ๋ codesandbox.io๊ฐ ์ด๋ฌํ ์์ ์ ์ํ ๋น ๋ฅธ ํธ์คํ ์น ํ๊ฒฝ์ ์ค์ ํ๋ ๊ฐ์ฅ ์ข์ ๋ฐฉ๋ฒ์ด๋ผ๋ ๊ฒ์ ์์์ต๋๋ค.
๊ทธ๋ฆฌ๊ณ .....์๋ก๊ณ ์นจ!
ํ , ์ด๊ฒ์ CORS ์ค๋ฅ์ ๋๋ค. NodeJS๋ก ์์ ํ๋ ๋ฐฉ๋ฒ์ ์๊ณ ์๋ ๊ฒฝ์ฐ์๋ง ๋น๊ต์ ์ฝ๊ฒ ๊ณ ์น ์ ์์ต๋๋ค. ;)
"๋ฐฉ๊ธ ๋ฌด์จ ์ผ์ด์ผ?"
์ด๋ฌํ ์ค๋ฅ๋ ํค๋
Access-Control-Allow-Origin
๊ฐ ์์ ๋ ๋ฐ์ํฉ๋๋ค. ์ด ํค๋๊ฐ ์๋ ์์ฒญ์ ์๋ต์ ์์ฒญ์ด 200 OK๋ฅผ ๋ฐํํ๋๋ผ๋ ๋ธ๋ผ์ฐ์ ์ ์ํด ์ฐจ๋จ๋ฉ๋๋ค.The Access-Control-Allow-Origin response header indicates whether the response can be shared with requesting code from the given origin.
์ด ํค๋here์์ ์์ธํ ๋ด์ฉ์ ์ฐพ์ผ์ญ์์ค. ์ด ์ค๋ฅ๋ ๋ธ๋ผ์ฐ์ ํ๊ฒฝ์์๋ง ๋ฐ์ํฉ๋๋ค. ๋ฐ๋ผ์ ์ด์ ์ด ์์ฒญ ์์ฑ ์ฝ๋ ๋ธ๋ก์ ๋ ธ๋ ํ๊ฒฝ์ผ๋ก ์ ํํ ๋ค์ ๋ ธ๋ API ๋์ ์ ๋ํ ์์ฒญ ํด๋ผ์ด์ธํธ์ ๋ํ ์๋ต์ ๋ฐํํฉ๋๋ค.
๋ํ ์ฐ์ฒด๋ถ ๋๋ ๋ถ๋ฉด์ฆ๊ณผ ๊ฐ์ด ๋ก์ปฌ ์์คํ ์ผ๋ก GET ์์ฒญ์ ํ๋ ๊ฒฝ์ฐ์๋ ๋ง์ฐฌ๊ฐ์ง์ ๋๋ค. ์ง์ ๋ URL ์ธ์ฝ๋ฉ ์ฟผ๋ฆฌ์ ๋ํด ์ ์์ ์ธ ์๋ต์ ๋ฐํํฉ๋๋ค
q
.์ด์ ๊ฒ์ ์ ์์ ๋ฐ๊ณ ์ด๋ฅผ JSON ์๋ต์ผ๋ก ๋ฐํํ๋๋ก ๋ ธ๋ ์๋ํฌ์ธํธ๋ฅผ ์ฝ๋ฉํด ๋ณด๊ฒ ์ต๋๋ค.
ํธ์คํ ํ๊ฒฝ์ ์ฆ์ ๋ฐฐํฌ๋๋ ๋น ๋ฅธ ์ฝ๋ ์ค๋ํซ์ ์ํด ์ ๋ ์ข ์ข replit.com์ ์ฌ์ฉํ๊ณ ์ถ์ต๋๋ค.
์ด ์ฝ๋์์๋
express
(์น ์๋ฒ ๊ฐ๋์ฉ) ๋ฐ axios
(์ธํฐ๋ท์ ํตํด ์์ค์ ๋ํ GET/POST ์์ฒญ ์์ฑ์ฉ)์ ๊ฐ์ ธ์์ต๋๋ค.๊ทธ๋ฐ ๋ค์ ์ต์คํ๋ ์ค ์๋ฒ/์ฑ์ ์ด๊ธฐํํ๊ณ
.get(url, (request, response) => {})
๋ฉ์๋๋ก API GET ENDPOINT๋ฅผ ์ ์ํ๊ณ axios
๋ก Google์ API์ GET ์์ฒญ์ ๋ง๋ค๊ณ ๋ฐํ๋ ์ ์ ๋ฐ์ดํฐ๋ฅผ ์์ฒญ ํด๋ผ์ด์ธํธ๋ก ๋ณด๋์ต๋๋ค.์๋ก ๋ง๋ ๋์ ์ ํ ์คํธํ๋ฉด ๋ถ๋ช ํ 200 OK ์๋ต์ด ๋ฐํ๋๊ณ ๊ฒ์ ๊ฒฐ๊ณผ๊ฐ ์ ๊ณต๋ฉ๋๋ค.
ํ์ง๋ง ๋์ ์ ์์ ์ด ํ๋ ๋ ๋จ์ ์์ผ๋ฉฐ JSON ํ์์ผ๋ก ๋ฉ์ง๊ณ ๋ฉ์ง ํ์์ ๊ฒ์ ์ ์์ ๋ฐํํฉ๋๋ค.
์ฝ๋์ ์ด ๋ถ๋ถ์์๋ ์ธ๋ฑ์ฑ์ ์ฌ์ฉํ์ฌ ๊ฒฐ๊ณผ์ โโ์ฃผ์ ๋ถ๋ถ์ ์ฐธ์กฐํ๊ณ , ์ ๊ท์์ ์ฌ์ฉํ์ฌ ์ค์ ์๋ฃ ํ ์คํธ๋ฅผ ์ ๊ณตํ๋ ๋ถ๋ถ๋ง ๊ฐ์ ธ์ค๊ณ , ์ ๊ท์ ์ผ์น์ ๋ํ ์ผ๋ถ null ๊ฒ์ฌ๋ฅผ ์ถ๊ฐํ์ต๋๋ค. ์ด์ API ์๋ต์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
React ์ ํ๋ฆฌ์ผ์ด์ ์์ API ๊ตฌํ
์ด์ ์ค์ ๋ก API๋ฅผ ์ฌ์ฉํ์ฌ ์ฌ์ฉ์์๊ฒ ๊ฒ์ ํค ์ ๋ ฅ์ ๋์ ์ผ๋ก ์ ์ํ๋ ๋ถ๋ถ์ด ์์ต๋๋ค. ์ฝ๋ ์๋๋ฐ์ค์์ ์ ๋ ฅ์ ๋ฐ์ ์ํ์ ์ ์ฅํ๋ ๊ธฐ๋ณธ ๋ฐ์ ์ฑ์ ์คํํด ๋ณด๊ฒ ์ต๋๋ค.
์ด์ ์ ๋ ฅ ๊ฐ์ด ๋ณ๊ฒฝ๋ ๋๋ง๋ค ํค๋ฅผ ๋๋ฅผ ๋๋ง๋ค ์์ญ ๊ฐ์ ์์ฒญ์ผ๋ก ์๋ํฌ์ธํธ์ ์คํธ์ ๋ณด๋ด๋ ๊ฒ์ ์ํ์ง ์์ต๋๋ค. ๋ฐ๋ผ์ ์ฐ๋ฆฌ๋ ๋ค์๊ณผ ๊ฐ์ด ์๊ฐ ์ด๊ณผ ๊ธฐ๋ฐ ์์ฒญ ๊ฐ์ ธ์ค๊ธฐ๋ฅผ ๊ตฌํํ ๊ฒ์ ๋๋ค.
import axios from "axios";
import { useState } from "react";
export default function App() {
const [searchResults, setSearchResults] = useState([]);
const [inputText, setInputText] = useState("");
const [inputTimer, setInputTimer] = useState(null);
const handleInputChange = async (e) => {
setInputText(e.target.value);
clearTimeout(inputTimer);
let timeout = setTimeout(() => {
console.log("FETCHING RESULTS");
axios
.get(
`https://autocomplete-google-search.kuvambhardwaj.repl.co/autocomplete?q=${e.target.value}`
)
.then((res) => {
setSearchResults(res.data);
});
}, 300);
setInputTimer(timeout);
};
return (
<div className="App">
<center>
<input
value={inputText}
onChange={handleInputChange}
placeholder="Type something"
style={{ fontSize: "24px" }}
/>
<div style={{ marginTop: "30px" }}>
<ul>
{searchResults.map((searchResult) => (
<li>{searchResult}</li>
))}
</ul>
</div>
</center>
</div>
)
}
์ด์ ์ฐ๋ฆฌ๊ฐ ํ๋ ์ผ์ ์ ๋ ฅ ๊ฐ์ด ๋ณ๊ฒฝ๋ ๋๋ง๋ค 300ms์ ๊ฐ์ ์๊ฐ ์ด๊ณผ๋ฅผ ์ค์ ํ๊ณ ์ํ์ ์๊ฐ ์ด๊ณผ ์ฐธ์กฐ๋ฅผ ์ ์ฅํ๋ ๊ฒ์ ๋๋ค. ์ฌ์ฉ์๊ฐ ๋ฌธ์๋ฅผ ์ ๋ ฅํ๊ณ ์ ๋ ฅ ๊ฐ์ด 300ms ์ด๋ด์ ๋ณ๊ฒฝ๋๋ฉด ์ด์ ์ค์ ์ด ์ง์์ง๋๋ค. ์๊ฐ ์ด๊ณผํ๊ณ ์ ๊ฒ์ ์ด๊ธฐํํ์ญ์์ค. 300ms์ ์ ๋ ฅ ๋นํ์ฑํ ํ ๋ง์ง๋ง์ผ๋ก ๊ฐ์ฅ ์ต๊ทผ์ ์ ๋ ฅ ๊ฐ์ผ๋ก ์๋ ์์ฑ ์์ฒญ์ ํ ๊ฒ์ ๋๋ค.
์์ฉ ํ๋ก๊ทธ๋จ์ ๋ค์๊ณผ ๊ฐ์ด ์๋ํด์ผ ํฉ๋๋ค.
๋ด ๊ฒ์๋ฌผ์ด ๋ง์์ ๋ค๋ฉด ๋ค์์ ๊ณ ๋ คํ์ญ์์ค :)
ํธ์ํฐ ->
Github -> @kuvamdazeus
๋งํฌ๋์ธ ->
ํฌํธํด๋ฆฌ์ค -> kuvambhardwaj.vercel.app
Reference
์ด ๋ฌธ์ ์ ๊ดํ์ฌ(NodeJS ๋ฐ React ๐๋ฅผ ์ฌ์ฉํ์ฌ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ๋์ ๊ฒ์ ์๋ ์์ฑ ์ถ๊ฐ), ์ฐ๋ฆฌ๋ ์ด๊ณณ์์ ๋ ๋ง์ ์๋ฃ๋ฅผ ๋ฐ๊ฒฌํ๊ณ ๋งํฌ๋ฅผ ํด๋ฆญํ์ฌ ๋ณด์๋ค https://dev.to/kuvambhardwaj/adding-dynamic-search-auto-complete-to-a-web-application-with-nodejs-and-react-2lh4ํ ์คํธ๋ฅผ ์์ ๋กญ๊ฒ ๊ณต์ ํ๊ฑฐ๋ ๋ณต์ฌํ ์ ์์ต๋๋ค.ํ์ง๋ง ์ด ๋ฌธ์์ URL์ ์ฐธ์กฐ URL๋ก ๋จ๊ฒจ ๋์ญ์์ค.
์ฐ์ํ ๊ฐ๋ฐ์ ์ฝํ ์ธ ๋ฐ๊ฒฌ์ ์ ๋ (Collection and Share based on the CC Protocol.)
์ข์ ์นํ์ด์ง ์ฆ๊ฒจ์ฐพ๊ธฐ
๊ฐ๋ฐ์ ์ฐ์ ์ฌ์ดํธ ์์ง
๊ฐ๋ฐ์๊ฐ ์์์ผ ํ ํ์ ์ฌ์ดํธ 100์ ์ถ์ฒ ์ฐ๋ฆฌ๋ ๋น์ ์ ์ํด 100๊ฐ์ ์์ฃผ ์ฌ์ฉํ๋ ๊ฐ๋ฐ์ ํ์ต ์ฌ์ดํธ๋ฅผ ์ ๋ฆฌํ์ต๋๋ค