{"id":134,"date":"2026-06-26T13:32:51","date_gmt":"2026-06-26T13:32:51","guid":{"rendered":"https:\/\/aabbee.cafe24.com\/?p=134"},"modified":"2026-06-26T13:32:51","modified_gmt":"2026-06-26T13:32:51","slug":"contact","status":"publish","type":"post","link":"https:\/\/coalacoding.com\/?p=134","title":{"rendered":"Contact"},"content":{"rendered":"<h1>07. Contact.jsx \u2014 EmailJS\ub85c \uc774\uba54\uc77c \uc804\uc1a1<\/h1>\n<h2>\uc774\ubc88 \ub2e8\uacc4\uc5d0\uc11c \ud560 \uc77c<\/h2>\n<p>Contact \ud3fc\uc5d0\uc11c \uc785\ub825\ud55c \ub0b4\uc6a9\uc744 <strong>\uc2e4\uc81c \uc774\uba54\uc77c\ub85c \uc804\uc1a1<\/strong>\ud55c\ub2e4.<br \/>\nEmailJS \u2014 \ubc31\uc5d4\ub4dc \uc11c\ubc84 \uc5c6\uc774 \ud504\ub860\ud2b8\uc5d4\ub4dc\uc5d0\uc11c \ubc14\ub85c \uc774\uba54\uc77c\uc744 \ubcf4\ub0b4\uc8fc\ub294 \uc11c\ube44\uc2a4\uc774\ub2e4.<\/p>\n<hr>\n<h2>\ud53c\uadf8\ub9c8 \ub514\uc790\uc778 \ubd84\uc11d<\/h2>\n<pre><code>\u2502 \u2500\u2500\u2500 contacts \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \u2502\n\u2502                                               \u2502\n\u2502   Name                                        \u2502\n\u2502   \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510  \u2502\n\u2502   \u2502 Value                                  \u2502  \u2502  \ub192\uc774: 40px\n\u2502   \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518  \u2502\n\u2502                                               \u2502\n\u2502   Email                                       \u2502\n\u2502   \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510  \u2502\n\u2502   \u2502 Value                                  \u2502  \u2502\n\u2502   \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518  \u2502\n\u2502                                               \u2502\n\u2502   Message (textarea)                          \u2502\n\u2502                                               \u2502\n\u2502   \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510  \u2502\n\u2502   \u2502  Cancel  \u2502  \u2502         Submit           \u2502  \u2502\n\u2502   \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518  \u2502\n<\/code><\/pre>\n<hr>\n<h2>STEP 0 \u2014 EmailJS \uac00\uc785 \ubc0f \uc124\uc815<\/h2>\n<p>EmailJS\ub97c \uc0ac\uc6a9\ud558\ub824\uba74 3\uac00\uc9c0 \uac12\uc774 \ud544\uc694\ud558\ub2e4.<\/p>\n<table>\n<thead>\n<tr>\n<th>\uac12<\/th>\n<th>\uc124\uba85<\/th>\n<th>\uc5b4\ub514\uc11c \ucc3e\ub098<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Service ID<\/td>\n<td>\uc5f0\uacb0\ud55c \uc774\uba54\uc77c \uc11c\ube44\uc2a4 \uc2dd\ubcc4\uc790<\/td>\n<td>Email Services \uba54\ub274<\/td>\n<\/tr>\n<tr>\n<td>Template ID<\/td>\n<td>\uc774\uba54\uc77c \ud15c\ud50c\ub9bf \uc2dd\ubcc4\uc790<\/td>\n<td>Email Templates \uba54\ub274<\/td>\n<\/tr>\n<tr>\n<td>Public Key<\/td>\n<td>\uacf5\uac1c \uc778\uc99d \ud0a4<\/td>\n<td>Account &gt; API Keys<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<ol>\n<li>\n<p><strong>EmailJS \uac00\uc785<\/strong> \u2014 <a href=\"https:\/\/www.emailjs.com\">https:\/\/www.emailjs.com<\/a> \uc5d0 \uc811\uc18d\ud558\uc5ec \ubb34\ub8cc \uacc4\uc815\uc744 \ub9cc\ub4e0\ub2e4<\/p>\n<\/li>\n<li>\n<p><strong>\uc774\uba54\uc77c \uc11c\ube44\uc2a4 \uc5f0\uacb0<\/strong> \u2014 Email Services \uba54\ub274\uc5d0\uc11c Gmail \ub4f1 \uc0ac\uc6a9\ud560 \uc774\uba54\uc77c\uc744 \uc5f0\uacb0\ud55c\ub2e4. \uc5f0\uacb0\ud558\uba74 <strong>Service ID<\/strong>\uac00 \uc0dd\uae34\ub2e4 (\uc608: <code>service_abc123<\/code>)<\/p>\n<\/li>\n<li>\n<p><strong>\uc774\uba54\uc77c \ud15c\ud50c\ub9bf \ub9cc\ub4e4\uae30<\/strong> \u2014 Email Templates \uba54\ub274\uc5d0\uc11c \uc0c8 \ud15c\ud50c\ub9bf\uc744 \ub9cc\ub4e0\ub2e4. \uc544\ub798\ucc98\ub7fc \uc791\uc131\ud55c\ub2e4<\/p>\n<\/li>\n<\/ol>\n<pre><code>Subject: \uc774\ub825\uc11c \uc0ac\uc774\ud2b8\uc5d0\uc11c \uc0c8 \uba54\uc2dc\uc9c0\uac00 \ub3c4\ucc29\ud588\uc2b5\ub2c8\ub2e4\n\nHello,\n\nYou got a new message from {{user_name}} ({{user_email}}):\n\n{{message}}\n\nBest wishes,\nEmailJS team\n<\/code><\/pre>\n<blockquote>\n<p><strong>Info<\/strong>: <code>{{user_name}}<\/code>, <code>{{user_email}}<\/code>, <code>{{message}}<\/code> \u2014 \uc774\uc911 \uc911\uad04\ud638 \uc548\uc758 \uc774\ub984\uc740 HTML form\uc758 <code>name<\/code> \uc18d\uc131\uacfc \uc77c\uce58\ud574\uc57c \ud55c\ub2e4. \ud3fc\uc5d0\uc11c <code>name=&quot;user_name&quot;<\/code>\uc73c\ub85c \ubcf4\ub0b4\uba74 \ud15c\ud50c\ub9bf\uc5d0\uc11c <code>{{user_name}}<\/code>\uc73c\ub85c \ubc1b\ub294\ub2e4.<\/p>\n<\/blockquote>\n<ol start=\"4\">\n<li>\n<p><strong>Template ID \ud655\uc778<\/strong> \u2014 \ud15c\ud50c\ub9bf\uc744 \uc800\uc7a5\ud558\uba74 <strong>Template ID<\/strong>\uac00 \uc0dd\uae34\ub2e4 (\uc608: <code>template_xyz789<\/code>)<\/p>\n<\/li>\n<li>\n<p><strong>Public Key \ud655\uc778<\/strong> \u2014 Account &gt; API Keys \uc5d0\uc11c <strong>Public Key<\/strong>\ub97c \ubcf5\uc0ac\ud55c\ub2e4<\/p>\n<\/li>\n<\/ol>\n<hr>\n<h2>STEP 1 \u2014 \ud328\ud0a4\uc9c0 \uc124\uce58<\/h2>\n<pre><code class=\"language-bash\">npm install @emailjs\/browser\n<\/code><\/pre>\n<blockquote>\n<p><strong>None<\/strong>: <code>@emailjs\/browser<\/code> \u2014 \ube0c\ub77c\uc6b0\uc800 \ud658\uacbd\uc5d0\uc11c EmailJS API\ub97c \uc0ac\uc6a9\ud560 \uc218 \uc788\uac8c \ud574\uc8fc\ub294 \ub77c\uc774\ube0c\ub7ec\ub9ac\uc774\ub2e4<\/p>\n<\/blockquote>\n<hr>\n<h2>STEP 2 \u2014 Contact.jsx \uc791\uc131<\/h2>\n<pre><code class=\"language-jsx\">import { useState, useRef } from &#39;react&#39;\nimport emailjs from &#39;@emailjs\/browser&#39;\nimport SectionTitle from &#39;.\/SectionTitle&#39;\n\nconst Contact = () =&gt; {\n  const formRef = useRef(null)\n  const [loading, setLoading] = useState(false)\n\n  const handleSubmit = (e) =&gt; {\n    e.preventDefault()\n    setLoading(true)\n\n    emailjs\n      .sendForm(\n        &#39;YOUR_SERVICE_ID&#39;,\n        &#39;YOUR_TEMPLATE_ID&#39;,\n        formRef.current,\n        { publicKey: &#39;YOUR_PUBLIC_KEY&#39; }\n      )\n      .then(() =&gt; {\n        alert(&#39;\uba54\uc2dc\uc9c0\uac00 \uc804\uc1a1\ub418\uc5c8\ub2e4!&#39;)\n        formRef.current.reset()\n      })\n      .catch((error) =&gt; {\n        alert(&#39;\uc804\uc1a1 \uc2e4\ud328: &#39; + error.text)\n      })\n      .finally(() =&gt; {\n        setLoading(false)\n      })\n  }\n\n  const handleReset = () =&gt; {\n    formRef.current.reset()\n  }\n\n  return (\n    &lt;section className=&quot;contact&quot; id=&quot;contacts&quot;&gt;\n      &lt;SectionTitle\n        title=&quot;contacts&quot;\n        subtitle=&quot;\ub048\uae30\uc640 \uc5f4\uc815\uc73c\ub85c \uc131\uc7a5\ud558\ub294 \uc624\uc131\uc758\uc785\ub2c8\ub2e4.&quot;\n      \/&gt;\n\n      &lt;form className=&quot;contact-form&quot; ref={formRef} onSubmit={handleSubmit}&gt;\n        &lt;div className=&quot;form-field&quot;&gt;\n          &lt;label className=&quot;form-label&quot;&gt;Name&lt;\/label&gt;\n          &lt;input\n            className=&quot;form-input&quot;\n            type=&quot;text&quot;\n            name=&quot;user_name&quot;\n            placeholder=&quot;\uc774\ub984\uc744 \uc785\ub825\ud558\uc138\uc694&quot;\n            required\n          \/&gt;\n        &lt;\/div&gt;\n\n        &lt;div className=&quot;form-field&quot;&gt;\n          &lt;label className=&quot;form-label&quot;&gt;Email&lt;\/label&gt;\n          &lt;input\n            className=&quot;form-input&quot;\n            type=&quot;email&quot;\n            name=&quot;user_email&quot;\n            placeholder=&quot;\uc774\uba54\uc77c\uc744 \uc785\ub825\ud558\uc138\uc694&quot;\n            required\n          \/&gt;\n        &lt;\/div&gt;\n\n        &lt;div className=&quot;form-field&quot;&gt;\n          &lt;label className=&quot;form-label&quot;&gt;Message&lt;\/label&gt;\n          &lt;textarea\n            className=&quot;form-textarea&quot;\n            name=&quot;message&quot;\n            placeholder=&quot;\uba54\uc2dc\uc9c0\ub97c \uc785\ub825\ud558\uc138\uc694&quot;\n            required\n          \/&gt;\n        &lt;\/div&gt;\n\n        &lt;div className=&quot;form-buttons&quot;&gt;\n          &lt;button\n            type=&quot;button&quot;\n            className=&quot;form-btn form-btn--cancel&quot;\n            onClick={handleReset}\n          &gt;\n            Cancel\n          &lt;\/button&gt;\n          &lt;button\n            type=&quot;submit&quot;\n            className=&quot;form-btn form-btn--submit&quot;\n            disabled={loading}\n          &gt;\n            {loading ? &#39;Sending...&#39; : &#39;Submit&#39;}\n          &lt;\/button&gt;\n        &lt;\/div&gt;\n      &lt;\/form&gt;\n    &lt;\/section&gt;\n  )\n}\n\nexport default Contact\n<\/code><\/pre>\n<blockquote>\n<p><strong>None<\/strong>: 1: <code>import { useState, useRef } from &#39;react&#39;<\/code> \u2014 <code>useState<\/code>\ub294 \uc0c1\ud0dc \uad00\ub9ac, <code>useRef<\/code>\ub294 DOM \uc694\uc18c\ub97c \uc9c1\uc811 \ucc38\uc870\ud560 \ub54c \uc0ac\uc6a9\ud55c\ub2e4<\/p>\n<p>2: <code>import emailjs from &#39;@emailjs\/browser&#39;<\/code> \u2014 EmailJS \ub77c\uc774\ube0c\ub7ec\ub9ac\ub97c \uac00\uc838\uc628\ub2e4<\/p>\n<p>3: <code>import SectionTitle from &#39;.\/SectionTitle&#39;<\/code> \u2014 \uc774\uc804\uc5d0 \ub9cc\ub4e0 \uc139\uc158 \ud0c0\uc774\ud2c0 \ucef4\ud3ec\ub10c\ud2b8\uc774\ub2e4<\/p>\n<p>6: <code>const formRef = useRef(null)<\/code> \u2014 form \ud0dc\uadf8\ub97c \uc9c1\uc811 \ucc38\uc870\ud558\uae30 \uc704\ud55c ref\uc774\ub2e4. EmailJS\uc758 <code>sendForm<\/code>\uc774 form \uc694\uc18c\ub97c \uc9c1\uc811 \uc77d\uc5b4\uc57c \ud558\uae30 \ub54c\ubb38\uc5d0 \ud544\uc694\ud558\ub2e4<\/p>\n<p>7: <code>const [loading, setLoading] = useState(false)<\/code> \u2014 \uc804\uc1a1 \uc911\uc778\uc9c0 \uc544\ub2cc\uc9c0 \uc0c1\ud0dc\ub97c \uc800\uc7a5\ud55c\ub2e4. \uc804\uc1a1 \uc911\uc5d0\ub294 \ubc84\ud2bc\uc744 \ube44\ud65c\uc131\ud654\ud55c\ub2e4<\/p>\n<p>9: <code>const handleSubmit = (e) =&gt; {<\/code> \u2014 \ud3fc\uc744 \uc81c\ucd9c\ud560 \ub54c \uc2e4\ud589\ub418\ub294 \ud568\uc218\uc774\ub2e4<\/p>\n<p>10: <code>e.preventDefault()<\/code> \u2014 form \ud0dc\uadf8\uc758 \uae30\ubcf8 \ub3d9\uc791(\ud398\uc774\uc9c0 \uc0c8\ub85c\uace0\uce68)\uc744 \ub9c9\ub294\ub2e4<\/p>\n<p>11: <code>setLoading(true)<\/code> \u2014 \uc804\uc1a1 \uc2dc\uc791\uc744 \ud45c\uc2dc\ud55c\ub2e4<\/p>\n<p>13~18: <code>emailjs.sendForm(...)<\/code> \u2014 EmailJS\uc5d0 \uc774\uba54\uc77c \uc804\uc1a1\uc744 \uc694\uccad\ud55c\ub2e4<\/p>\n<ul>\n<li>\uccab \ubc88\uc9f8 \uc778\uc790: Service ID<\/li>\n<li>\ub450 \ubc88\uc9f8 \uc778\uc790: Template ID<\/li>\n<li>\uc138 \ubc88\uc9f8 \uc778\uc790: form DOM \uc694\uc18c (<code>formRef.current<\/code>)<\/li>\n<li>\ub124 \ubc88\uc9f8 \uc778\uc790: Public Key \uac1d\uccb4<\/li>\n<\/ul>\n<p>19~21: <code>.then(() =&gt; { ... })<\/code> \u2014 \uc804\uc1a1 \uc131\uacf5 \uc2dc \uc54c\ub9bc\uc744 \ub744\uc6b0\uace0, <code>formRef.current.reset()<\/code>\uc73c\ub85c \ud3fc\uc744 \ucd08\uae30\ud654\ud55c\ub2e4<\/p>\n<p>22~24: <code>.catch((error) =&gt; { ... })<\/code> \u2014 \uc804\uc1a1 \uc2e4\ud328 \uc2dc \uc5d0\ub7ec \uba54\uc2dc\uc9c0\ub97c \ubcf4\uc5ec\uc900\ub2e4<\/p>\n<p>25~27: <code>.finally(() =&gt; { ... })<\/code> \u2014 \uc131\uacf5\/\uc2e4\ud328 \uc0c1\uad00\uc5c6\uc774 loading \uc0c1\ud0dc\ub97c <code>false<\/code>\ub85c \ub418\ub3cc\ub9b0\ub2e4<\/p>\n<p>30~32: <code>const handleReset = () =&gt; { ... }<\/code> \u2014 Cancel \ubc84\ud2bc \ud074\ub9ad \uc2dc \ud3fc\uc758 \ubaa8\ub4e0 \uac12\uc744 \ucd08\uae30\ud654\ud55c\ub2e4<\/p>\n<p>42: <code>ref={formRef}<\/code> \u2014 form \ud0dc\uadf8\uc5d0 ref\ub97c \uc5f0\uacb0\ud55c\ub2e4. \uc774\uc81c <code>formRef.current<\/code>\ub85c \uc774 form \uc694\uc18c\uc5d0 \uc811\uadfc\ud560 \uc218 \uc788\ub2e4<\/p>\n<p>47: <code>name=&quot;user_name&quot;<\/code> \u2014 EmailJS \ud15c\ud50c\ub9bf\uc758 <code>{{user_name}}<\/code>\uacfc \ub9e4\uce6d\ub418\ub294 \uc774\ub984\uc774\ub2e4<\/p>\n<p>49: <code>required<\/code> \u2014 \ube48 \uce78\uc73c\ub85c \uc81c\ucd9c\ud560 \uc218 \uc5c6\uac8c \ub9c9\ub294\ub2e4<\/p>\n<p>75: <code>disabled={loading}<\/code> \u2014 \uc804\uc1a1 \uc911\uc5d0\ub294 \ubc84\ud2bc\uc744 \ud074\ub9ad\ud560 \uc218 \uc5c6\uac8c \ub9c9\ub294\ub2e4. \uc911\ubcf5 \uc804\uc1a1\uc744 \ubc29\uc9c0\ud55c\ub2e4<\/p>\n<p>77: <code>{loading ? &#39;Sending...&#39; : &#39;Submit&#39;}<\/code> \u2014 \uc0bc\ud56d \uc5f0\uc0b0\uc790\ub85c \uc804\uc1a1 \uc911\uc774\uba74 &quot;Sending&#8230;&quot;, \uc544\ub2c8\uba74 &quot;Submit&quot;\uc744 \ud45c\uc2dc\ud55c\ub2e4<\/p>\n<\/blockquote>\n<blockquote>\n<p><strong>Warning<\/strong>: <code>&#39;YOUR_SERVICE_ID&#39;<\/code>, <code>&#39;YOUR_TEMPLATE_ID&#39;<\/code>, <code>&#39;YOUR_PUBLIC_KEY&#39;<\/code>\ub294 \ubc18\ub4dc\uc2dc \ubcf8\uc778\uc758 EmailJS \ub300\uc2dc\ubcf4\ub4dc\uc5d0\uc11c \ubcf5\uc0ac\ud55c \uc2e4\uc81c \uac12\uc73c\ub85c \ubc14\uafd4\uc57c \ud55c\ub2e4.<\/p>\n<\/blockquote>\n<hr>\n<h2>\uc0c8\ub85c\uc6b4 \uac1c\ub150: useRef<\/h2>\n<p>\uc774\uc804 \ub2e8\uacc4\uc5d0\uc11c\ub294 <code>useState<\/code>\ub85c input \uac12\uc744 \uad00\ub9ac\ud588\ub2e4 (\uc81c\uc5b4 \ucef4\ud3ec\ub10c\ud2b8).<br \/>\n\uc774\ubc88\uc5d0\ub294 <code>useRef<\/code>\ub85c form \uc790\uccb4\ub97c \ucc38\uc870\ud55c\ub2e4 (\ube44\uc81c\uc5b4 \ucef4\ud3ec\ub10c\ud2b8).<\/p>\n<pre><code>\uc81c\uc5b4 \ucef4\ud3ec\ub10c\ud2b8 (useState):\n  React\uac00 input \uac12\uc744 \uc9c1\uc811 \uad00\ub9ac\ud55c\ub2e4\n  value={state} + onChange={setState}\n\n\ube44\uc81c\uc5b4 \ucef4\ud3ec\ub10c\ud2b8 (useRef):\n  HTML form\uc774 \uac12\uc744 \uc2a4\uc2a4\ub85c \uad00\ub9ac\ud55c\ub2e4\n  React\ub294 ref\ub85c form\uc5d0 \uc811\uadfc\ub9cc \ud55c\ub2e4\n<\/code><\/pre>\n<p>EmailJS\uc758 <code>sendForm<\/code>\uc740 form DOM \uc694\uc18c\ub97c \ud1b5\uc9f8\ub85c \uc77d\uc5b4\uc11c \ub370\uc774\ud130\ub97c \uc218\uc9d1\ud55c\ub2e4.<br \/>\n\uadf8\ub798\uc11c <code>useRef<\/code>\ub85c form\uc744 \ucc38\uc870\ud558\ub294 \ubc29\uc2dd\uc774 \ub354 \uc790\uc5f0\uc2a4\ub7fd\ub2e4.<\/p>\n<pre><code class=\"language-jsx\">const formRef = useRef(null)\n\n&lt;form ref={formRef}&gt;\n  &lt;input name=&quot;user_name&quot; \/&gt;\n&lt;\/form&gt;\n\nemailjs.sendForm(&#39;...&#39;, &#39;...&#39;, formRef.current, { publicKey: &#39;...&#39; })\n<\/code><\/pre>\n<p><code>formRef.current<\/code> \u2014 ref \uc548\uc5d0 \uc800\uc7a5\ub41c \uc2e4\uc81c DOM \uc694\uc18c\uc774\ub2e4. <code>useRef<\/code>\ub294 <code>.current<\/code> \uc18d\uc131\uc5d0 \uac12\uc744 \ub2f4\uc544\ub454\ub2e4.<\/p>\n<hr>\n<h2>\uc0c8\ub85c\uc6b4 \uac1c\ub150: Promise (.then \/ .catch \/ .finally)<\/h2>\n<p><code>emailjs.sendForm()<\/code>\uc740 <strong>Promise<\/strong>\ub97c \ubc18\ud658\ud55c\ub2e4.<br \/>\nPromise \u2014 \ubbf8\ub798\uc5d0 \uc644\ub8cc\ub420 \uc791\uc5c5\uc744 \ub098\ud0c0\ub0b4\ub294 \uac1d\uccb4\uc774\ub2e4. &quot;\ub098\uc911\uc5d0 \uacb0\uacfc\ub97c \uc54c\ub824\uc904\uac8c&quot;\ub77c\ub294 \uc57d\uc18d\uc774\ub2e4.<\/p>\n<pre><code>emailjs.sendForm(...)     \u2190 \uc774\uba54\uc77c \uc804\uc1a1 \uc694\uccad (\uc2dc\uac04\uc774 \uac78\ub9b0\ub2e4)\n  .then(() =&gt; { ... })    \u2190 \uc131\uacf5\ud558\uba74 \uc2e4\ud589\n  .catch(() =&gt; { ... })   \u2190 \uc2e4\ud328\ud558\uba74 \uc2e4\ud589\n  .finally(() =&gt; { ... }) \u2190 \uc131\uacf5\/\uc2e4\ud328 \uc0c1\uad00\uc5c6\uc774 \ud56d\uc0c1 \uc2e4\ud589\n<\/code><\/pre>\n<p>\ube44\uc720: \ud0dd\ubc30\ub97c \ubcf4\ub0b4\ub294 \uac83\uacfc \uac19\ub2e4.<\/p>\n<pre><code>\ud0dd\ubc30 \uc811\uc218 (sendForm)\n  \u251c\u2500 \ubc30\ub2ec \uc644\ub8cc (.then)    \u2192 &quot;\ubc30\ub2ec\ub418\uc5c8\uc2b5\ub2c8\ub2e4&quot; \uc54c\ub9bc\n  \u251c\u2500 \ubc30\ub2ec \uc2e4\ud328 (.catch)   \u2192 &quot;\ubc30\ub2ec \uc2e4\ud328&quot; \uc54c\ub9bc\n  \u2514\u2500 \uc5b4\ub5a4 \uacbd\uc6b0\ub4e0 (.finally) \u2192 \ubc30\ub2ec \ucd94\uc801 \ud654\uba74 \ub2eb\uae30\n<\/code><\/pre>\n<hr>\n<h2>STEP 3 \u2014 CSS \ucd94\uac00<\/h2>\n<pre><code class=\"language-css\">\/* src\/index.css \uc5d0 \ucd94\uac00 *\/\n\n.contact {\n  padding: 80px 24px;\n}\n\n.contact-form {\n  width: 320px;\n  display: flex;\n  flex-direction: column;\n  gap: 20px;\n}\n\n.form-field {\n  display: flex;\n  flex-direction: column;\n  gap: 6px;\n}\n\n.form-label {\n  font-size: 16px;\n  font-weight: 500;\n  color: #1e1e1e;\n}\n\n.form-input {\n  height: 40px;\n  padding: 0 12px;\n  border: 1px solid #d0d0d0;\n  border-radius: 4px;\n  font-size: 16px;\n  color: #1e1e1e;\n  outline: none;\n  width: 100%;\n}\n\n.form-textarea {\n  height: 80px;\n  padding: 10px 12px;\n  border: 1px solid #d0d0d0;\n  border-radius: 4px;\n  font-size: 16px;\n  color: #1e1e1e;\n  resize: none;\n  outline: none;\n  width: 100%;\n}\n\n.form-input::placeholder,\n.form-textarea::placeholder {\n  color: #b3b3b3;\n}\n\n.form-input:focus,\n.form-textarea:focus {\n  border-color: #2c2c2c;\n}\n\n.form-buttons {\n  display: flex;\n  gap: 12px;\n}\n\n.form-btn {\n  height: 40px;\n  padding: 0 20px;\n  border: none;\n  border-radius: 4px;\n  font-size: 16px;\n  cursor: pointer;\n  transition: opacity 0.2s;\n}\n\n.form-btn--cancel {\n  background-color: #f0f0f0;\n  color: #303030;\n}\n\n.form-btn--submit {\n  flex: 1;\n  background-color: #2c2c2c;\n  color: #f5f5f5;\n}\n\n.form-btn--submit:disabled {\n  opacity: 0.5;\n  cursor: not-allowed;\n}\n\n.form-btn:hover:not(:disabled) {\n  opacity: 0.8;\n}\n<\/code><\/pre>\n<blockquote>\n<p><strong>None<\/strong>: 89~92: <code>.form-btn--submit:disabled<\/code> \u2014 <code>disabled<\/code> \uc18d\uc131\uc774 \uc788\uc744 \ub54c\uc758 \uc2a4\ud0c0\uc77c\uc774\ub2e4. \uc804\uc1a1 \uc911\uc5d0\ub294 \ubc18\ud22c\uba85\ud558\uac8c \ubcf4\uc774\uace0 \ucee4\uc11c\uac00 \uae08\uc9c0 \ubaa8\uc591\uc73c\ub85c \ubc14\ub010\ub2e4<\/p>\n<p>94~96: <code>.form-btn:hover:not(:disabled)<\/code> \u2014 \ube44\ud65c\uc131\ud654 \uc0c1\ud0dc\uac00 \uc544\ub2d0 \ub54c\ub9cc hover \ud6a8\uacfc\ub97c \uc801\uc6a9\ud55c\ub2e4<\/p>\n<\/blockquote>\n<hr>\n<h2>\ube0c\ub77c\uc6b0\uc800 \ud655\uc778<\/h2>\n<ol>\n<li>\ud3fc\uc5d0 \uc774\ub984, \uc774\uba54\uc77c, \uba54\uc2dc\uc9c0\ub97c \uc785\ub825\ud55c\ub2e4<\/li>\n<li><strong>Submit<\/strong> \ubc84\ud2bc\uc744 \ud074\ub9ad\ud55c\ub2e4<\/li>\n<li>\ubc84\ud2bc\uc774 &quot;Sending&#8230;&quot;\uc73c\ub85c \ubc14\ub00c\ub294 \uac83\uc744 \ud655\uc778\ud55c\ub2e4<\/li>\n<li>&quot;\uba54\uc2dc\uc9c0\uac00 \uc804\uc1a1\ub418\uc5c8\ub2e4!&quot; \uc54c\ub9bc\uc774 \ub728\uba74 \uc131\uacf5\uc774\ub2e4<\/li>\n<li>EmailJS\uc5d0 \uc5f0\uacb0\ud55c \uc774\uba54\uc77c \ubc1b\uc740\ud3b8\uc9c0\ud568\uc744 \ud655\uc778\ud55c\ub2e4 \u2014 \uc2e4\uc81c \uc774\uba54\uc77c\uc774 \uc640 \uc788\ub2e4<\/li>\n<\/ol>\n<blockquote>\n<p><strong>Warning<\/strong>: \uc804\uc1a1\uc774 \uc2e4\ud328\ud558\uba74 \ud655\uc778\ud560 \uac83:<\/p>\n<ul>\n<li>Service ID, Template ID, Public Key\uac00 \uc815\ud655\ud55c\uc9c0 \ud655\uc778\ud55c\ub2e4<\/li>\n<li>EmailJS \ub300\uc2dc\ubcf4\ub4dc\uc5d0\uc11c \uc774\uba54\uc77c \uc11c\ube44\uc2a4\uac00 Active \uc0c1\ud0dc\uc778\uc9c0 \ud655\uc778\ud55c\ub2e4<\/li>\n<li>\ud15c\ud50c\ub9bf\uc758 \ubcc0\uc218 \uc774\ub984(<code>{{user_name}}<\/code> \ub4f1)\uc774 form\uc758 <code>name<\/code> \uc18d\uc131\uacfc \uc77c\uce58\ud558\ub294\uc9c0 \ud655\uc778\ud55c\ub2e4<\/li>\n<li>\ubb34\ub8cc \ud50c\ub79c\uc740 \uc6d4 200\uac74\uae4c\uc9c0 \uc804\uc1a1 \uac00\ub2a5\ud558\ub2e4<\/li>\n<\/ul>\n<\/blockquote>\n<hr>\n<h2>\uc815\ub9ac<\/h2>\n<table>\n<thead>\n<tr>\n<th>\uac1c\ub150<\/th>\n<th>\uc124\uba85<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>EmailJS<\/td>\n<td>\ubc31\uc5d4\ub4dc \uc5c6\uc774 \ud504\ub860\ud2b8\uc5d4\ub4dc\uc5d0\uc11c \uc774\uba54\uc77c\uc744 \ubcf4\ub0b4\ub294 \uc11c\ube44\uc2a4<\/td>\n<\/tr>\n<tr>\n<td><code>useRef<\/code><\/td>\n<td>DOM \uc694\uc18c\ub97c \uc9c1\uc811 \ucc38\uc870\ud558\ub294 React Hook<\/td>\n<\/tr>\n<tr>\n<td><code>ref={formRef}<\/code><\/td>\n<td>form \ud0dc\uadf8\uc5d0 ref\ub97c \uc5f0\uacb0\ud558\ub294 \ubc29\ubc95<\/td>\n<\/tr>\n<tr>\n<td><code>sendForm()<\/code><\/td>\n<td>form \uc694\uc18c\ub97c \uc77d\uc5b4\uc11c \uc774\uba54\uc77c\uc744 \uc804\uc1a1\ud558\ub294 \ud568\uc218<\/td>\n<\/tr>\n<tr>\n<td>Promise<\/td>\n<td>\ubbf8\ub798\uc5d0 \uc644\ub8cc\ub420 \uc791\uc5c5\uc744 \ub098\ud0c0\ub0b4\ub294 \uac1d\uccb4<\/td>\n<\/tr>\n<tr>\n<td><code>.then()<\/code><\/td>\n<td>\uc131\uacf5 \uc2dc \uc2e4\ud589<\/td>\n<\/tr>\n<tr>\n<td><code>.catch()<\/code><\/td>\n<td>\uc2e4\ud328 \uc2dc \uc2e4\ud589<\/td>\n<\/tr>\n<tr>\n<td><code>.finally()<\/code><\/td>\n<td>\uc131\uacf5\/\uc2e4\ud328 \uc0c1\uad00\uc5c6\uc774 \ud56d\uc0c1 \uc2e4\ud589<\/td>\n<\/tr>\n<tr>\n<td><code>disabled<\/code><\/td>\n<td>\ubc84\ud2bc\uc744 \ud074\ub9ad \ubd88\uac00\ub2a5\ud558\uac8c \ub9cc\ub4dc\ub294 \uc18d\uc131<\/td>\n<\/tr>\n<tr>\n<td><code>required<\/code><\/td>\n<td>\ube48 \uce78 \uc81c\ucd9c\uc744 \ub9c9\ub294 HTML \uc18d\uc131<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<hr>\n","protected":false},"excerpt":{"rendered":"<p>07. Contact.jsx \u2014 EmailJS\ub85c \uc774\uba54\uc77c \uc804\uc1a1 \uc774\ubc88 \ub2e8\uacc4\uc5d0\uc11c \ud560 \uc77c Contact \ud3fc\uc5d0\uc11c \uc785\ub825\ud55c \ub0b4\uc6a9\uc744 \uc2e4\uc81c \uc774\uba54\uc77c\ub85c \uc804\uc1a1\ud55c\ub2e4. EmailJS \u2014 \ubc31\uc5d4\ub4dc \uc11c\ubc84 \uc5c6\uc774 \ud504\ub860\ud2b8\uc5d4\ub4dc\uc5d0\uc11c \ubc14\ub85c \uc774\uba54\uc77c\uc744 \ubcf4\ub0b4\uc8fc\ub294 \uc11c\ube44\uc2a4\uc774\ub2e4. \ud53c\uadf8\ub9c8 \ub514\uc790\uc778 \ubd84\uc11d \u2502 \u2500\u2500\u2500 contacts \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \u2502 \u2502 \u2502 \u2502 Name \u2502 \u2502 \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502 \u2502 \u2502 Value \u2502 \u2502 \ub192\uc774: 40px \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502 \u2502 \u2502 &#8230; <a title=\"Contact\" class=\"read-more\" href=\"https:\/\/coalacoding.com\/?p=134\" aria-label=\"Contact\uc5d0 \ub300\ud574 \ub354 \uc790\uc138\ud788 \uc54c\uc544\ubcf4\uc138\uc694\">\ub354 \uc77d\uae30<\/a><\/p>\n","protected":false},"author":0,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[11],"tags":[],"class_list":["post-134","post","type-post","status-publish","format-standard","hentry","category-react-resume"],"_links":{"self":[{"href":"https:\/\/coalacoding.com\/index.php?rest_route=\/wp\/v2\/posts\/134","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/coalacoding.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/coalacoding.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"replies":[{"embeddable":true,"href":"https:\/\/coalacoding.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=134"}],"version-history":[{"count":0,"href":"https:\/\/coalacoding.com\/index.php?rest_route=\/wp\/v2\/posts\/134\/revisions"}],"wp:attachment":[{"href":"https:\/\/coalacoding.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=134"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/coalacoding.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=134"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/coalacoding.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=134"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}