๊ธฐ์กด์ ํ์ด์ง์ ์์ ๋ก๊ทธ์ธ ๊ธฐ๋ฅ์ ์ถ๊ฐํ๋ ค๊ณ ํ๋ค.
๊ทธ๋์ ์ด๋ฏธ ์๋ ์ฌ์ฉ์์ ์๋ก ๋ก๊ทธ์ธํ ์ฌ์ฉ์์์ ๋งค์นญ๊ธฐ๋ฅ์ด ํ์ํ๋ค.
๊ทธ๋ฆฌ๊ณ ํ์๊ฐ์ ์ด ํ์ํ ์ฌ์ดํธ๊ฐ ์๋๋ผ, ๊ด๋ฆฌ์๊ฐ ์ฌ์ฉ์์ ๋ณด๋ฅผ ๋ฑ๋กํ๋ ํ์์ด๋ผ
๋ง์ผ ์ ๋ณด๊ฐ ์์ผ๋ฉด ํ๊ฒจ๋์์ ๊ด๋ฆฌ์ ๋ฌธ์๋ฅผ ๋ฐ๋ก ํด์ผํ๋ค.
๊ทธ๋ฌ๋ ๋ก๊ทธ์ธ๊ธฐ๋ฅ๋ง ์์ผ๋ฉด ๋จ!
๐ํ๋ฆ๋
๊ทธ๋ฆผ์์๋ ๋ณด๋ค์ํผ ์ฌ์ค ํ๋ก ํธ์์ ํฌ๊ฒ ํ ์ผ์ ์๋ค..
์ผ๋จ kakao ๋ก๊ทธ์ธ์ ์ด์ฉํ๊ธฐ ์ํด ์ธํ ๋ถํฐ!
1. Kakao Developers ์์ ์ ํ๋ฆฌ์ผ์ด์ ์์ฑ
kakao developers ์์ ์นด์นด์ค ๋ก๊ทธ์ธํ๊ณ ์ ํ๋ฆฌ์ผ์ด์ ์ ์์ฑํ๋ค.
๊ทธ๋ฌ๋ฉด ์๋์ฒ๋ผ api key๊ฐ์ ์ป์ ์ ์๋๋ฐ ์ฌ๊ธฐ์ javascript ํค๊ฐ์ ์ฌ์ฉํ ๊ฒ์
๊ทธ๋ฆฌ๊ณ ํ๋ซํผ > Web ํ๋ซํผ ๋ฑ๋ก์ ํด์ ์ฌ์ดํธ ๋๋ฉ์ธ์ ์ถ๊ฐํด์ค๋ค (๊ฐ๋ฐํ๋ฉด์ ํ์ธํ ๊ฒ์ด๊ธฐ ๋๋ฌธ์ ๋๋ http://localhost:3000 ์ ๋ฑ๋กํจ, ๋ฐฐํฌํ์๋ ๋ฐฐํฌ์๋ฒ ์ฃผ์๋ฅผ ์ ์ผ๋ฉด ๋๊ฒ ์ง?) ํ๋จ์ Redirect URI ๋ฑ๋กํ๋ฌ๊ฐ๊ธฐ๋ฅผ ๋๋ฌ Redirect URI๋ฅผ ๋ฑ๋กํด์ค๋ค.
Redirect URI๋ ์ธ๊ฐ์ฝ๋ ๋ฐ๊ธฐ ์์ฒญ์ ์๋ต์ผ๋ก ๊ฐ๋ ํ์ด์ง๋ผ์ ํ๋ก ํธ์์ ์ ๊ทผ์ด ๊ฐ๋ฅํ ํ์ด์ง๋ก ๋ง๋ค์ด์ผํ๋ค.
๊ทธ๋์ ๋๋ http://localhost:3000/login/kakao ๋ก ์ค์ ํด ์ค. (๋ฐฐํฌ ํ์ http://๋ฐฐํฌ์๋ฒ์ฃผ์/login/kakao ์ถ๊ฐํ๋ฉด ๋จ)
๊ทธ๋ฆฌ๊ณ ๋ฌธ์>javascript>๋ค์ด๋ก๋ ํ์ด์ง( JavaScript SDK ๋ค์ด๋ก๋ ) ์์ intergrity ์ version์ด ํ์ํ๋ค.
์ด๋ ๊ฒ ์๋ฐ์ด๋ฐ ๋ชจ์๊ฐ ์ ๋ณด๋ก ์ธํ ์ ํด๋ณด์
2. Next ์ ๊ฐ๋ฐ ์ค์
next 13~14๋ layout.tsx ์, ๊ทธ ์ดํ๋ _app.tsx๋ด <script>์ sdk๋ฅผ ์ถ๊ฐํด์ค๋ค.
next 13, 14
KakaoScript.tsx
'use client';
import Script from "next/script";
export default function KakaoScript() {
const handleKakaoInit = () => {
window.Kakao.init(process.env.NEXT_PUBLIC_KAKAO_JAVASCRIPT_KEY);
};
return (
<Script
src={`https://t1.kakaocdn.net/kakao_js_sdk/{!!!version!!!}/kakao.min.js`}
integrity={"!!!integridy!!!"}
crossOrigin="anonymous"
onLoad={handleKakaoInit}
/>
);
}
์ด์ ๋ฒ์ ์์๋ ๋ฐ๋ก _app.tsx์ Kakao.init์ ์งํํ ์ ์๋๋ฐ ์ดํ ๋ฒ์ ์์ window๊ฐ์ฒด๋ฅผ ์ฌ์ฉ ํ์ง ๋ชปํ์ฌ ๊ทธ๋ฌ์ง ๋ชปํ๋ค.
๊ทธ๋ ๊ธฐ ๋๋ฌธ์ "use client"๋ฅผ ์ ์ธํ ํ์ผ์ด ํ๋ ์ถ๊ฐ๋ก ํ์ํ๋ค.
layout.tsx
import KakaoScript from 'components/common/KakaoScript';
declare global {
interface Window {
Kakao: any;
}
}
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html>
<body>
...
</body>
<KakaoScript />
</html>
);
}
next 12 ์ดํ
_app.tsx
function MyApp({ Component, pageProps }: AppProps) {
const handleKakaoInit = () => {
window.Kakao.init(process.env.NEXT_PUBLIC_KAKAO_JAVASCRIPT_KEY);
window.Kakao.isInitialized();
};
return ( ....
<Layout>
...
<Script
src={`https://t1.kakaocdn.net/kakao_js_sdk/{!!!version!!!}/kakao.min.js`}
integrity={"!!!integridy!!!"}
crossOrigin="anonymous"
onLoad={handleKakaoInit}
/>
</Layout>
...
);
}
์๋ฌ ๐ข
TypeError: Cannot read properties of undefined (reading 'Auth')
์ด์ ๋ ์ ๋ชจ๋ฅด๊ฒ ์ง๋ง window.kakao๊ฐ ์์ง ์ ์๋์ง ์์์ ๋ ๊ทธ ํ์ ํ๋กํผํฐ๋ฅผ ์ฝ์ ๋ ๋ฐ์ํ๋ ๊ฒ์ด ์๋๊ฐ ํด์
์ถ๊ฐํ๋ ๋ถ๋ถ์ด๋ค..
const [kakaoLoaded, setKakaoLoaded] = useState(false);
// Script ์ปดํฌ๋ํธ๋ก ์คํฌ๋ฆฝํธ๋ฅผ ๋ก๋ํ๊ณ ์์ง๋ง,
// ๋ก๋๋๊ธฐ ์ ์ useEffect๊ฐ ์คํ๋๋ ๊ฑฐ ๊ฐ์์ ๋ก๋๋์๋์ง ํ์ธ ํ์ useEffect๋ฅผ ์คํ
useEffect(() => {
const handleKakaoInit = () => {
if (window.Kakao) {
if (!window.Kakao.isInitialized()) {
window.Kakao.init(process.env.NEXT_PUBLIC_KAKAO_JAVASCRIPT);
}
} else {
console.error("Kakao SDK not loaded");
}
};
if (kakaoLoaded) {
handleKakaoInit();
}
}, [kakaoLoaded]);
๊ทธ๋ฆฌ๊ณ Script ์ onLoad ์ {()=>setKakaoLoaded(true)} ๋ฅผ ๋ด์์ฃผ์๋ค.
์์ธ์ด ๋ฌด์์ธ์ง.. ์ด๊ฒ ์ ๋ต์ธ์ง๋ ๋๋ ํ์คํ์ง ์๋ค ใ ใ ๋๊ฐ ์๋ค๋ฉด ์ข ์๋ ค์ฃผ๋ผ....

3. ๋ฐฑ์๋์ ์ธ๊ฐ ์ฝ๋๋ฅผ ๋ณด๋ผ ํ์ด์ง ๋ง๋ค๊ธฐ (์ค์ ๋ก๊ทธ์ธ ํ์ด์ง)
๊ฐ์ ๋ฒ์ ์ ๋ง๋ ๋ผ์ฐํฐ๋ฐฉ์์ ์ด์ฉํด์ redirect URI์ ๊ฒฝ๋ก๊ฐ ๊ฐ์ ํ์ด์ง๋ฅผ ๋ง๋ ๋ค.
๊ทธ๋์ผ ์ฃผ์์ฐฝ์ query๋ก ๋ด๋ ค์ค๋ code๋ฅผ ๊ฐ์ ธ์์ ์ฌ์ฉํ ์ ์๊ธฐ ๋๋ฌธ์ด๋ค.
๋๋ ~~~/login/kakao ๋ก ์ค์ ํ๊ธฐ ๋๋ฌธ์ ์ด์ ๋ง๊ฒ ๊ฒฝ๋ก๋ฅผ ๊ตฌ์ฑํ๋ค.
์ผ๋จ login ํ์ด์ง์์ ๋ฒํผ์ ๋๋ฅด๋ฉด ์นด์นด์คํ์ด์ง๋ก ์ด๋
login.tsx
const { Kakao } = window;
const loginWithKakao = () => {
Kakao.Auth.authorize({
redirectUri: `http://localhost:3000/login/kakao`,
scope: "profile_nickname",
});
};
...
<Button className="form_btn" onClick={loginWithKakao}>
์นด์นด์ค ๋ก๊ทธ์ธ
</Button>
...
kakao ๋ก๊ทธ์ธ ํ์ด์ง
์ด ํ์ด์ง์์ ์ฌ์ฉ์ ์ด๋ฆ/์ ํ๋ฒํธ๋ฅผ ๋ชป๋ฐ์ ๊ฒฝ์ฐ๋ฅผ ๊ณ ๋ คํด
code์ ํจ๊ป input์ผ๋ก ๊ฐ์ ๋ฐ์ api๋ฅผ ๋ณด๋ด์ค๋ค.
export default function Kakao() {
const router = useRouter();
const { code: authCode, error: kakaoServerError } = router.query;
const [name, setName] = useState<string>("");
const [phone, setPhone] = useState<string>("");
const { mutate: loginMutate } = useMutation(
async () => {
const response = await axios.post(Account.POST_SNS_LOGIN, {
code: authCode,
snsCode: "1110501",
phoneNumber: phone,
name: name,
});
return response;
},
{
onSuccess: (response: any) => {
const data = response.data;
const headers = response.headers;
console.log(data, headers);
//๋ฐ์ ํ ํฐ์ ๋ก๊ทธ์ธํ๊ฒ ํด์ฃผ๋ ๋ก์ง
//๋ถ๋ฌ์จ ์ ๋ณด๋ฅผ ์ํ๊ด๋ฆฌ๋ก ์ ์ฅํด์ฃผ๋ ๋ก์ง ๋ฑ
//๋ก๊ทธ์ธ์ด ์ฑ๊ณตํ์ ๋์ ์ฝ๋๋ฅผ ์ ์ด์ค๋ค
},
onError: (error) => {
console.error(error);
},
}
);
return (
<>
<LoginContainer>
<div className="container">
<h1>๋ก๊ทธ์ธ ์ ๋ณด ์ ์ก</h1>
<span>
๊ด๋ฆฌ์๊ฐ ๋ฑ๋กํ ๊ณ์ ๊ณผ SNS ๋ก๊ทธ์ธ ์ฐ๋์
<br />
๋ฑ๋กํ๊ธฐ ์ํด ์
๋ ฅํฉ๋๋ค.
</span>
<div>
<input placeholder="์ด๋ฆ" onChange={(e: any) => setName(e.target.value)} />
</div>
<div>
<input placeholder="์ ํ๋ฒํธ" onChange={(e: any) => setPhone(e.target.value)} />
</div>
<button className="form_btn" onClick={loginMutate}>
๊ณ์ ํ์ธ
</button>
<div>
<a href="/" className="under">
<span>๋ก๊ทธ์ธ ํ์ด์ง๋ก ๋์๊ฐ๊ธฐ</span>
</a>
</div>
</div>
</LoginContainer>
</>
);
}
๋ด๊ฐ ํ ๊ฒ์ด ์ ๋ต๋ ์๋๊ณ ๋ชจ๋ฅด๋ ๊ฒ ํฌ์ฑ์ด์ ๋ฐ๋ณด์ด๋
๊ผญ ๊ผญ ๋ค๋ฅธ ๋ฐฉ๋ฒ์ด๋ ์ข์ ๋ฐฉ๋ฒ์ด๋ ์๋ชป๋ ๊ฒ์์ผ๋ฉด ์๋ ค์ฃผ์ธ์ค..

'TIL > Next.js' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
Next.js | ๋ค์ด๋ฒ ๋ก๊ทธ์ธ ๊ตฌํํ๊ธฐ (๋ค์๋ก~) (0) | 2024.03.06 |
---|---|
Next.js | ๊ตฌ๊ธ ๋ก๊ทธ์ธ ๊ตฌํํ๊ธฐ (0) | 2024.03.05 |
[TIL] Next.js 13 ๋ผ์ฐํ (4) | 2023.05.27 |
Next.js ๊ธฐ์ด 2 - component, props, state (0) | 2023.05.20 |
Next.js ๊ธฐ์ด 1 - ์์ํ๊ธฐ & ๋ผ์ฐํ & ์ด๋ฏธ์ง ๋ฃ๊ธฐ (0) | 2023.05.20 |