<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>si_do.log</title>
        <link>https://velog.io/</link>
        <description>나의 성장일지 💫</description>
        <lastBuildDate>Tue, 02 May 2023 05:05:54 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>si_do.log</title>
            <url>https://velog.velcdn.com/images/si_do/profile/68fb562e-98d3-456e-96d1-2399515d2d3c/image.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. si_do.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/si_do" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[React 로 만드는 음악 커뮤니티 사이트 #4 (Firebase로 로그인 / 로그아웃 구현)]]></title>
            <link>https://velog.io/@si_do/React-%EB%A1%9C-%EB%A7%8C%EB%93%9C%EB%8A%94-%EC%9D%8C%EC%95%85-%EC%BB%A4%EB%AE%A4%EB%8B%88%ED%8B%B0-%EC%82%AC%EC%9D%B4%ED%8A%B8-3-Firebase%EB%A1%9C-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EB%A1%9C%EA%B7%B8%EC%95%84%EC%9B%83-%EA%B5%AC%ED%98%84</link>
            <guid>https://velog.io/@si_do/React-%EB%A1%9C-%EB%A7%8C%EB%93%9C%EB%8A%94-%EC%9D%8C%EC%95%85-%EC%BB%A4%EB%AE%A4%EB%8B%88%ED%8B%B0-%EC%82%AC%EC%9D%B4%ED%8A%B8-3-Firebase%EB%A1%9C-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EB%A1%9C%EA%B7%B8%EC%95%84%EC%9B%83-%EA%B5%AC%ED%98%84</guid>
            <pubDate>Tue, 02 May 2023 05:05:54 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/si_do/post/fd52825f-d885-4b6d-8b76-5fe0b1536759/image.gif" alt=""></p>
<h2 id="구현-내용">구현 내용</h2>
<blockquote>
<ol>
<li>login 됐을때 logout으로 버튼변경</li>
<li>login이 성공한다면 Home으로 돌아가기</li>
<li>login된 유저의 정보를 받아 화면상에 띄우기</li>
<li>logout 기능</li>
</ol>
</blockquote>
<hr>
<h2 id="1-context-만들기">1. context 만들기</h2>
<p>유저가 로그인 했다는 정보를 전역에서 사용할 것이기 때문에 <code>context</code> 를 만들어줬다.
<code>src/context/AuthContext.tsx</code></p>
<pre><code class="language-javascript">import React from &quot;react&quot;;
import { User } from &quot;firebase/auth&quot;;

export const AuthContext = React.createContext&lt;User | null&gt;(null);
</code></pre>
<hr>
<h2 id="2provider">2.Provider</h2>
<p>이제 <code>context</code> 를 사용할 곳에 우산을 씌워주기 위해 <code>provider</code> 를 만들어준다.
<code>src/provider/AuthProvidert.tsx</code></p>
<pre><code class="language-javascript">import React, { useEffect, useState } from &quot;react&quot;;
import { User } from &quot;firebase/auth&quot;;
import { onUserStateChange } from &quot;../api/firebase&quot;;
import { AuthContext } from &quot;../context/AuthContext&quot;;

interface Props {
  children: React.ReactNode;
}

const AuthProvider = ({ children }: Props) =&gt; {
  const [user, setUser] = useState&lt;User | null&gt;(null); //유저의 정보 상태

  useEffect(() =&gt; {
    onUserStateChange((fbUser: User| null) =&gt; {
      console.log(fbUser);
      setUser(fbUser);
    });
  }, []); //user의 상태 변경을 감지하면 serUser에 받아온 유저정보를 넘겨줌
  return &lt;AuthContext.Provider value={user}&gt;{children}&lt;/AuthContext.Provider&gt;;
};

export default AuthProvider;
</code></pre>
<hr>
<h2 id="3-indextsx-에-provider-씌우기">3. index.tsx 에 provider 씌우기</h2>
<pre><code class="language-javascript">


const root = ReactDOM.createRoot(document.getElementById(&quot;root&quot;) as HTMLElement);
root.render(
  &lt;React.StrictMode&gt;
    &lt;AuthProvider&gt;
      &lt;RouterProvider router={router} /&gt;
    &lt;/AuthProvider&gt;
    &lt;Toaster /&gt;
  &lt;/React.StrictMode&gt;
);

</code></pre>
<p><code>context</code> 를 만들더라도 <code>provider</code>를 씌워주지 않으면 사용 불가능</p>
<hr>
<h2 id="4firebasets-에-email로-로그인-하기-추가">4.firebase.ts 에 Email로 로그인 하기 추가</h2>
<pre><code class="language-javascript">
//Email 로그인
export const EmailLogin = (email: string, password: string) =&gt; {
  signInWithEmailAndPassword(auth, email, password)
    .then((userCredential) =&gt; {
      const user = userCredential.user;
      toast.success(&quot;로그인 되었습니다!&quot;);
    })
    .catch((error) =&gt; {
      const errorCode = error.code;

      switch (errorCode) {
        case &quot;auth/wrong-password&quot;:
          toast.error(&quot;비밀번호를 확인 해 주세요&quot;);
          break;
        case &quot;auth/user-not-found&quot;:
          toast.error(&quot;존재하지 않는 사용자 입니다.&quot;);
          break;
      }
    });
};
</code></pre>
<p>오류가 난다면 <code>error</code> 메세지를 보여준다.<img src="https://velog.velcdn.com/images/si_do/post/c27834d1-54ce-4009-b273-ab92e077f448/image.png" alt=""></p>
<p> 정상적으로 잘 작동된다면 성공 메세지와 함께 메인페이지로 보내주고 로그인 했다는 정보가 보여진다.<img src="https://velog.velcdn.com/images/si_do/post/cd46ca84-c58e-4809-86ee-7db0a2103ac4/image.png" alt=""></p>
<blockquote>
<p>firebase 공식문서
<a href="https://firebase.google.com/docs/auth/web/start?hl=ko#sign_in_existing_users">https://firebase.google.com/docs/auth/web/start?hl=ko#sign_in_existing_users</a></p>
</blockquote>
<hr>
<h2 id="5-logout-구현">5. logout 구현</h2>
<p><code>firebase.ts</code> 에 로그아웃 하는 함수를 만들어준다.</p>
<pre><code class="language-javascript">//로그아웃
export const logout = () =&gt; {
  signOut(auth).then(() =&gt; null);
};</code></pre>
<blockquote>
<p>firebase 공식문서
<a href="https://firebase.google.com/docs/auth/web/password-auth?hl=ko&amp;authuser=0#next_steps">https://firebase.google.com/docs/auth/web/password-auth?hl=ko&amp;authuser=0#next_steps</a></p>
</blockquote>
<hr>
<h2 id="6firebase-로그인-상태-감지">6.firebase 로그인 상태 감지</h2>
<pre><code class="language-javascript">export const onUserStateChange = (callback: any) =&gt; {
  onAuthStateChanged(auth, (user) =&gt; {
    callback(user);
  });</code></pre>
<blockquote>
<p>firebase 공식문서
<a href="https://firebase.google.com/docs/auth/web/start?hl=ko#set_an_authentication_state_observer_and_get_user_data">https://firebase.google.com/docs/auth/web/start?hl=ko#set_an_authentication_state_observer_and_get_user_data</a></p>
</blockquote>
<hr>
<h2 id="usenavigate-로-메인페이지로-이동">useNavigate 로 메인페이지로 이동</h2>
<p>src/pages/LoginPage.tsx</p>
<pre><code class="language-javascript">import React, { useContext, useEffect } from &quot;react&quot;;
import LoginInput from &quot;../components/Login/LoginInput&quot;;
import { Link, useNavigate } from &quot;react-router-dom&quot;;
import { AuthContext } from &quot;../context/AuthContext&quot;;

const LoginPage = () =&gt; {
  const navigate = useNavigate();
  const user = useContext(AuthContext);
  useEffect(() =&gt; {
    if (user) {
      navigate(&quot;/&quot;);
    }
  });
  return (
    &lt;div className=&quot;w-full h-screen mx-auto flex justify-center items-center flex-col&quot;&gt;
      &lt;LoginInput /&gt;

      &lt;div className=&quot;mt-2  w-72 flex text-sm font-bold text-gray-700&quot;&gt;
        &lt;p className=&quot; font-normal mr-1&quot;&gt;계정이 없으신가요?&lt;/p&gt;
        &lt;Link to=&quot;/signin&quot;&gt;
          &lt;button&gt;회원가입&lt;/button&gt;
        &lt;/Link&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  );
};

export default LoginPage;
</code></pre>
<blockquote>
<p><code>useEffect</code>로 <code>user</code>가 있는지 확인한다음 유저가 있다면 <code>useNavigate</code>로 메인페이지로 이동시킴</p>
</blockquote>
<hr>
<blockquote>
<p>드디어 <code>firebase</code> 를 이용한 회원가입 , 로그인 , 로그아웃 기능이 완성되었다!!! 이제 게시판 만들차례다😼</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Input Animation (Label 을 Placeholder 처럼 사용하기)]]></title>
            <link>https://velog.io/@si_do/Input-Animation-Label-%EC%9D%84-Placeholder-%EC%B2%98%EB%9F%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@si_do/Input-Animation-Label-%EC%9D%84-Placeholder-%EC%B2%98%EB%9F%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0</guid>
            <pubDate>Tue, 02 May 2023 01:41:25 GMT</pubDate>
            <description><![CDATA[<h3 id="로그인과-회원가입-인풋에-들어갈-애니메이션의-최종-버전이다">로그인과 회원가입 인풋에 들어갈 애니메이션의 최종 버전이다.</h3>
<p><img src="https://velog.velcdn.com/images/si_do/post/36098e67-f33f-4237-876a-52d6c7388319/image.gif" alt=""></p>
<h1 id="🔥-문제">🔥 문제</h1>
<hr>
<p>이전에 올린 포스팅에서의 인풋 애니메이션에는 문제가 <strong>2가지</strong>가 있었다.</p>
<p>일단 이전에는 <code>onFocus</code> 와 <code>onBlur</code> 를 사용해 거기에 <code>True</code> / <code>False</code> 값으로
각각에 따른 스타일을 주었는데</p>
<p>첫번째 문제는 같은 <code>useState</code>를 사용하면 이메일 부분이<code>Focus</code> 되어도 다른 인풋들 모두 같이 애니메이션이 변한다는 점이고</p>
<p>두번째 문제는 Input 안에 값이 있을때는 동작을 하지않아 <code>Label</code> 이 <code>Input value</code> 값을 가려버리는 문제였다.</p>
<hr>
<p>그래서 첫번째 문제를 해결하기 위해 각각의 인풋에 다른 <code>useState</code> 값을 주었고 그러다보니 같은 동작을 하는 함수임에도 쓸데없이 많아졌다.
<img src="https://velog.velcdn.com/images/si_do/post/c1dde67f-2abb-47ed-961f-1f6df5c9fe58/image.png" alt="">
이런식으로...</p>
<hr>
<p>그리고 두번째 문제가 Input 안에 값이 있을때는 조건식으로 된 Css 값이 동작을 안해서 Label이 Input 값을 가려버린다는 건데 ...</p>
<p>이 두가지 문제를 해결할 수 있는 방법이 있었고 의외로 간단했다 !ㅇ!</p>
<hr>
<h1 id="🔥-문제-해결">🔥 문제 해결</h1>
<h2 id="peer">Peer</h2>
<blockquote>
<p><code>peer</code>는 바로 뒤 형제 요소에 <code>Css</code>를 입힐 때 사용한다. 셀렉터에서 <code>~</code>의 역할이다.</p>
</blockquote>
<p>peer를 사용함으로써 <code>label</code>이 <code>Input</code>에 일어난 <code>event</code>를 감지하고 그에 맞는 스타일을 입혀주는 것이다!!</p>
<p>나는 <code>peer-focus</code> 와 <code>peer-valid</code>를 이용해 스타일을 주었다.</p>
<blockquote>
<ul>
<li><code>peer-focus</code> : peer 요소가 <code>focus</code> 되었을때 스타일을 지정</li>
</ul>
</blockquote>
<ul>
<li><code>peer-valid</code> : peer 요소에 <code>값이 있을때</code> 스타일을 지정</li>
</ul>
<p>그리고 많은 css때메 값을 넣기도 불편하고 다른곳에서 Input을 만들때도 불편하여 css를 따로 빼주고 다른곳에서도 사용할수 있게 export 해주었다.</p>
<p>❗️참고로 input 에 꼭 <code>required</code> 속성이 있어야지 동작함</p>
<pre><code class="language-javascript">import React from &quot;react&quot;;
import Button from &quot;../Button/Button&quot;;
import { FcGoogle } from &quot;react-icons/fc&quot;;
import { googleLogin } from &quot;../../api/firebase&quot;;

export const INPUT_CSS = `border border-gray-600 w-full rounded-[4px] h-14 pt-4 pl-3 mb-1 peer transition
         `;
export const LABEL_CSS = `text-md absolute font-gray-600 transition ease-in-out left-3 top-4
         peer-focus:-translate-x-2 peer-focus:scale-75 peer-focus:-translate-y-3  peer-valid:scale-75 peer-valid:-translate-x-2 peer-valid:-translate-y-3`;

const LoginInput = () =&gt; {
  const handleLogin = () =&gt; {};
  const handleGoogleLogin = (e: React.MouseEvent&lt;HTMLButtonElement&gt;) =&gt; {
    e.preventDefault();
    googleLogin();
  };

  return (
    &lt;form className=&quot; w-72 mx-auto flex flex-col justify-center&quot;&gt;
      &lt;div className=&quot;relative&quot;&gt;
        &lt;input type=&quot;text&quot; id=&quot;email&quot; name=&quot;email&quot; className={`${INPUT_CSS}`} required /&gt;
        &lt;label
          htmlFor=&quot;email&quot;
          className={`${LABEL_CSS}
         `}
        &gt;
          이메일
        &lt;/label&gt;
      &lt;/div&gt;
      &lt;div className=&quot;relative&quot;&gt;
        &lt;input type=&quot;text&quot; id=&quot;pw&quot; name=&quot;pw&quot; className={`${INPUT_CSS}`} required /&gt;
        &lt;label htmlFor=&quot;pw&quot; className={`${LABEL_CSS}`}&gt;
          비밀번호
        &lt;/label&gt;
      &lt;/div&gt;
      &lt;Button onClick={handleLogin} label=&quot;로그인&quot; textStyle=&quot;text-white&quot; bgStyle=&quot;bg-blue-600&quot; /&gt;
      &lt;Button onClick={handleGoogleLogin} label=&quot;Google 로그인&quot; icon={FcGoogle} textStyle=&quot;text-blue-600&quot; bgStyle=&quot;bg-white&quot; borderStyle=&quot;border border-blue-600&quot; /&gt;
    &lt;/form&gt;
  );
};

export default LoginInput;
</code></pre>
<blockquote>
<p>Tailwind peer-[] 공식문서
<a href="https://tailwindcss.com/docs/hover-focus-and-other-states#styling-based-on-sibling-state">https://tailwindcss.com/docs/hover-focus-and-other-states#styling-based-on-sibling-state</a></p>
</blockquote>
<hr>
<blockquote>
<p>덕분에 코드가 줄어들고 가독성도 해결되서 속이 너무 시원하다 😿
(Tailwind 최고！) 근데 그냥 Input Component 만들면 더 간결해질텐데 나중에 리팩토링해야겠당</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[React 로 만드는 음악 커뮤니티 사이트 #3 (Firebase로 회원가입 구현)]]></title>
            <link>https://velog.io/@si_do/React-%EB%A1%9C-%EB%A7%8C%EB%93%9C%EB%8A%94-%EC%9D%8C%EC%95%85-%EC%BB%A4%EB%AE%A4%EB%8B%88%ED%8B%B0-%EC%82%AC%EC%9D%B4%ED%8A%B8-2-Firebase%EB%A1%9C-%ED%9A%8C%EC%9B%90%EA%B0%80%EC%9E%85-%EA%B5%AC%ED%98%84</link>
            <guid>https://velog.io/@si_do/React-%EB%A1%9C-%EB%A7%8C%EB%93%9C%EB%8A%94-%EC%9D%8C%EC%95%85-%EC%BB%A4%EB%AE%A4%EB%8B%88%ED%8B%B0-%EC%82%AC%EC%9D%B4%ED%8A%B8-2-Firebase%EB%A1%9C-%ED%9A%8C%EC%9B%90%EA%B0%80%EC%9E%85-%EA%B5%AC%ED%98%84</guid>
            <pubDate>Tue, 02 May 2023 00:59:18 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>Firebase 셋업을 완료하고 이번에 Firebase 회원가입 기능을 구현 해 보려한다.</p>
</blockquote>
<p>이메일로 회원가입 하는 기능을 만들기 전에 회원가입 페이지를 간단하게 구현 하였다.
<img src="https://velog.velcdn.com/images/si_do/post/44c18d21-ac21-4283-bc43-2c1d05f7ea6d/image.png" alt=""></p>
<blockquote>
<h4 id="구현-내용">구현 내용</h4>
</blockquote>
<ol>
<li>사용자가 form에 이름 , 이메일 ,비밀번호를 입력한다.</li>
<li>비밀번호가 일치한지 확인한다. (일치하지 않는다면 오류메세지 출력)</li>
<li>회원가입 버튼을 누르면 <code>firebase</code> 에 <code>createUserWithEmailAndPassword</code> 로 이름 , 이메일 ,비밀번호 값을 전달한다.</li>
<li><code>createUserWithEmailAndPassword</code> 에서 값을 받아서 <code>fireabase/auth</code> 에서 유효성 검사를 실행한 후 , 오류가 있다면 그에 맞는 오류메세지를 출력하고 정상적으로 완료 된다면 회원가입 진행후 <code>displayName</code> 에 이름 값을 추가 한 뒤 완료 메세지를 출력한다.</li>
</ol>
<hr>
<h3 id="회원가입-폼-만들기">회원가입 폼 만들기</h3>
<p><code>src/pages/Signup.tsx</code></p>
<pre><code class="language-javascript">
import React, { useState } from &quot;react&quot;;
import Button from &quot;../components/Button/Button&quot;;
import { signup } from &quot;../api/firebase&quot;;
import { toast } from &quot;react-hot-toast&quot;;

const SignIn = () =&gt; {
  const [name, setName] = useState&lt;string&gt;(&quot;&quot;);
  const [email, setEmail] = useState&lt;string&gt;(&quot;&quot;);
  const [password, setPassword] = useState&lt;string&gt;(&quot;&quot;);
  const [rePassword, setRePassword] = useState&lt;string&gt;(&quot;&quot;);

  return (
    &lt;form className=&quot; w-72 mx-auto flex flex-col justify-center&quot;&gt;
      &lt;h2 className=&quot; text-center my-12 text-2xl font-bold text-gray-800 pb-2 border border-t-0 border-x-0  border-b-gray-600&quot;&gt;회원가입&lt;/h2&gt;
      &lt;div className=&quot;relative&quot;&gt;
        &lt;label htmlFor=&quot;name&quot; className={`text-md absolute font-gray-600 transition ease-in-out left-3 top-4 ${isFocusName ? &quot;-translate-x-2&quot; : &quot;&quot;} ${isFocusName ? &quot;-translate-y-3&quot; : &quot;&quot;} ${isFocusName ? &quot;scale-75&quot; : &quot;&quot;}`}&gt;
          이름
        &lt;/label&gt;
        &lt;input
          onChange={(e) =&gt; {
            setName(e.target.value);
          }}
          onBlur={handleNameBlur}
          onFocus={handleNameFocus}
          value={name}
          type=&quot;text&quot;
          id=&quot;name&quot;
          name=&quot;name&quot;
          className={`border border-gray-600 w-full rounded-[4px] h-14 pt-4 pl-3 mb-2`}
        /&gt;
      &lt;/div&gt;
      &lt;div className=&quot;relative&quot;&gt;
        &lt;label htmlFor=&quot;email&quot; className={`text-md absolute font-gray-600 transition ease-in-out left-3 top-4 ${isFocus ? &quot;-translate-x-2&quot; : &quot;&quot;} ${isFocus ? &quot;-translate-y-3&quot; : &quot;&quot;} ${isFocus ? &quot;scale-75&quot; : &quot;&quot;}`}&gt;
          이메일
        &lt;/label&gt;
        &lt;input
          onChange={(e) =&gt; {
            setEmail(e.target.value);
          }}
          onBlur={handleEmailBlur}
          onFocus={handleEmailFocus}
          value={email}
          type=&quot;text&quot;
          id=&quot;email&quot;
          name=&quot;email&quot;
          className={`border border-gray-600 w-full rounded-[4px] h-14 pt-4 pl-3 mb-1`}
        /&gt;
      &lt;/div&gt;
      &lt;div className=&quot;relative&quot;&gt;
        &lt;label htmlFor=&quot;pw&quot; className={`text-md absolute font-gray-600 transition ease-in-out left-3 top-4 ${isFocusPw ? &quot;-translate-x-2&quot; : &quot;&quot;} ${isFocusPw ? &quot;-translate-y-3&quot; : &quot;&quot;} ${isFocusPw ? &quot;scale-75&quot; : &quot;&quot;}`}&gt;
          비밀번호
        &lt;/label&gt;
        &lt;input
          onChange={(e) =&gt; {
            setPassword(e.target.value);
          }}
          onBlur={handlePwBlur}
          onFocus={handlePwFocus}
          value={password}
          type=&quot;password&quot;
          id=&quot;pw&quot;
          name=&quot;pw&quot;
          className={`border border-gray-600 w-full rounded-[4px] h-14 pt-4 pl-3 mb-2`}
        /&gt;
      &lt;/div&gt;
      &lt;div className=&quot;relative&quot;&gt;
        &lt;label htmlFor=&quot;re_pw&quot; className={`text-md absolute font-gray-600 transition ease-in-out left-3 top-4 ${isFocusRePw ? &quot;-translate-x-2&quot; : &quot;&quot;} ${isFocusRePw ? &quot;-translate-y-3&quot; : &quot;&quot;} ${isFocusRePw ? &quot;scale-75&quot; : &quot;&quot;}`}&gt;
          비밀번호 확인
        &lt;/label&gt;
        &lt;input
          onChange={(e) =&gt; {
            setRePassword(e.target.value);
          }}
          onBlur={handleRePwBlur}
          onFocus={handleRePwFocus}
          value={rePassword}
          type=&quot;password&quot;
          id=&quot;re_pw&quot;
          name=&quot;re_pw&quot;
          className={`border border-gray-600 w-full rounded-[4px] h-14 pt-4 pl-3 mb-2`}
        /&gt;
      &lt;/div&gt;
      &lt;Button
        onClick={(e: React.MouseEvent&lt;HTMLButtonElement&gt;) =&gt; {
          if (password !== rePassword) {
            e.preventDefault();
            toast.error(&quot;입력하신 비밀번호가 다릅니다.&quot;);
          } else {
            e.preventDefault();
            signup(name, email, password);
            setName(&quot;&quot;);
            setEmail(&quot;&quot;);
            setPassword(&quot;&quot;);
            setRePassword(&quot;&quot;);
          }
        }}
        label=&quot;회원가입&quot;
        textStyle=&quot;text-white&quot;
        bgStyle=&quot;bg-blue-600&quot;
      /&gt;
    &lt;/form&gt;
  );
};

export default SignIn;</code></pre>
<blockquote>
<p>Button 에 <code>onClick</code> 이벤트를 추가해준다.</p>
</blockquote>
<ul>
<li>비밀번호가 일치하지 않는다면 <code>error</code> 메세지를 출력한다.</li>
<li>비밀번호가 일치한다면 <code>../api/firebase</code> 에 있는 <code>signup</code> 함수를 실행하고 <code>value</code> 값을 초기화 시켜준다.</li>
</ul>
<hr>
<h3 id="회원가입-구현">회원가입 구현</h3>
<p><code>../api/firebase</code></p>
<pre><code class="language-javascript">import { initializeApp } from &quot;firebase/app&quot;;
import { getAuth, signInWithPopup, GoogleAuthProvider, createUserWithEmailAndPassword, updateProfile } from &quot;firebase/auth&quot;;
import { toast } from &quot;react-hot-toast&quot;;

const firebaseConfig = {
  apiKey: process.env.REACT_APP_FIREBASE_API_KEY,
  authDomain: process.env.REACT_APP_FIREBASE_AUTH_DOMAIN,
  databaseURL: process.env.REACT_APP_FIREBASE_DB_URL,
  projectId: process.env.REACT_APP_FIREBASE_PROJECT_ID,
};

// Initialize Firebase
const app = initializeApp(firebaseConfig);
const auth = getAuth();
const provider = new GoogleAuthProvider();

***
생략
***


//Email 회원가입
export const signup = async (name: string, email: string, password: string) =&gt; {
  await createUserWithEmailAndPassword(auth, email, password)
    .then((userCredential) =&gt; {
      const user = userCredential.user;
      updateProfile(user, { displayName: name }); // 가입한 유저 정보에 이름을 저장한다.
      // console.log(user);
      toast.success(&quot;회원가입이 완료 되었습니다.&quot;);
    })
    .catch((error) =&gt; {
      const errorCode = error.code;

      switch (errorCode) {
        case &quot;auth/weak-password&quot;:
          toast.error(&quot;비밀번호는 6자리 이상이어야 합니다.&quot;);
          break;
        case &quot;auth/invalid-email&quot;:
          toast.error(&quot;잘못된 이메일 형식입니다.&quot;);
          break;
        case &quot;auth/email-already-in-use&quot;:
          toast.error(&quot;이미 사용중인 이메일 입니다.&quot;);
          break;
      }
    });
};</code></pre>
<blockquote>
<p>위에 보이듯이 <code>props</code> 값으로 <code>name</code> , <code>email</code>, <code>password</code> 를 받아오고 회원가입이 성공적으로 완료 된다면 <code>displayName</code> 에 <code>name</code> 값을 넣어준다. 그 후에 성공 메세지를 출력해준다.</p>
</blockquote>
<blockquote>
<p>공식문서
<a href="https://firebase.google.com/docs/auth/web/password-auth?hl=ko">https://firebase.google.com/docs/auth/web/password-auth?hl=ko</a>
사용자 프로필 업데이트
<a href="https://firebase.google.com/docs/auth/web/manage-users?hl=ko">https://firebase.google.com/docs/auth/web/manage-users?hl=ko</a></p>
</blockquote>
<h3 id="만약-오류가-발생한다면">만약 오류가 발생한다면,</h3>
<p>밑에 보이는 사진 처럼 오류 메세지를 전송해주고,
<img src="https://velog.velcdn.com/images/si_do/post/5a475ecb-3448-4bfe-9d41-425d34458511/image.png" alt=""></p>
<h3 id="회원가입이-성공적으로-완료된다면">회원가입이 성공적으로 완료된다면,</h3>
<p>회원가입이 완료 되었다는 메세지가 출력된다.</p>
<p><img src="https://velog.velcdn.com/images/si_do/post/b0c94a23-37d3-4c97-bfd0-c944e1b4042f/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/si_do/post/262583fb-2687-4df8-8a6f-3fc7d701b7f5/image.png" alt=""></p>
<p>Fireabase 에 사용자 정보가 잘 등록 된 모습을 볼 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/si_do/post/ccb4d858-40a8-46e6-a0b2-5641df1927ff/image.png" alt=""></p>
<hr>
<h2 id="🔥-오류-사항">🔥 오류 사항</h2>
<blockquote>
<p>입력 폼 CSS 에 문제가 있다는 것을 발견했다!!
원래는 Focus 값에 대해서만 생각해서 Css값을 줬는데 ,
Input에 값이 있어도 Focus가 아웃되면 blur 함수가 실행되면서 value 값을 가려버린다. input 에 대한 css 로직을 다시 구상해야 할 것 같다.</p>
</blockquote>
<hr>
<h3 id="🚀-다음-구현-내용">🚀 다음 구현 내용</h3>
<blockquote>
<p>이제 이메일 회원가입과 Google계정으로 로그인 하는 것을 완료 했으니 firebase에 등록된 사용자 정보를 이용하여 로그인/로그아웃 기능을 구현 해 볼 것이다!</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[인풋 버튼 애니메이션 ]]></title>
            <link>https://velog.io/@si_do/%EC%9D%B8%ED%92%8B-%EB%B2%84%ED%8A%BC-%EC%95%A0%EB%8B%88%EB%A9%94%EC%9D%B4%EC%85%98</link>
            <guid>https://velog.io/@si_do/%EC%9D%B8%ED%92%8B-%EB%B2%84%ED%8A%BC-%EC%95%A0%EB%8B%88%EB%A9%94%EC%9D%B4%EC%85%98</guid>
            <pubDate>Sat, 22 Apr 2023 11:20:44 GMT</pubDate>
            <description><![CDATA[<p>로그인 페이지를 만들 던 중 label을 placeholder 처럼 쓰면서 애니메이션을 주고 싶어 어떻게 할 지 생각하다 본게 밑에 보이는 애니메이션이다.</p>
<p>간단하게 설명하자면 input에 <code>focus</code>되면 label 글자가 왼쪽 위 방향으로 올라가고 인풋이 아닌 다른 부분을 클릭하면 다시돌아와서 사용자가 글자를 입력하는 곳에 방해를 주지 않게 해주는 것 이다. label을 placeholder 처럼 사용하는 가장 멋진 일 이라고 생각해서 한 번 구현해  보기로 하였다.
<img src="https://velog.velcdn.com/images/si_do/post/7775574e-b853-4242-acbd-a367cba2c1c2/image.gif" alt=""></p>
<hr>
<h3 id="💫-생각한-구조">💫 생각한 구조</h3>
<blockquote>
<ol>
<li><code>input</code> 요소에 onFocus 와 onBlur 이벤트를 준다.</li>
<li><code>isFocus</code> 라는 <code>State</code> 를 만들어서 초기값을 false로 지정한다.</li>
<li><code>handleFocus</code> 와 <code>handleBlur</code> 함수를 만들어 포커스와 블러가 될 때 <code>state</code> 값을 <code>toggle</code> 하게 만들어준다.</li>
<li><code>Tailwind</code> 를 사용하였으므로 <code>className</code> 값에 삼항연산자를 사용하여 <code>isFocus</code>가 <code>true</code>,<code>false</code> 일때의 스타일을 다르게 지정해준다.</li>
</ol>
</blockquote>
<hr>
<h3 id="❗️문제">❗️문제</h3>
<p>구현을 완료했는데 한가지 문제 사항이 생겼다. 두개의 input에 같은 함수를 사용하였기 때문에 Email 인풋을 포커스 할 때도 2개의 인풋이 전부 애니메이션 되고 Password 인풋을 포커스 할 때도 2개의 인풋이 전부 애니메이션 된다는 것이였다!!😿</p>
<h3 id="🔥해결">🔥해결</h3>
<p>어떻게 해야할 지 고민하다가 <code>ref</code>를 사용해서 <code>input element</code>를 따로 선택 해 줘서 함수에 입력해줄까 했는데 생각대로 잘 되지 않았었다. (Typescript도 처음이라 ref문에서 자꾸 오류가 났다😭)</p>
<p>그래서 결국 밑에 보이는 코드와 같이 <code>Email</code> 인풋의 <code>Focus</code> , <code>Blur</code> 함수를 따로만들고 <code>Password</code> 인풋의 <code>Focus</code>,<code>Blur</code>를 따로 만들었다.</p>
<pre><code class="language-javascript">  const handleEmailFocus = () =&gt; {
    setIsFocus(!isFocus);
  };
  const handleEmailBlur = () =&gt; {
    setIsFocus(!isFocus);
  };
  const handlePwFocus = () =&gt; {
    setIsFocusPw(!isFocusPw);
  };
  const handlePwBlur = () =&gt; {
    setIsFocusPw(!isFocusPw);
  };
</code></pre>
<p>그리고 각각의 인풋에다가 함수들을 넣어줬다.</p>
<pre><code>  &lt;div className=&quot;relative&quot;&gt;
        &lt;label htmlFor=&quot;email&quot; className={`text-md absolute font-gray-600 transition ease-in-out left-3 top-4 ${isFocus ? &quot;-translate-x-2&quot; : &quot;&quot;} ${isFocus ? &quot;-translate-y-3&quot; : &quot;&quot;} ${isFocus ? &quot;scale-75&quot; : &quot;&quot;}`}&gt;
          이메일
        &lt;/label&gt;
        &lt;input onBlur={handleEmailBlur} onFocus={handleEmailFocus} type=&quot;text&quot; id=&quot;email&quot; name=&quot;email&quot; className={`border border-gray-600 w-full rounded-[4px] h-14 pt-4 pl-3 mb-1`} /&gt;
      &lt;/div&gt;
      &lt;div className=&quot;relative&quot;&gt;
        &lt;label htmlFor=&quot;pw&quot; className={`text-md absolute font-gray-600 transition ease-in-out left-3 top-4 ${isFocusPw ? &quot;-translate-x-2&quot; : &quot;&quot;} ${isFocusPw ? &quot;-translate-y-3&quot; : &quot;&quot;} ${isFocusPw ? &quot;scale-75&quot; : &quot;&quot;}`}&gt;
          비밀번호
        &lt;/label&gt;
        &lt;input onBlur={handlePwBlur} onFocus={handlePwFocus} type=&quot;text&quot; id=&quot;pw&quot; name=&quot;pw&quot; className={`border border-gray-600 w-full rounded-[4px] h-14 pt-4 pl-3 mb-2`} /&gt;
      &lt;/div&gt;</code></pre><hr>
<h3 id="🧚♀️-마지막으로">🧚‍♀️ 마지막으로</h3>
<p>사실 지금 위에 함수를 보면 똑같은 기능을 하는 함수가 2개씩 따로따로 구성 되어있다. 이렇게 사용하는 방식은 좋지 않다고 생각한다. 그래서 나중에 이부분을 한번 생각해보고 고쳐볼 생각이다!!</p>
<blockquote>
<p>이렇게 하는 방식보다 더 좋은 방식이 있다면 알려주세요 고수분들😿</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[React 로 만드는 음악 커뮤니티 사이트 #2 (Firebase로 로그인 셋업)]]></title>
            <link>https://velog.io/@si_do/React-%EB%A1%9C-%EB%A7%8C%EB%93%9C%EB%8A%94-%EC%9D%8C%EC%95%85-%EC%BB%A4%EB%AE%A4%EB%8B%88%ED%8B%B0-%EC%82%AC%EC%9D%B4%ED%8A%B8-2-Firebase%EB%A1%9C-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@si_do/React-%EB%A1%9C-%EB%A7%8C%EB%93%9C%EB%8A%94-%EC%9D%8C%EC%95%85-%EC%BB%A4%EB%AE%A4%EB%8B%88%ED%8B%B0-%EC%82%AC%EC%9D%B4%ED%8A%B8-2-Firebase%EB%A1%9C-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0</guid>
            <pubDate>Thu, 20 Apr 2023 09:03:44 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>오늘은 회원정보와 게시물 관리 등을 위하여 Firebase를 이용한 인증 기능을 구현 해 볼 것이다.</p>
</blockquote>
<h1 id="firebase-프로젝트-생성-및-로그인-설정">Firebase 프로젝트 생성 및 로그인 설정</h1>
<h2 id="프로젝트-추가하기">프로젝트 추가하기<img src="https://velog.velcdn.com/images/si_do/post/32a7c4b5-ff25-4319-a617-208d185f9592/image.png" alt=""></h2>
<blockquote>
<p>firebase 콘솔로 이동하면 보이는 메인페이지다. 프로젝트 추가 버튼을 눌러서 새로운 프로젝트를 생성한다.</p>
</blockquote>
<h2 id="로그인-제공-방법-선택">로그인 제공 방법 선택</h2>
<ul>
<li>프로젝트 관리 페이지에서 빌드 - Authentication 탭으로 들어가서 시작하기를 눌러준다.
<img src="https://velog.velcdn.com/images/si_do/post/7c7a1a14-3314-4c97-b034-2f00ebd0c1c3/image.png" alt=""><blockquote>
<p>본인은 이메일과 구글 로그인만 일단 구현 해 볼 것이기  때문에 두개만 선택 해 주었다.</p>
</blockquote>
</li>
</ul>
<h2 id="firebase-앱-생성하기">Firebase 앱 생성하기</h2>
<p><img src="https://velog.velcdn.com/images/si_do/post/4767e8f0-f9ab-4816-b686-f3713bc383ba/image.png" alt=""></p>
<blockquote>
<p>프로젝트 메인화면에서 앱을 추가해준다. 웹으로 만들거기 떄문에 Web을 선택해주면 된다.</p>
</blockquote>
<p>앱이름을 누르고 작성하면 SDK가 추가된다.
<img src="https://velog.velcdn.com/images/si_do/post/c54f3a35-2d2d-406b-8cae-df1af2dc2e00/image.png" alt=""></p>
<blockquote>
<p>SDK는 프로젝트 설정 -&gt; 일반 에서 언제든지 확인 가능하다.</p>
</blockquote>
<h2 id="firebase-앱-초기화">Firebase 앱 초기화</h2>
<p>저는 firebase 기능만 담은 firebase.ts 파일을 생성하였습니다.
( src / api / firebase.ts )
firebase.ts에 SDK로 생성한 스크립트를 붙여넣어줍니다.
<img src="https://velog.velcdn.com/images/si_do/post/fce2bc29-f989-4144-b68e-c41c750a5401/image.png" alt=""></p>
<blockquote>
<p>보안문제를 위해 SDK로 받은 키들을 .env에 저장하였다.</p>
</blockquote>
<p>다음 게시물에서 로그인 기능을 구현 해 보도록 하겠다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[React 로 만드는 음악 커뮤니티 사이트 #1]]></title>
            <link>https://velog.io/@si_do/React-%EB%A1%9C-%EB%A7%8C%EB%93%9C%EB%8A%94-%EC%9D%8C%EC%95%85-%EC%BB%A4%EB%AE%A4%EB%8B%88%ED%8B%B0-%EC%82%AC%EC%9D%B4%ED%8A%B8</link>
            <guid>https://velog.io/@si_do/React-%EB%A1%9C-%EB%A7%8C%EB%93%9C%EB%8A%94-%EC%9D%8C%EC%95%85-%EC%BB%A4%EB%AE%A4%EB%8B%88%ED%8B%B0-%EC%82%AC%EC%9D%B4%ED%8A%B8</guid>
            <pubDate>Thu, 20 Apr 2023 08:40:05 GMT</pubDate>
            <description><![CDATA[<p>이번에 React로 만드는 게시판 기능을 구현해보고 싶어 어떤 사이트를 만들까 고민하다가
그냥 커뮤니티 사이트보다 특정 타겟을 삼은 커뮤니티를 만들어보고 싶어서 내 원래 전공 이었던
음악하는 사람들을 위한 커뮤니티를 만들기로 했다. (음악하는 사람이 아니여도 음악을 좋아하는 사람들을 위한)</p>
<p>그리고 Typescript도 함께 공부하기 위해 Typescript 를 사용 할 거고 로그인이나 호스팅은 사용해 본 적이 있던
FIrebase 를 이용하기로 했다. 그리고 사용해 보지 않았던 다른 라이브러리들을 사용 해 볼 예정이다.</p>
<h1 id="1구성">1.구성</h1>
<ul>
<li>React + Typescript</li>
<li>Firebase</li>
<li>Tailwindcss</li>
</ul>
<hr>
<h2 id="2구조">2.구조</h2>
<p>일단은 생각 해 본 게 가장 적합하다고 생각되는 게시판들이다.</p>
<ul>
<li>Firebase    를 이용한 게시물 , 회원관리</li>
<li>음악 추천 게시판</li>
<li>아티스트 추천 게시판</li>
<li>자유게시판</li>
</ul>
<hr>
<blockquote>
<p>앞으로 이사이트를 만들어 나가면서 내가 몰랐던 부분이나 지식들을 정리해 가면서 공부해볼 예정이다!</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React.js] useState 란 무엇인가?]]></title>
            <link>https://velog.io/@si_do/React.js-useState-%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80</link>
            <guid>https://velog.io/@si_do/React.js-useState-%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80</guid>
            <pubDate>Wed, 25 Jan 2023 06:14:47 GMT</pubDate>
            <description><![CDATA[<h3 id="usestate-와-hook">useState 와 Hook</h3>
<blockquote>
<p>Hook을 이용하여 기존 Class 바탕의 코드를 작성할 필요 없이 상태값과 여러 React의 기능을 사용할 수 있게된다.
-&gt; Hook은 함수형 컴포넌트에 기능을 추가할 때 사용하는 함수, 함수형 컴포넌트에서 상태값을 사용할 수 있고 자식요소에 접근할 수 있음
<br>
useState 는 React의 훅 중 가장 기본적인 훅인다.</p>
</blockquote>
<h2 id="usestate-란">useState 란?</h2>
<ul>
<li>useState는 컴포넌트에서 state값을 추가할 때 사용된다. 함수형 컴포넌트에서는 클래스형 컴포넌트처럼 state를 사용할 수 없어, Hook을 사용해서 state와 같은 기능을 할 수 있도록 만들어준다.<br></li>
<li>하나의 useState 함수는 하나의 상태 값만 관리를 할 수 있어 만약에 컴포넌트에서 관리해야 할 상태가 여러 개라면 useState를 여러번 사용해야한다.<br>
</li>
</ul>
<hr>
<h1 id="사용법">사용법</h1>
<h3 id="1-import-해오기">1. Import 해오기</h3>
<pre><code class="language-javascript">import React, { useState } from &#39;react&#39;;</code></pre>
<br>

<h3 id="2usestate-선언하기">2.useState 선언하기</h3>
<pre><code class="language-javascript">const [state,setState] = useState(초기값);</code></pre>
<ul>
<li>const [state,setState]<blockquote>
<p>useState()가 호출되면 배열을 반환하는데, 그 배열의 첫번째 원소는 상태값이고, 두번째 원소는 상태를 업데이트하는 함수이다. 이 함수에 파라미터를 넣어서 호출하게 되면 전달받은 파라미터로 값이 바뀌게 되고 컴포넌트는 정상적으로 리렌더링 된다.</p>
</blockquote>
</li>
<li>setState<blockquote>
<p>count값을 업데이트하는 함수. 클래스 컴포넌트에서의 this.setState는 이전 state와 새로운 state를 합치지만 얘는 이전값을 덮어쓴다.</p>
</blockquote>
</li>
<li>useState(0)<blockquote>
<p>숫자 0은 초기값을 의미. useState는 인자로 초기 state 설정값을 하나 받는다. 이 초기값은 첫 번째 렌더링 시에 딱 한 번 사용된다.</p>
</blockquote>
</li>
</ul>
<h3 id="3setstate-를-사용해-상태값-변경하기">3.setState 를 사용해 상태값 변경하기</h3>
<pre><code class="language-javascript">function Example() { 

const [count, setCount] = useState(0);         // &quot;count&quot;라는 새로운 상태 값을 정의

return (
    &lt;div&gt; 
        &lt;p&gt; You clicked {count} times&lt;/p&gt; 
        &lt;button onClick={() =&gt;         
            setCount(count + 1)         //setCount 로 count의 상태 값 변경
        }&gt; Click me &lt;/button&gt; 
    &lt;/div&gt; ); 
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Javascript] 배열 메소드 정리]]></title>
            <link>https://velog.io/@si_do/Javascript-%EB%B0%B0%EC%97%B4-%EB%A9%94%EC%86%8C%EB%93%9C-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@si_do/Javascript-%EB%B0%B0%EC%97%B4-%EB%A9%94%EC%86%8C%EB%93%9C-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Fri, 20 Jan 2023 04:01:33 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>오늘은 배열에 관한 메소드 들을 정리 해봤다.</p>
</blockquote>
<h3 id="pop">pop()</h3>
<ul>
<li>배열 뒷부분의 값을 삭제하는 메서드<pre><code class="language-javascript">var arr=[1,2,3,4];
arr.pop();
console.log(arr); // [1,2,3]
</code></pre>
</li>
</ul>
<pre><code>
&lt;br&gt;

### push()
- 배열 뒷부분에 값을 삽입하는 메서드
```javascript
var arr=[1,2,3,4];
arr.push(5);
console.log(arr); // [1,2,3,4,5] 
</code></pre><br>

<h3 id="unshift">unshift()</h3>
<ul>
<li>배열 앞부분에 값을 삽입<pre><code class="language-javascript">var arr=[1,2,3,4];
arr.unshift(0);
console.log(arr); // [0,1,2,3,4] 
</code></pre>
</li>
</ul>
<pre><code>
&lt;br&gt;

### shift()
- 배열 앞부분에 값을 삭제
```javascript
var arr=[1,2,3,4];
arr.shift();
console.log(arr); // [2,3,4] 
</code></pre><br>

<h3 id="splice">splice()</h3>
<ul>
<li>배열 특정위치에 요소를 추가하거나 삭제</li>
<li>splice( index , 제거할 요소 갯수 , 배열에 추가될 요소 )<pre><code class="language-javascript">var arr = [ 1, 2, 3, 4, 5, 6, 7 ];
arr.splice( 3, 2 );
console.log( arr ); // [ 1, 2, 3, 6, 7 ]   3번째 인덱스에서부터 2개 제거

</code></pre>
</li>
</ul>
<p>var arr = [ 1, 2, 3, 4, 5, 6, 7 ];
arr.splice( 2, 1, &quot;a&quot;, &quot;b&quot;);
console.log( arr ); // [ 1, 2, &quot;a&quot;, &quot;b&quot;, 4, 5, 6, 7 ] 2번째 인덱스에서 1개 제거 후 &quot;a&quot;와 &quot;b&quot;를 추가</p>
<pre><code>
&lt;br&gt;

### slice()
- 배열의 startIndex부터 endIndex까지(endIndex는 불포함)에 대한 shallow copy를 새로운 배열 객체로 반환

```javascript
var arr = [ 1, 2, 3, 4, 5, 6, 7 ];
var newArr = arr.slice( 3, 6 );
console.log( &#39;slice&#39;,  newArr ); // [ 4, 5, 6 ]</code></pre><br>

<h3 id="concat">concat()</h3>
<ul>
<li>다수의 배열을 합치고 합친 새로운 배열을 반환</li>
</ul>
<pre><code class="language-javascript">var arr1 = [ 1, 2, 3 ];
var arr2 = [ 4, 5, 6 ];
var arr3 = arr1.concat( arr2 );
console.log( arr3 ); // [ 1, 2, 3, 4, 5, 6 ]</code></pre>
<br>

<h3 id="every">every()</h3>
<ul>
<li>배열의 모든 요소가 제공한 함수로 구현된 테스트를 통과하는지를 테스트</li>
</ul>
<pre><code class="language-javascript">var arr =[ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
var isEven = function( value ) {

  // value가 2의 배수이면 true를 반환한다.
  return value % 2 === 0;
};
console.log( arr.every( isEven ) ); // false  모든 요소가 true이면 true를 return 하고 그렇지 않으면 false</code></pre>
<br>

<h3 id="some">some()</h3>
<ul>
<li>지정된 함수의 결과가 true일 때까지 배열의 각 원소를 반복</li>
</ul>
<pre><code class="language-javascript">var arr =[ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
var isEven = function( value ) {

  // value가 2의 배수이면 true를 반환한다.
  return value % 2 === 0;
};
console.log( arr.some( isEven ) ); // true  하나라도 true이면 true를 return</code></pre>
<br>

<h3 id="foreach">forEach()</h3>
<ul>
<li>배열의 각 원소별로 지정된 함수를 실행한다.</li>
</ul>
<pre><code class="language-javascript">var arr =[ 1, 2, 3 ];
arr.forEach( function( value ) {
  console.log( value );   // 1 2 3
});</code></pre>
<br>

<h3 id="map">map()</h3>
<ul>
<li>배열의 각 원소별로 지정된 함수를 실행한 결과로 구성된 새로운 배열을 반환한다.</li>
</ul>
<pre><code class="language-javascript">var arr =[ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
var isEven = function( value ) {
  return value % 2 === 0;
};
var newArr = arr.map( isEven );
console.log( newArr ); // [ false, true, false, true, false, true, false, true, false, true ]</code></pre>
<br>

<h3 id="filter">filter()</h3>
<ul>
<li>지정된 함수의 결과 값을 true로 만드는 원소들로만 구성된 별도의 배열을 반환한다.</li>
</ul>
<pre><code class="language-javascript">var arr =[ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
var isEven = function( value ) {
  return value % 2 === 0;
};
var newArr = arr.filter( isEven );
console.log( newArr ); // [ 2, 4, 6, 8, 10 ]</code></pre>
<br>

<h3 id="reverse">reverse()</h3>
<ul>
<li>배열의 원소 순서를 반대로 바꾼다.</li>
</ul>
<pre><code class="language-javascript">var arr =[ 1, 2, 3, 4 ];
arr.reverse();
console.log( arr ); // [ 4, 3, 2, 1 ]</code></pre>
<br>

<h3 id="tostring">toString()</h3>
<ul>
<li>배열을 문자열로 바꾸어 반환한다</li>
</ul>
<pre><code class="language-javascript">var arr =[ 1, 2, 3, 4 ];
console.log( arr.toString() ); // 1, 2, 3, 4</code></pre>
<br>

<h3 id="valueof">valueOf()</h3>
<ul>
<li>toString과 비슷하지만 배열을 반환 (toString 은 문자열을 반환)</li>
</ul>
<pre><code class="language-javascript">var arr =[ 1, 2, 3, 4 ];
console.log( arr.toString() ); // 1, 2, 3, 4</code></pre>
<br>

<h3 id="join">join()</h3>
<ul>
<li>배열 원소 전부를 하나의 문자열로 합친다.</li>
</ul>
<pre><code class="language-javascript">var arr =[ 1, 2, 3, 4 ];
console.log( arr.join() );      // 1,2,3,4
console.log( arr.join( &#39;-&#39; ) ); // 1-2-3-4</code></pre>
<br>

<h3 id="sort">sort()</h3>
<ul>
<li>배열을 정렬하기 위해 사용하는 함수</li>
</ul>
<pre><code class="language-javascript">//오름차순 정렬
const arr = [2, 1, 3, 10];

arr.sort(function(a, b)  {
  return a - b;
});
document.writeln(arr + &#39;&lt;br&gt;&#39;); // [1, 2, 3, 10]

//내림차순 정렬
const arr = [2, 1, 3, 10];

arr.sort(function(a, b)  {
  return b - a;
});
document.writeln(arr + &#39;&lt;br&gt;&#39;); // [10, 3, 2, 1]

//객체 정렬
const arr = [
  {name: &#39;banana&#39;, price: 3000}, 
  {name: &#39;apple&#39;, price: 1000},
  {name: &#39;orange&#39;, price: 500}
];

arr.sort(function(a, b) {
  return a.price - b.price;
});

document.writeln(JSON.stringify(arr[0]) + &#39;&lt;br&gt;&#39;);
document.writeln(JSON.stringify(arr[1]) + &#39;&lt;br&gt;&#39;);
document.writeln(JSON.stringify(arr[2]) + &#39;&lt;br&gt;&#39;);</code></pre>
<br>]]></description>
        </item>
        <item>
            <title><![CDATA[[Vue] Vuetify 사용하기]]></title>
            <link>https://velog.io/@si_do/Vue-Vuetify-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@si_do/Vue-Vuetify-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0</guid>
            <pubDate>Mon, 09 Jan 2023 03:32:02 GMT</pubDate>
            <description><![CDATA[<h1 id="vuetify란-무엇인가">Vuetify란 무엇인가?</h1>
<ul>
<li>뷰 자바스크립트 프레임워크에 머티리얼 디자인을 사용할 수 있는 컴포넌트 프레임워크</li>
<li>구글의 머티리얼 디자인 스펙 2를 충실하게 표현</li>
<li>현대 웹앱에 필요한 컴포넌트를 편리하게 사용</li>
</ul>
<hr>
<h2 id="뷰티파이가-주목받는-4가지-특징">뷰티파이가 주목받는 4가지 특징</h2>
<ol>
<li>구글 머티리얼 스펙의 충실한 지원</li>
<li>80개 이상의 시맨틱 머티리얼 디자인 컴포넌트</li>
<li>빠른속도</li>
<li>쉬운 학습 곡선<h3 id="vuetify-참고-사이트">vuetify 참고 사이트</h3>
</li>
</ol>
<ul>
<li><a href="https://vuetifyjs.com/">https://vuetifyjs.com/</a></li>
</ul>
<hr>
<h2 id="vuetify-시작하기">Vuetify 시작하기</h2>
<h3 id="cdn으로-시작하기">CDN으로 시작하기</h3>
<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
  &lt;link href=&quot;https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900&quot; rel=&quot;stylesheet&quot;&gt;
  &lt;link href=&quot;https://cdn.jsdelivr.net/npm/@mdi/font@6.x/css/materialdesignicons.min.css&quot; rel=&quot;stylesheet&quot;&gt;
  &lt;link href=&quot;https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.min.css&quot; rel=&quot;stylesheet&quot;&gt;
  &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui&quot;&gt;
&lt;/head&gt;
&lt;body&gt;
  &lt;div id=&quot;app&quot;&gt;
    &lt;v-app&gt;
      &lt;v-main&gt;
        &lt;v-container&gt;Hello world&lt;/v-container&gt;
      &lt;/v-main&gt;
    &lt;/v-app&gt;
  &lt;/div&gt;

  &lt;script src=&quot;https://cdn.jsdelivr.net/npm/vue@2.x/dist/vue.js&quot;&gt;&lt;/script&gt;
  &lt;script src=&quot;https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.js&quot;&gt;&lt;/script&gt;
  &lt;script&gt;
    new Vue({
      el: &#39;#app&#39;,
      vuetify: new Vuetify(),
    })
  &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre>
<p>위 템플릿은 html 문서에 붙혀넣기 해주면 기본 세팅 완성</p>
<blockquote>
<p>템플릿은 vuetify.com 에서 제공함</p>
</blockquote>
<h3 id="npm으로-시작하기">npm으로 시작하기</h3>
<h4 id="1-vue-cli로-프로젝트를-설정한다">1. vue CLI로 프로젝트를 설정한다.</h4>
<pre><code>create vue [프로젝트 명]</code></pre><h4 id="2-초기-프로젝트를-구성한-뒤--vuetify를-vue-cli로-설치">2. 초기 프로젝트를 구성한 뒤 , vuetify를 vue-cli로 설치</h4>
<pre><code>vue add vuetify</code></pre><h4 id="3-vuetifycom-홈페이지에서-필요한-기능들을-찾아서-사용하기-">3. vuetify.com 홈페이지에서 필요한 기능들을 찾아서 사용하기 !</h4>
<hr>
<h2 id="예제---기본3단-레이아웃-만들기">예제 - 기본3단 레이아웃 만들기</h2>
<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html&gt;
  &lt;head&gt;
    &lt;link href=&quot;https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900&quot; rel=&quot;stylesheet&quot; /&gt;
    &lt;link href=&quot;https://cdn.jsdelivr.net/npm/@mdi/font@6.x/css/materialdesignicons.min.css&quot; rel=&quot;stylesheet&quot; /&gt;
    &lt;link href=&quot;https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.min.css&quot; rel=&quot;stylesheet&quot; /&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui&quot; /&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;div id=&quot;app&quot;&gt;
      &lt;v-app&gt;
        &lt;!-- 앱 바 색상을 primary로 설정하고 fixed로 위치 고정 --&gt;
        &lt;v-app-bar app color=&quot;primary&quot; dark fixed&gt;
          &lt;v-app-bar-nav-icon&gt;&lt;/v-app-bar-nav-icon&gt;
          &lt;v-toolbar-title&gt;마스터 페이지&lt;/v-toolbar-title&gt;
          &lt;!-- 우측에 추가메뉴 아이콘을 넣기 위해 v-spacer 엘리먼트 사용 --&gt;
          &lt;v-spacer&gt;&lt;/v-spacer&gt;
          &lt;v-btn icon&gt;
            &lt;v-icon&gt;mdi-dots-vertical&lt;/v-icon&gt;
          &lt;/v-btn&gt;
        &lt;/v-app-bar&gt;

        &lt;!-- v-main --&gt;
        &lt;v-main&gt;
          &lt;v-container&gt;
            &lt;h1 class=&quot;display-1 my-5&quot;&gt;안녕하세요&lt;/h1&gt;
            &lt;p class=&quot;body-2 my-4&quot;&gt;마스터 페이지 입니다.&lt;/p&gt;
            &lt;v-divider&gt;&lt;/v-divider&gt;
            &lt;h1 class=&quot;display-3 my-4&quot;&gt;안녕하세요&lt;/h1&gt;
            &lt;p class=&quot;body-3 my-4&quot;&gt;마스터 페이지 입니다.&lt;/p&gt;
          &lt;/v-container&gt;
        &lt;/v-main&gt;

        &lt;!-- footer 색상을 secondary로 설정하고 fixed로 위치 고정 --&gt;
        &lt;v-footer color=&quot;secondary&quot; dark fixed&gt;
          &lt;div class=&quot;mx-auto&quot;&gt;Copyright &amp;copy;&lt;/div&gt;
        &lt;/v-footer&gt;
      &lt;/v-app&gt;
    &lt;/div&gt;

    &lt;script src=&quot;https://cdn.jsdelivr.net/npm/vue@2.x/dist/vue.js&quot;&gt;&lt;/script&gt;
    &lt;script src=&quot;https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.js&quot;&gt;&lt;/script&gt;
    &lt;script&gt;
      new Vue({
        el: &quot;#app&quot;,
        vuetify: new Vuetify(),
      });
    &lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;
</code></pre>
<p><img src="https://velog.velcdn.com/images/si_do/post/e10307eb-f754-4b61-86fe-367318a857d0/image.png" alt=""></p>
<h2 id="예제-2---카드-ui-만들기">예제 2 - 카드 UI 만들기</h2>
<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html&gt;
  &lt;head&gt;
    &lt;link href=&quot;https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900&quot; rel=&quot;stylesheet&quot; /&gt;
    &lt;link href=&quot;https://cdn.jsdelivr.net/npm/@mdi/font@6.x/css/materialdesignicons.min.css&quot; rel=&quot;stylesheet&quot; /&gt;
    &lt;link href=&quot;https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.min.css&quot; rel=&quot;stylesheet&quot; /&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui&quot; /&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;div id=&quot;app&quot;&gt;
      &lt;v-app&gt;
        &lt;v-main&gt;
          &lt;v-container&gt;
            &lt;!-- 카드 UI 사용을 선언하는 v-card 엘리먼트 --&gt;
            &lt;v-card max-width=&quot;400&quot;&gt;
              &lt;!-- 카드 상단에 이미지 배치 --&gt;
              &lt;v-img src=&quot;../img/microphone-7495739_1920.jpg&quot; aspect-ritio=&quot;2&quot;&gt;&lt;/v-img&gt;

              &lt;!-- 카드 중간에 텍스트 배치 --&gt;
              &lt;v-card-text&gt;
                &lt;div&gt;
                  &lt;h2 class=&quot;title primary--text mb-2&quot;&gt;카드 UI&lt;/h2&gt;
                  &lt;p class=&quot;mb-0&quot;&gt;카드 디자인에 출력될 텍스트를 입력합니다.&lt;/p&gt;
                &lt;/div&gt;
              &lt;/v-card-text&gt;

              &lt;!-- 카드 하단에 버튼 배치 --&gt;
              &lt;v-card-actions&gt;
                &lt;v-btn color=&quot;red white--text&quot;&gt;확인&lt;/v-btn&gt;
                &lt;v-btn outlined color=&quot;red&quot;&gt;취소&lt;/v-btn&gt;
                &lt;v-btn color=&quot;#9C27B0&quot; dark&gt;취소&lt;/v-btn&gt;
              &lt;/v-card-actions&gt;
            &lt;/v-card&gt;
          &lt;/v-container&gt;
        &lt;/v-main&gt;
      &lt;/v-app&gt;
    &lt;/div&gt;

    &lt;script src=&quot;https://cdn.jsdelivr.net/npm/vue@2.x/dist/vue.js&quot;&gt;&lt;/script&gt;
    &lt;script src=&quot;https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.js&quot;&gt;&lt;/script&gt;
    &lt;script&gt;
      new Vue({
        el: &quot;#app&quot;,
        vuetify: new Vuetify(),
      });
    &lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;
</code></pre>
<p><img src="https://velog.velcdn.com/images/si_do/post/bc853488-4b6d-4639-8314-8d85f6209faa/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Vue] Vue-cli 설치와 프로젝트 생성]]></title>
            <link>https://velog.io/@si_do/Vue-Vue-cli-%EC%84%A4%EC%B9%98%EC%99%80-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%83%9D%EC%84%B1</link>
            <guid>https://velog.io/@si_do/Vue-Vue-cli-%EC%84%A4%EC%B9%98%EC%99%80-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%83%9D%EC%84%B1</guid>
            <pubDate>Fri, 06 Jan 2023 09:46:39 GMT</pubDate>
            <description><![CDATA[<h2 id="vue-cli-시작하기">Vue-cli 시작하기</h2>
<h3 id="vue-clicommand-line-interface">Vue-cli(Command Line Interface)</h3>
<ul>
<li>vue 개발환경을 설정해는 명령어 실행 도구</li>
<li>기본적인 프로젝트 구조 세팅으로 디렉토리 구조 및 webpack 등 설정</li>
</ul>
<h3 id="vue-cli-설치">Vue-cli 설치</h3>
<p>-기본적으로 <strong>Node.js</strong> 및 <strong>npm</strong>이 설치 되어있어야 한다.</p>
<pre><code>#global 설치
npm install -g @vue/cli

#버전확인
vue --version </code></pre><blockquote>
<p>npm install -g @vue/cli 는
컴퓨터 환경 전역에 vue cli를 설치하는 것입니다.</p>
</blockquote>
<h3 id="vue-프로젝트-생성">Vue 프로젝트 생성</h3>
<h4 id="1-프로젝트를-만든-폴더를-생성후-터미널에서-경로-설정">1. 프로젝트를 만든 폴더를 생성후 터미널에서 경로 설정</h4>
<p><img src="https://velog.velcdn.com/images/si_do/post/97f20cc3-6869-4b3b-bde6-2844dd5095c0/image.png" alt=""></p>
<h4 id="2터미널에서-커맨드-입력">2.터미널에서 커맨드 입력</h4>
<pre><code>vue create [프로젝트 명]

vue create .   &lt;-- create . 을하면 현재 선택된 디렉토리에 프로젝트가 생성됨</code></pre><p><img src="https://velog.velcdn.com/images/si_do/post/9cdc7015-d5e8-4ee4-b50a-567ca6fa188e/image.png" alt=""></p>
<blockquote>
<p>vue create . 을 했을때 나오는 문장 // 현재 디렉토리에 프로젝트를 만들 것 인지 묻는다.</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/si_do/post/e3eb1ca1-4c7d-4119-b6fe-465a577ecc45/image.png" alt=""></p>
<blockquote>
<p>y 를 입력하면 Vue3 , Vue2 버전중 선택할 수 있도록 창이 나옴</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/si_do/post/18c03156-de4b-4e1e-882e-f5ffacfc04f8/image.png" alt=""></p>
<blockquote>
<p>선택 후 엔터를 누르면 프로젝트 파일이 자동으로 생성됨</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/si_do/post/86aae73d-5726-496d-a757-7792866277c4/image.png" alt=""></p>
<blockquote>
<p>만들어진 프로젝트</p>
</blockquote>
<h4 id="3서버-작동시키기">3.서버 작동시키기</h4>
<p>터미널을 열고 (vscode 단축키 command+j ) 밑에 있는 코드를 작성해준다. </p>
<pre><code>npm run serve</code></pre><p><img src="https://velog.velcdn.com/images/si_do/post/d82655c3-65ae-4712-9b03-3ae87e8fd262/image.png" alt=""></p>
<blockquote>
<p>⚠️ 꼭 선택된 폴더가 만들어진 프로젝트 폴더 이어야 한다.</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/si_do/post/8ff350a0-fcf9-4fc0-82c0-eccc9ec54470/image.png" alt=""></p>
<blockquote>
<p>이렇게 개발환경 서버를 만들어주는데 네모 박스친 부분에 option + 마우스클릭을 하면 페이지를 열어준다.</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/si_do/post/22c34e4c-8510-4832-b490-d0bdf6c5098b/image.png" alt=""></p>
<blockquote>
<p>이렇게 npm을 이용한 vue 프로젝트 개발환경세팅에 대해 알아보았다. 이제 우리는 vue.js 를 사용할 준비가 완료 된 것이다!!!</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Vue] Vue.js 시작하기 ]]></title>
            <link>https://velog.io/@si_do/Vue-Vue.js-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@si_do/Vue-Vue.js-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0</guid>
            <pubDate>Fri, 06 Jan 2023 07:19:51 GMT</pubDate>
            <description><![CDATA[<h1 id="vue란-무엇인가-">Vue란 무엇인가 ?</h1>
<ul>
<li>프론트엔드 개발을 쉽게하기 위한 react와 함께 대중적인 오픈소스 javascript 프레임워크</li>
<li>MVVM패턴의 ViewModel에 해당하여, UI코드와 데이터제어 제어 로직을 분리</li>
<li>SPA(Single Page Application)를 구축하는데 이용 가능</li>
</ul>
<p><img src="https://velog.velcdn.com/images/si_do/post/7597efb6-312b-4664-b07c-4ba4a0ab0fca/image.png" alt=""></p>
<ul>
<li><p><strong>View(html DOM)</strong>: 사용자에게 보이는 화면.</p>
</li>
<li><p><strong>Model(JS)</strong>: 데이터를 담는 용기, 보통 서버에서 가져온 데이터를 javascript 객체로 저장</p>
</li>
<li><p><strong>ViewModel</strong>: View와 Model의 중간 영역으로 DomListener와 DataBinding을 제공하는 영역</p>
</li>
<li><p><strong>DOM</strong>: HTML 문서에 들어가는 요소(tag, class, attribute 등)의 정보를 담고 있는 데이터 트리</p>
</li>
<li><p><strong>DOM Listener</strong>: DOM의 변경에 대한 즉각적으로 반응하여 특정 로직을 수행하는 장치</p>
</li>
<li><p><strong>Data Binding</strong>: View에 표시되는 내용과 모델의 데이터를 동기화
Vue에서는 기본적으로 단방향 데이터바인딩으로 컴포넌트간 통신은 상위 컴포넌트-&gt;하위컴포넌트로 전달</p>
</li>
</ul>
<hr>
<h2 id="vue의-장점">Vue의 장점</h2>
<ul>
<li>배우기 쉽다</li>
<li>React, Angular에 비해 가볍고 성능이 빠름</li>
<li>React(<strong>Virtual DOM</strong>), Angular(<strong>데이터 바인딩</strong>)의 장점을 취했음</li>
<li>컴포넌트 기반 프레임워크로 레고 블록과 같이 컴포넌트 조합으로 뷰 구성, 코드 재사용 쉬움<blockquote>
<p><strong>Virtual DOM</strong> 이란</p>
</blockquote>
</li>
<li>화면에 변화가 있을 때마다 실시간으로 DOM Tree 를 수정하지 않고 변경사항이 반영된 Virtual DOM을 이용해 메모리에서 처리하고 한 번만 DOM 수정을 한다. 결과적으로 브라우저는 한번만 렌더링을 하게 됨으로써 불필요한 렌더링 횟수를 줄여 렌더링 성능을 높인다</li>
</ul>
<hr>
<blockquote>
<p>다음시간에는 Vue-cli 설치와 프로젝트 생성을 알아보도록 하겠다.</p>
</blockquote>
]]></description>
        </item>
    </channel>
</rss>