<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>semi.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Sat, 18 Sep 2021 14:54:46 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <copyright>Copyright (C) 2019. semi.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/semi_kimm" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[여러 조건문으로 분기시 check point]]></title>
            <link>https://velog.io/@semi_kimm/%EC%97%AC%EB%9F%AC-%EC%A1%B0%EA%B1%B4%EB%AC%B8-%EB%B6%84%EA%B8%B0%EC%8B%9C-check-point</link>
            <guid>https://velog.io/@semi_kimm/%EC%97%AC%EB%9F%AC-%EC%A1%B0%EA%B1%B4%EB%AC%B8-%EB%B6%84%EA%B8%B0%EC%8B%9C-check-point</guid>
            <pubDate>Sat, 18 Sep 2021 14:54:46 GMT</pubDate>
            <description><![CDATA[<p>백준 2884번 문제를 해결하면서 </p>
<p>주어진 테스트 케이스도 올바르게 돌아가고 입력값의 최대 최소값을 입력했을때의 케이스가 정상적으로 동작하는지도 다 확인했지만 채점결과가 틀렸다고 나왔다.</p>
<p>문법적 오류가 발생한것도 아니고 런타임에러가 있는것도 아니고 해서 그렇다면 반례가 있다는 것 일텐데 도저히 어느 부분이 잘못된건지 알 수가 없었다.</p>
<p>채점결과 틀린 코드는 우선 다음과 같다.</p>
<pre><code class="language-python">H, M = input().split(&quot; &quot;)
hour = int(H)
minute = int(M)
dif = minute-45
if dif &lt; 0:
    minute = 60+dif
    hour = hour-1
elif dif == 0:
    minute = minute
else:
    minute = dif
if hour &lt; 0:
    hour = 23
else:
    hour = hour
print(hour, minute, sep=&quot; &quot;)</code></pre>
<p>그러다가 질의 응답을 통해 <strong>여러조건문으로 분기했을때 가장 먼저 테스트 해야할 것이 그 모든 분기들이 실행되는 케이스들을 전부 테스트해보는 것</strong>이라는 걸 알았다.</p>
<p>그렇게 다 확인을 해보니 8번째 줄의 elif dif==0 이라는 조건에서 조건을 만족하면 minute에 dif를 할당해주어야 하는데 minute를 그대로 넣어서 생긴 문제였다.</p>
<p>수정해서 정답으로 인정된 코드는 다음과 같다.</p>
<pre><code class="language-python">H, M = input().split(&quot; &quot;)
hour = int(H)
minute = int(M)
dif = minute-45
if 0 &lt;= hour &lt;= 23 and 0 &lt;= minute &lt;= 59:
    if dif &lt; 0:
        minute = 60+dif
        hour = hour-1
    elif dif == 0:
        minute = dif
    else:
        minute = dif
    if hour &lt; 0:
        hour = 23
    else:
        hour = hour
print(hour, minute, sep=&quot; &quot;)</code></pre>
<p>다음부터는 꼭! 기억하자</p>
<p><strong>여러 조건문으로 분기했을때 가장 먼저 테스트 해야할 것은 그 모든 분기들이 실행되는 케이스들을 전부 테스트해보는 것이다!</strong></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Python] Switch문이 없는 Python]]></title>
            <link>https://velog.io/@semi_kimm/Python-Switch%EB%AC%B8</link>
            <guid>https://velog.io/@semi_kimm/Python-Switch%EB%AC%B8</guid>
            <pubDate>Fri, 17 Sep 2021 16:30:35 GMT</pubDate>
            <description><![CDATA[<p>백준의 1330문제를 풀면서 Python에서는 Switch Case 문이 사용되지 않는다는 것을 알았다.</p>
<p>백준 1330번은 아래의 링크에서 확인이 가능하다. 
<a href="https://www.acmicpc.net/problem/1330">백준 1330번 - 두 수 비교하기 (두개의 정수의 관계를 파악하여 해당 관계에 대한 특정 출력을 해주는 문제)</a></p>
<p>C언어에서도 사용되고 Java에서도 사용되기 때문에 당연히 Python에서도 사용이 될것이라고 생각하였다.</p>
<p>결론은, Python에서는 Switch문이 없어도 if문 또는 dictionary 자료구조를 사용하여 충분히 대체가 가능하기 때문에 즉, 필요하지 않기 때문에 없다는 것이었다.</p>
<p>그렇다면 특정 조건에 따른 결과를 얻고 싶을때 Python에서는 어떻게 구현을 해야 할까?</p>
<p>백준 1330번 문제를 통해 정리해보자</p>
<p><img src="https://images.velog.io/images/semi_kimm/post/64e982cc-a688-47cb-890c-d2d7a7e9a2e8/image.png" alt=""></p>
<h3 id="01-if--elif-문-사용하기">01. if ~ elif 문 사용하기</h3>
<p>if ~ elif 문을 사용하여 위 문제를 해결하려면 다음과 같이 해결 가능하다.</p>
<pre><code class="language-python">a, b = input().split(&quot; &quot;)
A = int(a)
B = int(b)
inputLimitA = A &gt;= -10000 &amp; A &lt;= 10000
inputLimitB = B &gt;= -10000 &amp; B &lt;= 10000
if inputLimitA &amp; inputLimitB:
    if A &gt; B:
        print(&quot;&gt;&quot;)
    elif A &lt; B:
        print(&quot;&lt;&quot;)
    elif A == B:
        print(&quot;==&quot;)</code></pre>
<h3 id="02-dictionary-사용하기">02. dictionary 사용하기</h3>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Python] 특수문자 출력하기]]></title>
            <link>https://velog.io/@semi_kimm/Python-%ED%8A%B9%EC%88%98%EB%AC%B8%EC%9E%90-%EC%B6%9C%EB%A0%A5</link>
            <guid>https://velog.io/@semi_kimm/Python-%ED%8A%B9%EC%88%98%EB%AC%B8%EC%9E%90-%EC%B6%9C%EB%A0%A5</guid>
            <pubDate>Thu, 16 Sep 2021 16:30:52 GMT</pubDate>
            <description><![CDATA[<p>Python 에서 , &quot;, &#39; 순서대로 백슬래시, 큰따옴표, 작은따옴표를 print 출력하기 위해서는 해당 문자 앞에 \ (백슬래시)를 붙여서 적어줘야한다.</p>
<blockquote>
<p>특수문자 출력 예시</p>
</blockquote>
<pre><code class="language-python">print(&quot; 백슬래시 출력 \\ &quot;)</code></pre>
<p>출력 결과는 다음과 같다.
<img src="https://images.velog.io/images/semi_kimm/post/fcb3dda4-7d49-4ba3-985e-674ed0353b40/image.png" alt=""></p>
<p>Python 에서 백슬래시를 통해 사용되는 특수문자 종류는 다음과 같다.</p>
<pre><code class="language-python">print(&quot;\n&quot;) //줄바꿈
print(&quot;\t&quot;) //수평 탭(Tab)
print(&quot;\\&quot;) // \ 백슬래시
print(&quot;\&quot;&quot;) // &quot; 큰 따옴표
print(&quot;\&#39;&quot;) // &#39; 작은 따옴표</code></pre>
<p>문자열 앞에 r을 붙이면 자동으로 특수문자를 \특수문자 로 치환하여 처리해준다.
(단순 처리 시에는 r을 붙이는 방법보다 백슬래시를 직접 입력하는 방법이 처리 시간상 더 효율적인것 같다.)</p>
<blockquote>
<p>예시 </p>
</blockquote>
<pre><code class="language-python">print(r&quot; 백슬래시 출력 \ &quot;)</code></pre>
<p>결과
<img src="https://images.velog.io/images/semi_kimm/post/5a2db4fc-d97a-4079-abdd-7bca12a04fe0/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JavaScript] 동기와 비동기]]></title>
            <link>https://velog.io/@semi_kimm/JavaScript-%EB%8F%99%EA%B8%B0%EB%B9%84%EB%8F%99%EA%B8%B0</link>
            <guid>https://velog.io/@semi_kimm/JavaScript-%EB%8F%99%EA%B8%B0%EB%B9%84%EB%8F%99%EA%B8%B0</guid>
            <pubDate>Wed, 11 Aug 2021 11:57:14 GMT</pubDate>
            <description><![CDATA[<p>작업을 동기적으로 처리하면 작업이 끝날 때까지 기다리는 동안 중지 상태가 되므로 다른 작업을 진행할 수 없다. 
반면, 비동기적으로 처리를 하면 작업의 흐름이 멈추지 않으므로 동시에 작업들을 처리할 수 있으며 기다리는 과정에서 다른 함수를 호출할 수도 있다.</p>
<h2 id="동기적-synchronous">동기적 (Synchronous)</h2>
<hr>
<h2 id="비동기적-asynchronous">비동기적 (Asynchronous)</h2>
<p>주로 비동기적으로 처리하는 작업은 다음과 같다.</p>
<ul>
<li><p>Ajax Web API 요청
: 서버로부터 데이터를 받아올 경우 요청을 하고 서버에서 응답을 할 때까지 대기가 발생한다. 따라서, 작업을 비동기적으로 처리한다.</p>
</li>
<li><p>파일 읽기
: 서버로부터 파일을 읽어야 하는 상황에서 주로 비동기적으로 처리한다.</p>
</li>
<li><p>암호화/복호화
: 암호화/복호화를 할 때에도 대기가 발생하는 경우가 있으므로 비동기적으로 처리한다.</p>
</li>
<li><p>작업 예약
: 특정 작업을 몇초 후 스케쥴링 해야 하는 경우에는 <a href="https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout#Reasons_for_delays_longer_than_specified">setTimeout</a> 을 사용하여 비동기적으로 처리한다.
(setTimeout을 사용하면 지정한 작업이 백그라운드에서 수행되므로 기존의 코드 흐름을 막지 않고 동시에 다른 작업들을 진행할 수 있다.)</p>
</li>
</ul>
<hr>
<p>비동기적 처리의 예시는 아래와 같다.</p>
<pre><code class="language-javascript">function work() {
  setTimeout(() =&gt; {
    console.log(&#39;2&#39;);
  }, 1000);
}
console.log(&#39;1&#39;);
work();
console.log(&#39;3&#39;);</code></pre>
<p>실행 결과
<img src="https://images.velog.io/images/semi_kimm/post/416ed521-3616-4514-9e7c-05630431de38/image.png" alt="">
work()가 console.log(&#39;3&#39;) 보다 먼저 실행되었지만 setTimeout으로 인해 1s뒤에 실행되도록 하였다.
즉, 대기 시간이 1s가 생겼지만 setTimeout의 작업은 백그라운드에서 수행되므로 console.log(&#39;3&#39;)이 먼저 출력이 되고 work()의 console.log(&#39;2&#39;)가 출력이 되었다.</p>
<p>추가적으로 위 예시에서 work() 함수가 끝난 다음 특정 작업을 처리하고 싶을 때에는 콜백 함수를 work() 함수의 파라미터로 전달해주면 된다.
(콜백 함수란, 함수 타입의 값을 파라미터로 넘겨주어 파라미터로 받은 함수를 특정 작업이 끝나고 호출을 해주는 것이다.)</p>
<pre><code class="language-javascript">function work(callback) {
  setTimeout(() =&gt; {
    console.log(&#39;2&#39;);
    callback();
  }, 1000);
}
console.log(&#39;1&#39;);
work(()=&gt;{
  console.log(&#39;work()작업을 마친 후 콜백함수 실행&#39;)
});
console.log(&#39;3&#39;);</code></pre>
<p>실행결과
<img src="https://images.velog.io/images/semi_kimm/post/e28d6882-14d8-49d9-9ac1-c3a84d2f0f63/image.png" alt=""></p>
<hr>
<p>비동기 작업을 처리할 때는 위 예시의 callback함수 사용과 Promise, async/await 문법을 사용하여 처리할 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] 조건부 렌더링]]></title>
            <link>https://velog.io/@semi_kimm/React-%EC%A1%B0%EA%B1%B4%EB%B6%80%EB%A0%8C%EB%8D%94%EB%A7%81</link>
            <guid>https://velog.io/@semi_kimm/React-%EC%A1%B0%EA%B1%B4%EB%B6%80%EB%A0%8C%EB%8D%94%EB%A7%81</guid>
            <pubDate>Sun, 01 Aug 2021 10:51:56 GMT</pubDate>
            <description><![CDATA[<p>특정 조건에 따라 다른 결과물을 출력하는 것을 조건부 렌더링이라고 한다.</p>
<p>어떤 변수가 특정 값을 가질 때 특정 컴포넌트를 렌더링하고 싶은 경우 사용한다.</p>
<blockquote>
<p>조건부 렌더링 방법</p>
</blockquote>
<ol>
<li>&amp;&amp; 사용</li>
<li>삼항 연산자 사용</li>
<li>if ~ else 문 사용</li>
</ol>
<h3 id="1">1. &amp;&amp;</h3>
<p>menubar라는 변수가 있고 이 변수값에 따라서 MenuBar 컴포넌트를 표시한다는 예시를 보면 아래와 같다.</p>
<pre><code class="language-javascript">const [menubar, setMenubar] = useState(true);
//...//
function onClickMenuBtn() {
    setMenubar(!menubar);
}
//...//
&lt;div onClick={onClickMenuBtn}&gt;
    &lt;img src={MenuImg} width=&#39;45&#39; height=&#39;45&#39; alt=&#39;menuIcon&#39; /&gt;
&lt;/div&gt;
//...//
&lt;div&gt;
    {menubar === true &amp;&amp; (
        &lt;div className=&#39;menubar&#39;&gt;
            &lt;MenuBar /&gt;
        &lt;/div&gt;
    )}
&lt;/div&gt;</code></pre>
<p>먼저, menubar는 동적인 값이기 때문에 useState를 사용하여 생성해준다.</p>
<p>onClick 이벤트가 발생했을때 setMenubar에 의해서 값이 반전되도록 구현되어있다.</p>
<p>이때, menubar가 true면 MenuBar 컴포넌트를 렌더링하고 false이면 렌더링하지 않는것을 &amp;&amp;로 구현할 수 있다.</p>
<pre><code class="language-javascript">&lt;div&gt;
    {menubar === true &amp;&amp; (
        &lt;div className=&#39;menubar&#39;&gt;
            &lt;MenuBar /&gt;
        &lt;/div&gt;
    )}
&lt;/div&gt;</code></pre>
<h3 id="2-삼항-연산자-사용">2. 삼항 연산자 사용</h3>
<p>위의 같은 예시에서 MenuBar 컴포넌트를 렌더링하는 것을 삼항 연산자를 사용하여 나타낼 수 있다.</p>
<pre><code class="language-javascript">&lt;div&gt;
    {menubar === true ? (
        &lt;div className=&#39;menubar&#39;&gt;
            &lt;MenuBar /&gt;
        &lt;/div&gt;
    ):null}
&lt;/div&gt;</code></pre>
<p>true이면 MenuBar 컴포넌트를 렌더링하고 그렇지 않으면 null을 사용하여 아무것도 렌더링하지 않도록 할 수 있다.</p>
<h3 id="3-if--else-문-사용">3. if ~ else 문 사용</h3>
<p>위의 예시를 if~else 문을 사용해서도 나타낼 수 있다.</p>
<pre><code class="language-javascript">&lt;div&gt;
    {
      if(menubar === true) { return 
        &lt;div className=&#39;menubar&#39;&gt;
            &lt;MenuBar /&gt;
        &lt;/div&gt;
    }else{return 
             null}
    }
&lt;/div&gt;</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] YouTube Clone Week2]]></title>
            <link>https://velog.io/@semi_kimm/YouTube-Clone-Week2</link>
            <guid>https://velog.io/@semi_kimm/YouTube-Clone-Week2</guid>
            <pubDate>Fri, 30 Jul 2021 10:10:22 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>목표</strong>
<del>영상시청 화면 구현</del>
<del>영상시청 화면에서 댓글기능 구현</del>
3. 로그인 창 구현
4. youtube data api 사용하여 영상 넣기</p>
</blockquote>
<hr>
<h2 id="1-영상시청-화면">1. 영상시청 화면</h2>
<h3 id="appjs">App.js</h3>
<pre><code class="language-javascript">//...//
function App() {
  const [menubar, setMenubar] = useState(true);
  const [videoState, setVideoState] = useState(false);
  const [home, setHome] = useState(true);
  return (
    &lt;&gt;
      &lt;div className=&#39;searchbar&#39;&gt;
        &lt;SearchBar
          menubar={menubar}
          setMenubar={setMenubar}
          videoState={videoState}
          setVideoState={setVideoState}
          home={home}
          setHome={setHome}
        /&gt;
      &lt;/div&gt;
      {videoState === false || home === true ? (
        &lt;div style={{ display: &#39;flex&#39;, flexDirection: &#39;row&#39; }}&gt;
          &lt;div&gt;
            {menubar === true &amp;&amp; (
              &lt;div className=&#39;menubar&#39;&gt;
                &lt;MenuBar /&gt;
              &lt;/div&gt;
            )}
          &lt;/div&gt;
          &lt;div className=&#39;videobody&#39;&gt;
            &lt;VideoBody
              videoState={videoState}
              setVideoState={setVideoState}
              home={home}
              setHome={setHome}
            /&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      ) : (
        &lt;div&gt;
          &lt;WatchingVideo /&gt;
        &lt;/div&gt;
      )}
    &lt;/&gt;
  );
}
export default App;</code></pre>
<p>영상 클릭시 영상시청화면으로 넘어가게 해주기 위해서 state값인 home과 videoState를 useState를 사용하여 생성해주었다.</p>
<p><a href="https://velog.io/@semi_kimm/React-%EC%A1%B0%EA%B1%B4%EB%B6%80%EB%A0%8C%EB%8D%94%EB%A7%81">조건부 렌더링</a> 을 사용하여 home===false거나 videoState===true 일 때 영상시청화면인 WatchingVideo 컴포넌트를 렌더링하도록 하였다.</p>
<hr>
<h3 id="watchingvideojs">WatchingVideo.js</h3>
<pre><code class="language-javascript">import React, { useState } from &#39;react&#39;;
import CreateComment from &#39;./CreateComment&#39;;
function WatchingVideo() {
  const [goodCount, setGoodCount] = useState(0);
  const [badCount, setBadCount] = useState(0);
  const goodBtnClick = () =&gt; {
    setGoodCount(goodCount + 1);
  };
  const badBtnClick = () =&gt; {
    setBadCount(badCount + 1);
  };
  return (
    &lt;&gt;
      &lt;div&gt;
        &lt;video alt={&#39;영상&#39;}&gt;&lt;/video&gt;
      &lt;/div&gt;
      &lt;div&gt;제목&lt;/div&gt;
      &lt;div style={{ display: &#39;flex&#39;, flexDirection: &#39;row&#39; }}&gt;
        &lt;div&gt;조회수&lt;/div&gt;
        &lt;div onClick={goodBtnClick}&gt;👍 {goodCount}&lt;/div&gt;
        &lt;div onClick={badBtnClick}&gt;👎 {badCount}&lt;/div&gt;
      &lt;/div&gt;
      &lt;div&gt;
        &lt;CreateComment /&gt;
      &lt;/div&gt;
    &lt;/&gt;
  );
}
export default WatchingVideo;</code></pre>
<p>WatchingVideo 컴포넌트는 영상시청 화면 부분이다.</p>
<p>동영상을 보여주는 부분 &amp; 영상의 정보 및 조회수를 보여주는 부분 &amp; 댓글 부분으로 구성되어 있다.</p>
<p>동영상을 보여주는 부분은 따로 컴포넌트를 만들어서 youtube data api를 사용하여 data를 가져와서 구현할 예정이다.</p>
<p>제목 부분도 data의 제목 data를 가져와서 넣어줄 예정이다.</p>
<p>댓글 부분은 CreateComment라는 컴포넌트를 새로 만들어주어서 구현하였다. 내용은 다음과 같다.</p>
<hr>
<h2 id="2-댓글-기능-구현">2. 댓글 기능 구현</h2>
<h3 id="createcommentjs">CreateComment.js</h3>
<pre><code class="language-javascript">import React, { useState, useRef } from &#39;react&#39;;
import CreateList from &#39;./CreateList&#39;;
function CreateComment() {
  const [commentCount, setCommentCount] = useState(0);
  const [inputs, setInputs] = useState({
    commentData: &#39;&#39;,
  });
  const { commentData } = inputs;
  const inputChange = (e) =&gt; {
    const { name, value } = e.target;
    setInputs({
      ...inputs,
      [name]: value,
    });
  };
  const [commentLists, setCommentLists] = useState([
    {
      id: 0,
      commentData: &#39;&#39;,
    },
  ]);
  const nextId = useRef(1);
  const putComment = () =&gt; {
    const commentList = {
      id: nextId.current,
      commentData,
    };
    setCommentLists([...commentLists, commentList]);
    setInputs({ commentData: &#39;&#39; });
    nextId.current += 1;
    setCommentCount(commentCount + 1);
  };
  return (
    &lt;&gt;
      &lt;div&gt;댓글 {commentCount}개&lt;/div&gt;
      &lt;div&gt;
        &lt;input
          name=&#39;commentData&#39;
          placeholder=&#39;공개 댓글 추가&#39;
          onChange={inputChange}
          value={commentData}
        /&gt;
        &lt;button onClick={putComment}&gt;등록&lt;/button&gt;
      &lt;/div&gt;
      &lt;CreateList commentLists={commentLists} /&gt;
    &lt;/&gt;
  );
}
export default CreateComment;</code></pre>
<hr>
<h3 id="createlistjs">CreateList.js</h3>
<pre><code class="language-javascript">import React from &#39;react&#39;;
function Data({ data }) {
  return (
    &lt;div&gt;
      &lt;div&gt;{data.commentData}&lt;/div&gt;
    &lt;/div&gt;
  );
}
function CreateList({ commentLists }) {
  return (
    &lt;div&gt;
      {commentLists.map((data) =&gt; (
        &lt;Data data={data} key={data.id} /&gt;
      ))}
    &lt;/div&gt;
  );
}
export default CreateList;</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] Img 태그를 사용한 이미지 추가]]></title>
            <link>https://velog.io/@semi_kimm/React-Img-tag</link>
            <guid>https://velog.io/@semi_kimm/React-Img-tag</guid>
            <pubDate>Sun, 25 Jul 2021 17:39:56 GMT</pubDate>
            <description><![CDATA[<p>React에 이미지를 추가하는 방법은 다음과 같다.</p>
<ol>
<li>import 사용</li>
<li>require() 사용</li>
</ol>
<hr>
<h4 id="1-import-사용하여-컴포넌트에-이미지-추가하기">1. import 사용하여 컴포넌트에 이미지 추가하기</h4>
<p>React에서는 다음과 같은 import 형식으로 이미지를 추가하고 불러올 수 있다.</p>
<pre><code class="language-javascript">import 이미지변수명 from &#39;이미지파일경로&#39;
//...//
&lt;img src={이미지변수명} /&gt;</code></pre>
<p>width, height, alt를 추가하고 싶다면 다음과 같이 작성하면 된다.</p>
<pre><code class="language-javascript">&lt;img src={이미지변수명} width=&#39;숫자&#39; height=&#39;숫자&#39; alt=&#39;이미지설명&#39; /&gt;</code></pre>
<blockquote>
<p>예시</p>
</blockquote>
<pre><code class="language-javascript">import LogoImg from &#39;./logo.jpg&#39;;
//...//
&lt;div&gt;
    &lt;img src={LogoImg} width=&#39;150&#39; height=&#39;45&#39; /&gt;
&lt;/div&gt;</code></pre>
<p><img src="https://images.velog.io/images/semi_kimm/post/2cde0717-c511-44ec-b901-15e61222215f/velog%EC%82%AC%EC%9A%A9%EC%9D%B4%EB%AF%B8%EC%A7%80.JPG" alt="">
노란색으로 동그라미 친 부분이 추가된 모습이다.</p>
<p>이미지를 추가하면서 발생한 경로 오류
상단에서 import를 사용하여 이미지 자체를 불러오거나
css파일에서 backgound-image로 사용할 경우
이미지 파일의 위치가 src 폴더 아래에 꼭 위치해야 한다.
<img src="https://images.velog.io/images/semi_kimm/post/8948f8bc-45db-4a31-86c0-22d162eefdd3/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] YouTube Clone week1]]></title>
            <link>https://velog.io/@semi_kimm/YouTube-Clone-week1</link>
            <guid>https://velog.io/@semi_kimm/YouTube-Clone-week1</guid>
            <pubDate>Sun, 25 Jul 2021 11:17:46 GMT</pubDate>
            <description><![CDATA[<blockquote>
<h4 id="목표">목표</h4>
<p><del>메인화면(홈화면) html&amp;css</del>
2) 영상시청화면 html&amp;css
3) 영상화면의 댓글입력 기능
<del>메뉴 눌렀을 때 메뉴바</del> 
5) 로그인창 및 로그인 기능</p>
</blockquote>
<hr>
<h2 id="1-메인화면홈화면">1. 메인화면(홈화면)</h2>
<p><img src="https://images.velog.io/images/semi_kimm/post/83f73473-fed6-4dd9-97f5-d02886357ad5/image.png" alt="">
메인화면은 아래와 같이 크게 3block으로 나누었다.
<img src="https://images.velog.io/images/semi_kimm/post/d0683dda-d70a-4ee7-a8f6-6988bd9d0f50/image.png" alt="">
React를 사용하여 구현하였으며 block들을 각각 모듈로 나누어서 구현하였다.</p>
<p>먼저, 모든 모듈을 담고있는 App.js는 다음과 같다.
(모든 모듈을 담고있다는 표현은 정확하지 않은것 같다. 정확한 표현을 찾아보는 것이 필요할듯)</p>
<h3 id="appjs">App.js</h3>
<pre><code class="language-javascript">import React from &#39;react&#39;;
import SearchBar from &#39;./SearchBar&#39;;
import VideoBody from &#39;./VideoBody&#39;;
import MenuBar from &#39;./MenuBar&#39;;
let menuState = true;
function App() {
  return (
    &lt;&gt;
      &lt;div className=&#39;searchbar&#39;&gt;
        &lt;SearchBar menuState={menuState} /&gt;
      &lt;/div&gt;

      &lt;div style={{ display: &#39;flex&#39;, flexDirection: &#39;row&#39; }}&gt;
        {menuState === true &amp;&amp; (
          &lt;div className=&#39;menubar&#39;&gt;
            &lt;MenuBar /&gt;
          &lt;/div&gt;
        )}
        &lt;div className=&#39;videobody&#39;&gt;
          &lt;VideoBody /&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/&gt;
  );
}

export default App;</code></pre>
<p>이 부분을 진행하면서 아직 동적인 기능이 없기 때문에 특별하게 참고할 사항은 없다.</p>
<p>우선 진행중인 메인화면에서의 동적인 기능은 searchbar의 MenuIcon을 클릭시 menubar가 생성되었다가 없어졌다가 하는 동작을 진행중이다.</p>
<pre><code class="language-javascript">let menuState=true;
//...//
&lt;div className=&#39;searchbar&#39;&gt;
        &lt;SearchBar menuState={menuState} /&gt;
&lt;/div&gt;
&lt;div style={{ display: &#39;flex&#39;, flexDirection: &#39;row&#39; }}&gt;
        {menuState === true &amp;&amp; (
          &lt;div className=&#39;menubar&#39;&gt;
            &lt;MenuBar /&gt;
&lt;/div&gt;
)}
&lt;/div&gt;</code></pre>
<p><del>App.js 에서 위 코드부분을 보면
true로 초기화한 menuState라는 변수를 선언하고
이 변수를 props로 SearchBar.js에 넘겨준다.
SearchBar.js에서는 menuIcon에 onClick 이벤트를 추가하여 클릭시 menuState 값이 반전되도록 구현하였다.
다시 App.js에서 <MenuBar />를 추가할 때 &amp;&amp;를 사용하여 menuState값이 true이면 <MenuBar />가 생성되도록 하고 아니면 생성되지 않도록 구현하였다.
현재 console을 통해 menuIcon 클릭시 menuState값이 변하는 것이 정상적으로 실행되는 것은 확인하였지만 SearchBar.js에서 제어하는 menuState값이 App.js에서는 변하지 않는 것인지 <MenuBar />가 생성되고 생성되지 않고 하는 부분은 아직 동작하지 않고 있다.</del></p>
<p><a href="https://velog.io/@semi_kimm/react%EC%9E%85%EB%AC%B8-1">props란 무엇인가 - 참고</a></p>
<blockquote>
<p>메뉴바 동작하지 않는 부분
-&gt; useState 사용하여 해결 (추가로 정리할 예정)</p>
</blockquote>
<p>추가적으로 css부분에서 어려움을 겪었다.
우선 react에서 css를 적용하려면 2가지 방법이 있다.</p>
<ol>
<li>css 파일을 추가하는 방법</li>
<li>tag에 style={}을 직접 추가하는 방법
첫번째 방식은 기본적으로 아는 방법이지만 여러개의 모듈로 나누어서 진행을 하다보니 다른 모듈에 적용하는 것에 있어서 어려움이 있었다.</li>
</ol>
<p>직관적으로 css를 확인하고 적용하기 위해서 2번째 방법을 사용하였다.</p>
<pre><code class="language-javascript">&lt;div style={{ display: &#39;flex&#39;, flexDirection: &#39;row&#39; }}&gt;
    {menuState === true &amp;&amp; (
    &lt;div className=&#39;menubar&#39;&gt;
        &lt;MenuBar /&gt;
    &lt;/div&gt;
    )}
    &lt;div className=&#39;videobody&#39;&gt;
        &lt;VideoBody /&gt;
    &lt;/div&gt;
&lt;/div&gt;</code></pre>
<p>App.js 부분에서 위 코드를 보면 SearchBar 와는 따로 MenuBar와 VideoBody를 묶어놓았다.</p>
<p>SearchBar는 상단에 자기 혼자만 고정으로 위치하고 MenuBar와 VideoBody는 가로정렬로 상단바 아래에 같이 위치해야되기 때문이다.</p>
<p>두 모듈을 가로정렬 하기 위해 하나의 div tag로 묶고</p>
<pre><code class="language-javascript">&lt;div style={{ display: &#39;flex&#39;, flexDirection: &#39;row&#39; }}&gt;</code></pre>
<p>style로 display는 flex로 flexDirection은 row로 설정해주었다.</p>
<p>display를 flex로 설정하여 두 태그를 감싼 div 태그가 부모 속성인 flex container가 된다.
이렇게 설정하면 MenuBar와 VideoBody가 flex container의 자식 속성 flex item이 된다.</p>
<p>부모 속성에서 flexDirection을 설정하면 자식속성들을 정렬할 수 있다.
flexDirection에서 값을 row로 설정하면 가로정렬 column으로 설정하면 세로정렬이다.</p>
<p><a href="https://d2.naver.com/helloworld/8540176">flexbox란? 참고</a></p>
<hr>
<h3 id="searchbarjs">Searchbar.js</h3>
<p><img src="https://images.velog.io/images/semi_kimm/post/834f220d-d8c7-4578-85fc-8888f81f12cb/image.png" alt="">
다음으로 상단바 부분이다.</p>
<pre><code class="language-javascript">import React from &#39;react&#39;;
import LogoImg from &#39;./logo.jpg&#39;;
import MenuImg from &#39;./menuImg.jpg&#39;;

const barStyle = {
  color: &#39;black&#39;,
  background: &#39;white&#39;,
  padding: &#39;10px&#39;,
  fontSize: &#39;20px&#39;,
  border: &#39;1px solid gainsboro&#39;,
  lineHeight: 1.5,
  display: &#39;flex&#39;, 
  flexDirection: &#39;row&#39;,
};

function SearchBar({ menuState }) {
  function onClickMenuBtn() {
    menuState = !menuState;
    console.log(menuState);
  }

  return (
    &lt;&gt;
      &lt;div style={barStyle}&gt;
        &lt;div onClick={onClickMenuBtn}&gt;
          &lt;img src={MenuImg} width=&#39;45&#39; height=&#39;45&#39; alt=&#39;menuIcon&#39; /&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;img src={LogoImg} width=&#39;150&#39; height=&#39;45&#39; alt=&#39;logoImg&#39; /&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;input
            type=&#39;text&#39;
            placeholder=&#39;검색&#39;
            style={{ width: &#39;300px&#39;, height: &#39;45px&#39; }}
          &gt;&lt;/input&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;button style={{ width: &#39;45px&#39;, height: &#39;45px&#39; }}&gt;🔍&lt;/button&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/&gt;
  );
}

export default SearchBar;</code></pre>
<p>앞서 언급한 menuIcon의 클릭 이벤트는 위 코드의 다음 부분을 참고하면 된다.</p>
<pre><code class="language-javascript">//...//
function SearchBar({ menuState }) {
  function onClickMenuBtn() {
    menuState = !menuState;
    console.log(menuState);
  }
  return (
    &lt;&gt;
      &lt;div style={barStyle}&gt;
        &lt;div onClick={onClickMenuBtn}&gt;
          &lt;img src={MenuImg} width=&#39;45&#39; height=&#39;45&#39; alt=&#39;menuIcon&#39; /&gt;
        &lt;/div&gt;
//...//</code></pre>
<p><a href="https://velog.io/@semi_kimm/React-Img-tag">이미지추가 참고</a></p>
<hr>
<h3 id="videobodyjs">VideoBody.js</h3>
<pre><code class="language-javascript">import React from &#39;react&#39;;
import VideoList from &#39;./VideoList&#39;;
const bodyStyle = {
  position: &#39;absolute&#39;,
  color: &#39;black&#39;,
  background: &#39;white&#39;,
  width: &#39;100%&#39;,
  display: &#39;flex&#39;, 
  flexDirection: &#39;column&#39;,
};
function VideoBody() {
  return (
    &lt;div style={bodyStyle}&gt;
      &lt;VideoList /&gt;
      &lt;VideoList /&gt;
      &lt;VideoList /&gt;
    &lt;/div&gt;
  );
}

export default VideoBody;
</code></pre>
<hr>
<h4 id="videolistjs">VideoList.js</h4>
<pre><code class="language-javascript">import React from &#39;react&#39;;

function VideoList() {
  return (
    &lt;div style={{ display: &#39;flex&#39;, flexDirection: &#39;row&#39; }}&gt;
      &lt;div style={{ border: &#39;0.5px solid gainsboro&#39;, height: &#39;35%&#39; }}&gt;
        &lt;video&gt;&lt;/video&gt;
        &lt;div&gt;영상제목1&lt;/div&gt;
        &lt;div&gt;채널명&lt;/div&gt;
      &lt;/div&gt;
      &lt;div style={{ border: &#39;0.5px solid gainsboro&#39;, height: &#39;35%&#39; }}&gt;
        &lt;video&gt;&lt;/video&gt;
        &lt;div&gt;영상제목2&lt;/div&gt;
        &lt;div&gt;채널명&lt;/div&gt;
      &lt;/div&gt;
      &lt;div style={{ border: &#39;0.5px solid gainsboro&#39;, height: &#39;35%&#39; }}&gt;
        &lt;video&gt;&lt;/video&gt;
        &lt;div&gt;영상제목3&lt;/div&gt;
        &lt;div&gt;채널명&lt;/div&gt;
      &lt;/div&gt;
      &lt;div style={{ border: &#39;0.5px solid gainsboro&#39;, height: &#39;35%&#39; }}&gt;
        &lt;video&gt;&lt;/video&gt;
        &lt;div&gt;영상제목4&lt;/div&gt;
        &lt;div&gt;채널명&lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  );
}

export default VideoList;
</code></pre>
<hr>
<h3 id="menubarjs">MenuBar.js</h3>
<pre><code class="language-javascript">import React from &#39;react&#39;;
const barStyle = {
  color: &#39;black&#39;,
  background: &#39;white&#39;,
  fontSize: &#39;20px&#39;,
  lineHeight: 3,
  width: &#39;200px&#39;,
  border: &#39;0.5px solid gainsboro&#39;,
};
function MenuBar() {
  return (
    &lt;div style={barStyle}&gt;
      &lt;div&gt;
        &lt;div&gt;홈&lt;/div&gt;
        &lt;div&gt;탐색&lt;/div&gt;
        &lt;div&gt;구독&lt;/div&gt;
      &lt;/div&gt;
      &lt;div&gt;
        &lt;div&gt;구독 목록&lt;/div&gt;
      &lt;/div&gt;
      &lt;div&gt;
        &lt;div&gt;설정&lt;/div&gt;
        &lt;div&gt;고객센터&lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  );
}
export default MenuBar;</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] 영화 리스트 만들기 - 1]]></title>
            <link>https://velog.io/@semi_kimm/movie-list</link>
            <guid>https://velog.io/@semi_kimm/movie-list</guid>
            <pubDate>Wed, 03 Feb 2021 16:35:34 GMT</pubDate>
            <description><![CDATA[<h4 id="httpsapitvmazecomsearchshowsqbatman-이-주소로부터-영화-정보를-state로-받아서-list-형태로-나타낸다-영화의-이미지는-필수로-출력하도록-한다">&#39;<a href="https://api.tvmaze.com/search/shows?q=batman&#39;">https://api.tvmaze.com/search/shows?q=batman&#39;</a> 이 주소로부터 영화 정보를 state로 받아서 list 형태로 나타낸다. 영화의 이미지는 필수로 출력하도록 한다.</h4>
<h3 id="appjs">App.js</h3>
<pre><code class="language-javascript">import React from &#39;react&#39;;
import CreateMovie from &#39;./CreateMovie&#39;;
function App() {
  return (
    &lt;&gt;
      &lt;h1&gt;Movie List&lt;/h1&gt;
      &lt;CreateMovie /&gt;
    &lt;/&gt;
  );
}
export default App;</code></pre>
<h3 id="movielistjs">MovieList.js</h3>
<pre><code class="language-javascript">import React from &#39;react&#39;;
function Movie({ movie }) {
  return (
    &lt;div&gt;
      &lt;li&gt;{movie.movieName}&lt;/li&gt;
      &lt;img src={movie.src} alt=&#39;movie&#39; /&gt;
    &lt;/div&gt;
  );
}
function MovieList({ movies }) {
  return (
    &lt;div&gt;
      {movies.map((movie) =&gt; (
        &lt;Movie movie={movie} key={movie.id} /&gt;
      ))}
    &lt;/div&gt;
  );
}
export default MovieList;</code></pre>
<h3 id="createmoviejs">CreateMovie.js</h3>
<pre><code class="language-javascript">import React, { useState } from &#39;react&#39;;
import axios from &#39;axios&#39;;
import MovieList from &#39;./MovieList&#39;;
let id = [];
let name = [];
let src = [];
function CreateMovie() {
  const [movies, setMoives] = useState([
    { id: 0, movieName: &#39;defaultName&#39;, src: &#39;&#39; },
  ]);
  let { id, movieName, src } = movies;
  async function getMovies() {
    let response = await axios.get(
      &#39;https://api.tvmaze.com/search/shows?q=batman&#39;
    );
    //console.log(response.data);
    response.data.forEach((list) =&gt; {
      //console.log(list);
      //id.push(list.show.id);
      name.push(list.show.name);
      //src.push(list.show.src);
      //console.log(movies);
    });
  }
  const onCreate = () =&gt; {
    getMovies();
    name.forEach((Name) =&gt; {
      //   const movie = {
      //     id: id[i],
      //     movieName: name[i],
      //     src: src[i],
      //   };
      setMoives([
        ...movies,
        {
          //id: id[i],
          movieName: Name,
          //src: src[i],
        },
      ]);
    });
    //console.log(movies);
    console.log(name);
  };
  return (
    &lt;&gt;
      &lt;button onClick={onCreate}&gt;영화 리스트 보기&lt;/button&gt;
      &lt;MovieList movies={movies} /&gt;
    &lt;/&gt;
  );
}
export default CreateMovie;</code></pre>
<h3 id="현재결과">현재결과</h3>
<p><img src="https://images.velog.io/images/semi_kimm/post/6add309a-0d6f-4855-935f-d612fb9a3c6e/image.png" alt=""></p>
<h3 id="해결-못-한-부분">해결 못 한 부분</h3>
<p>영화 리스트 보기 버튼을 누르면 영화 리스트가 나오도록 하는데
받아온 데이터의 첫번째 정보만 계속 출력?된다. &gt;&gt;  async function 부분이 비동기 처리인데 setmovies를 그 밖에서 따로 처리해줘서 실행 순서가 섞이면서 제대로 실행이 안된것
이미지가 엑박으로 뜨고 제대로 안보인다. &gt;&gt; 데이터를 잘못 가져옴
해결 위해서 require().default사용시 오류남</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] 입문 - 2]]></title>
            <link>https://velog.io/@semi_kimm/react%EC%9E%85%EB%AC%B8-2</link>
            <guid>https://velog.io/@semi_kimm/react%EC%9E%85%EB%AC%B8-2</guid>
            <pubDate>Wed, 03 Feb 2021 06:32:05 GMT</pubDate>
            <description><![CDATA[<h3 id="13-배열에-항목-추가하기">13. 배열에 항목 추가하기</h3>
<blockquote>
<p>input 2개와 button 1개로 이루어진 CreateUser.js를 src디렉터리에 생성한다.</p>
</blockquote>
<pre><code class="language-javascript">import React from &#39;react&#39;;
function CreateUser({ username, email, onChange, onCreate }) {
  return (
    &lt;div&gt;
      &lt;input
        name=&#39;username&#39;
        placeholder=&#39;계정명&#39;
        onChange={onChange}
        value={username}
      /&gt;
      &lt;input
        name=&#39;email&#39;
        placeholder=&#39;이메일&#39;
        onChange={onChange}
        value={email}
      /&gt;
      &lt;button onClick={onCreate}&gt;등록&lt;/button&gt;
    &lt;/div&gt;
  );
}
export default CreateUser;</code></pre>
<p>상태 관리를 CreateUser에서 하지 않고 부모 컴포넌트 App에서 처리하고, input 값과 이벤트로 등록할 함수를 props로 받아 사용한다.
users도 userState를 사용하여 컴포넌트의 상태로서 관리하도록 한다.</p>
<h4 id="appjs">App.js</h4>
<pre><code class="language-javascript">import React, { useRef, useState } from &#39;react&#39;;
import UserList from &#39;./UserList&#39;;
import CreateUser from &#39;./CreateUser&#39;;
import &#39;./App.css&#39;;
function App() {
  const [inputs, setInputs] = useState({
    username: &#39;&#39;,
    email: &#39;&#39;,
  });
  const { username, email } = inputs;
  const onChange = (e) =&gt; {
    const { name, value } = e.target;
    setInputs({
      ...inputs,
&gt;       [name]: value,
    });
  };
  const [users, setUsers] = useState([
    {
      id: 1,
      username: &#39;velopert&#39;,
      email: &#39;public.velopert@gmail.com&#39;,
    },
    {
      id: 2,
      username: &#39;tester&#39;,
      email: &#39;tester@example.com&#39;,
    },
    {
      id: 3,
      username: &#39;liz&#39;,
      email: &#39;liz@example.com&#39;,
    },
  ]);
  const nextId = useRef(4); //초기값을 4로 설정=&gt;.current의 기본값이 된다.
  const onCreate = () =&gt; {
    setInputs({//등록 버튼을 눌렀을 때 input 값들을 초기화 시킨다. 입력박스를 빈칸으로 초기화한다.
      username: &#39;&#39;,
      email: &#39;&#39;,
    });
    nextId.current += 1;
  };
  return (
    &lt;Wrapper&gt;
      &lt;CreateUser
        username={username}
        email={email}
        onChange={onChange}
        onCreate={onCreate}
      /&gt;
      &lt;UserList users={users} /&gt;
    &lt;/Wrapper&gt;
  );
}
export default App;</code></pre>
<p>이제 배열에 변화를 준다.
배열에 변화를 줄때에는 객체와 똑같이 !!!불변성!!!을 지켜야 한다.
따라서 배열의 push, splice, sort 처럼 기존배열을 바꾸는 함수는 사용하면 안되고 사용하더라도 기존 배열을 복사한 후 사용해야 한다.</p>
<p>불변성을 지키면서 배열에 새 항목을 추가하는 방법은 2가지가 있다.</p>
<blockquote>
<p>첫 번째로 spread 연산자를 사용하는 것이다.</p>
</blockquote>
<pre><code class="language-javascript"> const onCreate = () =&gt; {
    const user = {
      id: nextId.current,
      username,
      email,
    };
    //1. spread 연산자를 사용하여 새 항목 추가
    setUsers([...users, user]);
    setInputs({
      username: &#39;&#39;,
      email: &#39;&#39;,
    });
    nextId.current += 1;
  };</code></pre>
<blockquote>
<p>두 번째로 concat 함수를 사용하는 것이다.
concat 함수는 기존의 배열을 수정하지 않고, 새로운 원소가 추가된 새로운 배열을 만든다.</p>
</blockquote>
<pre><code class="language-javascript">const onCreate = () =&gt; {
    const user = {
      id: nextId.current,
      username,
      email,
    };
    //2. concat 함수 사용하여 새 항목 추가
    setUsers(users.concat(user));
    setInputs({
      username: &#39;&#39;,
      email: &#39;&#39;,
    });
    nextId.current += 1; 
  };</code></pre>
<h3 id="14-배열에-항목-제거하기">14. 배열에 항목 제거하기</h3>
<p>UserList에서 각 User 컴포넌트를 보여줄 때 삭제 버튼을 렌더링한다.
배열에 있는 항목을 제거할 때에는 불변성을 지키면서 업데이트를 해야 한다.
이때 filter 내장 함수를 사용하는 것이 가장 편하다.
filter : 배열에서 특정 조건이 만족하는 원소들만 추출하여 새로운 배열을 반환한다.</p>
<blockquote>
<p>삭제 버튼을 눌렀을 때 props로 받아온 onRemove 함수의 파라미터로 삭제 버튼이 눌린 객체의 user.id 값을 파라미터로 받는다.
onRemove : id가 ~인 객체를 삭제해라.</p>
</blockquote>
<h4 id="userlistjs">UserList.js</h4>
<pre><code class="language-javascript">import React from &#39;react&#39;;
function User({ user }) {
  return (
    &lt;div&gt;
      &lt;b&gt;{user.username}&lt;/b&gt; &lt;span&gt;({user.email})&lt;/span&gt;
      &lt;button onClick={() =&gt; onRemove(user.id)}&gt;삭제&lt;/button&gt;
    &lt;/div&gt;
  );
}
function UserList({ users }) {
  return (
    &lt;div&gt;
      {users.map((user) =&gt; (
        &lt;User user={user} key={user.id} onRemove={onRemove} /&gt;
      ))}
    &lt;/div&gt;
  );
}
export default UserList;</code></pre>
<h4 id="appjs-1">App.js</h4>
<pre><code class="language-javascript">import React, { useRef, useState } from &#39;react&#39;;
import Wrapper from &#39;./Wrapper&#39;;
import UserList from &#39;./UserList&#39;;
import CreateUser from &#39;./CreateUser&#39;;
import &#39;./App.css&#39;;
function App() {
  const [inputs, setInputs] = useState({
    username: &#39;&#39;,
    email: &#39;&#39;,
  });
  const { username, email } = inputs;
  const onChange = (e) =&gt; {
    const { name, value } = e.target;
    setInputs({
      ...inputs,
&gt;       [name]: value,
    });
  };
  const [users, setUsers] = useState([
    {
      id: 1,
      username: &#39;velopert&#39;,
      email: &#39;public.velopert@gmail.com&#39;,
    },
    {
      id: 2,
      username: &#39;tester&#39;,
      email: &#39;tester@example.com&#39;,
    },
    {
      id: 3,
      username: &#39;liz&#39;,
      email: &#39;liz@example.com&#39;,
    },
  ]);
  const name = &#39;react&#39;;
  const style = {
    backgroundColor: &#39;black&#39;,
    color: &#39;aqua&#39;,
    fontSize: 24,
    padding: &#39;1rem&#39;,
  };
  const nextId = useRef(4);
  const onCreate = () =&gt; {
    const user = {
      id: nextId.current,
      username,
      email,
    };
    setUsers(users.concat(user));
    setInputs({
      username: &#39;&#39;,
      email: &#39;&#39;,
    });
    nextId.current += 1; 
  };
  const onRemove = (id) =&gt; {
    setUsers(users.filter((user) =&gt; user.id !== id));
  };
  return (
    &lt;Wrapper&gt;
      &lt;CreateUser
        username={username}
        email={email}
        onChange={onChange}
        onCreate={onCreate}
      /&gt;
      &lt;UserList users={users} onRemove={onRemove} /&gt;
    &lt;/Wrapper&gt;
  );
}
export default App;</code></pre>
<h3 id="15-배열-항목-수정하기">15. 배열 항목 수정하기</h3>
<p>User 컴포넌트에 계정명을 클릭했을때 색상이 초록색으로 바뀌고 다시 누르면 검정색으로 바뀌도록 구현한다.</p>
<blockquote>
<p>App컴포넌트의 users 배열의 객체에 active 속성을 추가한다.
active 값에 따라 폰트의 색상을 바꿔주도록 한다.
cursor 필드를 설정하여 마우스를 올렸을때 커서가 손가락 모양으로 변하도록 한다.</p>
</blockquote>
<h4 id="appjs-부분">App.js 부분</h4>
<pre><code class="language-javascript">const [users, setUsers] = useState([
    {
      id: 1,
      username: &#39;velopert&#39;,
      email: &#39;public.velopert@gmail.com&#39;,
      active: true,
    },
    {
      id: 2,
      username: &#39;tester&#39;,
      email: &#39;tester@example.com&#39;,
      active: false,
    },
    {
      id: 3,
      username: &#39;liz&#39;,
      email: &#39;liz@example.com&#39;,
      active: false,
    },
  ]);</code></pre>
<h4 id="userlistjs-1">UserList.js</h4>
<pre><code class="language-javascript">function User({ user, onRemove }) {
  return (
    &lt;div&gt;
      &lt;b style={{ cursor: &#39;pointer&#39;, color: user.active ? &#39;green&#39; : &#39;black&#39; }}&gt; //이부분 추가
        {user.username}
      &lt;/b&gt;{&#39; &#39;}
      &lt;span&gt;({user.email})&lt;/span&gt;
      &lt;button onClick={() =&gt; onRemove(user.id)}&gt;삭제&lt;/button&gt;
    &lt;/div&gt;
  );
}
function UserList({ users, onRemove }) {
  return (
    &lt;div&gt;
      {users.map((user) =&gt; (
        &lt;User user={user} key={user.id} onRemove={onRemove} /&gt;
      ))}
    &lt;/div&gt;
  );
}
export default UserList;</code></pre>
<blockquote>
<p>App.js에 onToggle 함수를 구현한다.
배열의 불변성 유지를하면서 업데이트 할 때 배열 내장 함수인 map 함수를 사용할 수 있다.
onToggle : id 값을 비교해서 id가 다르다면 그대로 두고, 같다면 active 값을 반전시키도록 구현한다.</p>
</blockquote>
<h4 id="appjs-2">App.js</h4>
<pre><code class="language-javascript">  const onToggle = (id) =&gt; {
    setUsers(
      users.map((user) =&gt; {
        user.id === id ? { ...user, active: !user.active } : user;
      })
    );
  };</code></pre>
<p><del>오류발생(해결 못함)</del>
<img src="https://images.velog.io/images/semi_kimm/post/627bd148-b73a-4113-9838-1b6fb76595b8/image.png" alt="">
line 74:~ 
: user.id === id ? { ...user, active: !user.active } : user;
책 코드
<img src="https://images.velog.io/images/semi_kimm/post/9249203d-60c3-4164-a0da-8721ccb948fb/image.png" alt="">
해결
<a href="https://helicopter55.tistory.com/2">오류해결참고</a>
해결방법 1. map() 함수를 사용할때 map(()=&gt;{}) 과 같이 {} 중괄호를 사용할때는 내부에 return을 사용해주어야 한다.</p>
<pre><code class="language-javascript">const onToggle = (id) =&gt; {
    setUsers(
      users.map((user) =&gt;(
        user.id === id ? { ...user, active: !user.active } : user)
      )
    );
  };</code></pre>
<p>해결방법 2. map()이 반환하는 것은 결국 컴포넌트 하나이기 때문에 {}가 아닌 ()소괄호에 요소를 담아 사용한다.</p>
<pre><code class="language-javascript">const onToggle = (id) =&gt; {
    setUsers(
      users.map((user) =&gt; {
        return user.id === id ? { ...user, active: !user.active } : user;
      })
    );
  };</code></pre>
<h4 id="userlistjs-2">UserList.js</h4>
<pre><code class="language-javascript">function User({ user, onRemove, onToggle }) {
  return (
    &lt;div&gt;
      &lt;b
        style={{ cursor: &#39;pointer&#39;, color: user.active ? &#39;green&#39; : &#39;black&#39; }}
        onClick={() =&gt; onToggle(user.id)}//여기
      &gt;
        {user.username}
      &lt;/b&gt;{&#39; &#39;}
      &lt;span&gt;({user.email})&lt;/span&gt;
      &lt;button onClick={() =&gt; onRemove(user.id)}&gt;삭제&lt;/button&gt;
    &lt;/div&gt;
  );
}
function UserList({ users, onRemove, onToggle }) {
  return (
    &lt;div&gt;
      {users.map((user) =&gt; (
        &lt;User
          user={user}
          key={user.id}
          onRemove={onRemove}
          onToggle={onToggle}//여기
        /&gt;
      ))}
    &lt;/div&gt;
  );
}</code></pre>
<h3 id="16-useeffect를-사용하여-마운트언마운트업데이트시-할-작업-설정하기">16. useEffect를 사용하여 마운트/언마운트/업데이트시 할 작업 설정하기</h3>
<p>마운트 : 처음 나타났을 때
언마운트 : 사라질 때
업데이트 : 특정 props가 바뀔 때</p>
<blockquote>
<p>마운트/언마운트 관리</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JavaScript] 배열 내장 함수]]></title>
            <link>https://velog.io/@semi_kimm/JS-array-func</link>
            <guid>https://velog.io/@semi_kimm/JS-array-func</guid>
            <pubDate>Thu, 28 Jan 2021 06:22:31 GMT</pubDate>
            <description><![CDATA[<h3 id="foreach">forEach</h3>
<pre><code class="language-javascript">//1.forEach
const arrayForEach = [&#39;하나&#39;, &#39;둘&#39;, &#39;셋&#39;, &#39;넷&#39;];
//for문으로 출력을 구현할 경우
for (let i = 0; i &lt; arrayForEach.length; i++) {
  console.log(arrayForEach[i]);
}
//forEach문으로 출력 구현
arrayForEach.forEach((number) =&gt; {
  console.log(number);
});</code></pre>
<p>forEach 함수의 파라미터
=&gt; 각 원소에 대해 처리하고 싶은 코드를 함수로 넣는다.
위 예시에서 number은 listForEach의 각 원소를 가리킨다.</p>
<h3 id="map중요">map(중요!)</h3>
<p>배열 안의 각 원소를 변환 할 때 사용하며 새로운 배열을 반환한다.</p>
<pre><code class="language-javascript">//2.map
const arrayMap = [1, 2, 3, 4, 5, 6, 7];
//for문 사용해서 새로운 배열 반환
const resultFor = [];
for (let i = 0; i &lt; arrayMap.length; i++) {
  resultFor.push(arrayMap[i] * 3);
}
console.log(resultFor);
//map사용해서 새로운 배열 반환
const resultMap = arrayMap.map((number) =&gt; number * 3);
console.log(resultMap);</code></pre>
<p>map 함수의 파라미터
=&gt; 변화를 주는 함수를 전달한다.</p>
<h3 id="indexof">indexOf</h3>
<p>배열 안에 있는 값이 숫자, 문자열 또는 boolean일 때,
원하는 항목이 몇번째 원소인지 찾아준다.
즉, 배열에서 특정 원소의 index를 반환한다.</p>
<pre><code class="language-javascript">//3.indexOf
const arrayindexOf = [&#39;하나&#39;, &#39;둘&#39;, &#39;셋&#39;, &#39;넷&#39;];
const index = arrayindexOf.indexOf(&#39;둘&#39;);
console.log(index);</code></pre>
<h3 id="findindex">findIndex</h3>
<p>배열 안에 있는 값이 객체 또는 배열일때 index를 반환한다.</p>
<pre><code class="language-javascript">//4.findIndex
const arrayFindeIndex = [
  {
    id: 1,
    text: &#39;하나&#39;,
    boolean: true,
  },
  {
    id: 2,
    text: &#39;둘&#39;,
    boolean: true,
  },
  {
    id: 3,
    text: &#39;셋&#39;,
    boolean: true,
  },
  {
    id: 4,
    text: &#39;넷&#39;,
    boolean: false,
  },
];
const indexFindIndex = arrayFindeIndex.findIndex((obj) =&gt; obj.id === 3);
console.log(indexFindIndex);</code></pre>
<h3 id="find">find</h3>
<p>찾아낸 값 자체를 반환한다.</p>
<pre><code class="language-javascript">//5.find
const arrayFind = [
  {
    id: 1,
    text: &#39;하나&#39;,
    boolean: true,
  },
  {
    id: 2,
    text: &#39;둘&#39;,
    boolean: true,
  },
  {
    id: 3,
    text: &#39;셋&#39;,
    boolean: true,
  },
  {
    id: 4,
    text: &#39;넷&#39;,
    boolean: false,
  },
];
const indexFind = arrayFind.find((obj) =&gt; obj.id === 3);
console.log(indexFind);</code></pre>
<p>결과
<img src="https://images.velog.io/images/semi_kimm/post/065ebac3-c73a-4d40-8fae-74aed8d0e454/image.png" alt=""></p>
<h3 id="filter중요">filter(중요!)</h3>
<p>배열에서 특정 조건을 만족하는 값들만 추출하여 새로운 배열을 반환한다.</p>
<pre><code class="language-javascript">//6.filter
const arrayFilter = [
  {
    id: 1,
    text: &#39;하나&#39;,
    boolean: true,
  },
  {
    id: 2,
    text: &#39;둘&#39;,
    boolean: true,
  },
  {
    id: 3,
    text: &#39;셋&#39;,
    boolean: true,
  },
  {
    id: 4,
    text: &#39;넷&#39;,
    boolean: false,
  },
];
const resultFilter = arrayFilter.filter((obj) =&gt; obj.boolean === true);
console.log(resultFilter);</code></pre>
<p>결과
<img src="https://images.velog.io/images/semi_kimm/post/1034e1e5-3712-46ca-a910-0bf943200f73/image.png" alt=""></p>
<h3 id="splice">splice</h3>
<p>배열에서 특정 항목을 제거할 때 사용한다.</p>
<pre><code class="language-javascript"></code></pre>
<p>splice(1,2)에서
첫 번째 파라미터
=&gt; 어떤 인덱스부터 지울지
두 번째 파라미터
=&gt; 지울 항목의 갯수</p>
<h3 id="slice">slice</h3>
<p>배열을 잘라낼 때 사용하며 기존의 배열은 건들지 않고 새로운 배열을 반환한다.</p>
<pre><code class="language-javascript"></code></pre>
<p>slice(1,2)에서
첫 번째 파라미터
=&gt; 어떤 인덱스부터 자를지
두 번째 파라미터
=&gt; 어디까지 자를지</p>
<h3 id="shift">shift</h3>
<p>첫 번째 원소를 배열에서 추출하고 해당 배열에서 추출한 원소는 없어진다.</p>
<pre><code class="language-javascript"></code></pre>
<h3 id="unshift">unshift</h3>
<p>shift와 반대로 배열의 맨 앞에 새 원소를 추가한다.</p>
<h3 id="pop">pop</h3>
<p>마지막 원소를 배열에서 추출하며 해당 배열에서 추출한 원소는 없어진다.</p>
<h3 id="push">push</h3>
<p>pop과 반대로 배열의 맨 마지막에 새 항목을 추가한다.</p>
<h3 id="concat">concat</h3>
<p>여러개의 배열을 하나의 배열로 합쳐서 새로운 배열을 반환한다.</p>
<h3 id="join">join</h3>
<p>배열 안의 값들을 문자열 형태로 합친다.</p>
<h3 id="reduce중요">reduce(중요!!)</h3>
<pre><code class="language-javascript">const result7Average = result7.reduce((accumulator, current, index, array) =&gt; {
  if (index === array.length - 1) return accumulator / array.length;
  return accumulator + current;
}, 0);</code></pre>
<p>reduce 콜백 함수의 4가지 파라미터
=&gt; 누적값, 현재값, 현재 index, 현재 배열
초기값 설정해줘야된다!</p>
<h3 id="참고">참고</h3>
<p><a href="https://learnjs.vlpt.us/basics/09-array-functions.html">벨로퍼트와 함께하는 모던 자바스크립트</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] 이상형 월드컵 만들기]]></title>
            <link>https://velog.io/@semi_kimm/React.js-%EC%9D%B4%EC%83%81%ED%98%95%EC%9B%94%EB%93%9C%EC%BB%B5%EB%A7%8C%EB%93%A4%EA%B8%B0</link>
            <guid>https://velog.io/@semi_kimm/React.js-%EC%9D%B4%EC%83%81%ED%98%95%EC%9B%94%EB%93%9C%EC%BB%B5%EB%A7%8C%EB%93%A4%EA%B8%B0</guid>
            <pubDate>Wed, 20 Jan 2021 16:49:53 GMT</pubDate>
            <description><![CDATA[<p><a href="https://github.com/SemiKimm/Front-end-Study/commit/4ac5502ed7cf2e88de121d6ce15cd23968800f00">완성코드</a></p>
<h3 id="이상형-월드컵">이상형 월드컵</h3>
<p>4가지의 음식이 2개씩 제시된다.
제시된 음식 중 1개를 고른다.
토너먼트 형식으로 나머지 두개의 음식 중에서 1개를 고르며
최종적인 2종류에서 하나를 고른다.
마지막으로 고른 음식이 화면에 나타나게된다.</p>
<h3 id="stylejs--global-스타일-지정">style.js : global 스타일 지정</h3>
<p>터미널에서 
npm install styled-components 를 사용하여
styled-components를 설치한다</p>
<blockquote>
<p>style.js 파일 생성 후
적용시킬 css코드를 작성한다.</p>
</blockquote>
<pre><code class="language-javascript">const GlobalStyle=createGlobalStyle`
백틱 `을 사용하여 여기에 원하는 css코드를 넣을 수 있다.
`</code></pre>
<h3 id="gamejs">Game.js</h3>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] 입문-1]]></title>
            <link>https://velog.io/@semi_kimm/react%EC%9E%85%EB%AC%B8-1</link>
            <guid>https://velog.io/@semi_kimm/react%EC%9E%85%EB%AC%B8-1</guid>
            <pubDate>Wed, 13 Jan 2021 15:28:56 GMT</pubDate>
            <description><![CDATA[<p><a href="https://github.com/SemiKimm/Front-end-Study/tree/main/React-Introduction/begin-react/src">작성코드참고-github</a></p>
<h3 id="1-리액트란">1. 리액트란?</h3>
<p>react
virtual Dom 사용
virtual dom : 가상의 dom 이며 브라우저에 실제로 보여지는 dom이 아닌 메모리에 가상으로 존재하는 dom으로서 그냥 JS 객체이기 때문에 작동 성능이 실제로 브라우저에서 DOM을 보여주는 것 보다 속도가 빠르다.
리액트는 상태가 업데이트 되면 업데이트가 필요한 곳의 ui를 virtual dom을 통해 렌더링 한다. 이후 브라우저에 보여지고 있는 dom과 비교 후에 차이가 있는 곳을 확인하여 실제 dom 에 패치시킨다.</p>
<h3 id="2-새-프로젝트-만들기">2. 새 프로젝트 만들기</h3>
<blockquote>
<p>새로운 리액트 프로젝트 만들기
(begin-react 디렉터리가 생기면서 그 안에 리액트 프로젝트가 생성된다.)</p>
</blockquote>
<pre><code>$ npx create-react-app begin-react</code></pre><p>cd 명령어를 사용하여 생성된 디렉터리로 이동한 후 yarn start 명령 또는 npm start 명령어를 사용하여 브라우저를 시작한다.
시작되는 브라우저: <a href="http://localhost:3000/">http://localhost:3000/</a>
(자동으로 페이지가 열리지 않는다면 브라우저에 주소를 직접 입력하여 들어간다.)</p>
<pre><code>$ cd begin-react
$ yarn start</code></pre><p><img src="https://images.velog.io/images/semi_kimm/post/a6d58b71-3d4c-4382-9325-97ef8ce9dc19/image.png" alt=""></p>
<h3 id="3-나의-첫번째-리액트-컴포넌트">3. 나의 첫번째 리액트 컴포넌트</h3>
<blockquote>
<p>src 디렉터리에 Hello.js 파일을 작성한다.</p>
</blockquote>
<h4 id="hellojs">Hello.js</h4>
<pre><code class="language-javascript">import React from &#39;react&#39;;
function Hello() {
  return &lt;div&gt;안녕하세요&lt;/div&gt;;
}
export default Hello;</code></pre>
<p>리액트 컴포넌트를 만들 때는 다음 코드를 사용하여 리액트를 불러와야한다.</p>
<pre><code class="language-javascript">import React from &#39;react&#39;;</code></pre>
<p>리액트 컴포넌트는 함수 형태 또는 클래스 형태로 작성 가능하다.
생성한 컴포넌트를 다른 컴포넌트에서 불러와 사용하기 위해서는 컴포넌트 코드의 최하단에 export default를 해주어야 한다.</p>
<pre><code class="language-javascript">//Hello라는 컴포넌트를 내보내겠다는 의미
export default Hello;</code></pre>
<p>다른 컴포넌트에서 생성한 컴포넌트를 사용할 때에는 </p>
<pre><code class="language-javascript">import Hello from &#39;./Hello&#39;;</code></pre>
<p>처럼 import를 사용하여 사용할 수 있으며
컴포넌트는 일종의 UI 조각이고 쉽게 재사용이 가능하다.</p>
<h4 id="appjs">App.js</h4>
<pre><code class="language-javascript">import React from &#39;react&#39;;
import Hello from &#39;./Hello&#39;;
function App() {
  return (
    &lt;div&gt;
      &lt;Hello /&gt;
    //재사용가능함
      &lt;Hello /&gt;
      &lt;Hello /&gt;
    &lt;/div&gt;
  );
}
export default App;</code></pre>
<h4 id="indexjs">index.js</h4>
<p>코드에서 ReactDOM.render의 역할
: 브라우저에 있는 실제 DOM 내부에 리액트 컴포넌트를 렌더링하겠다는 의미</p>
<h3 id="4-jsx의-기본-규칙-알아보기">4. JSX의 기본 규칙 알아보기</h3>
<blockquote>
<p>JSX는 리액트에서 생김새를 정의할 때 사용하는 문법이며 HTML과 비슷한 생김새를 갖는다. 리액트 컴포넌트 파일에서 XML형태로 코드를 작성하면 babel이 JSX를 JavaScript로 변환해준다.</p>
</blockquote>
<p>  Babel
  : 자바스크립트의 문법을 확장해주는 도구</p>
<h4 id="jsx에서-지켜야할-규칙">JSX에서 지켜야할 규칙</h4>
<blockquote>
<ol>
<li>태그는 꼭 닫혀있어야 한다.
오류 예시</li>
</ol>
</blockquote>
<pre><code class="language-javascript">    &lt;div&gt;
      &lt;Hello /&gt;
      &lt;Hello /&gt;
      &lt;Hello /&gt;
      &lt;div&gt;
    &lt;/div&gt;</code></pre>
<ol start="2">
<li>태그와 태그 사이에 내용이 들어가지 않을 때에는 Self Closing 태그를 사용한다.
Self Closing  태그란 열리고 바로 닫히는 태그를 의미한다.
예시<pre><code>&lt;Hello /&gt;</code></pre></li>
<li>꼭 감싸져야하는 태그
두개 이상의 태그는 무조건 하나의 태그로 감싸져 있어야 한다.
오류 예시<pre><code class="language-javascript">function App() {
return (
 &lt;Hello /&gt;
 &lt;div&gt;안녕히계세요.&lt;/div&gt;
);
}</code></pre>
올바른 예시<pre><code class="language-javascript">function App() {
return (
 &lt;div&gt;
   &lt;Hello /&gt;
   &lt;div&gt;안녕히계세요.&lt;/div&gt;
 &lt;/div&gt;
);
}</code></pre>
</li>
</ol>
<h4 id="fragment">Fragment</h4>
<blockquote>
<p>단순히 감싸기 위해 불필요한 div로 감싸는것은 별로 좋지 않다. 이를 위해 fragment를 사용한다. fragment는 태그를 작성 할 때 이름 없이 작성을 하는 것이며 브라우저 상에서 따로 별도의 엘리먼트로 나타나지 않는다.
&lt;&gt;&lt;/&gt;</p>
</blockquote>
<pre><code class="language-javascript">function App() {
  return (
    &lt;&gt;
      &lt;Hello /&gt;
      &lt;div&gt;안녕히계세요.&lt;/div&gt;
    &lt;/&gt;
  );
}</code></pre>
<h4 id="jsx안에-자바스크립트-값-사용하기">JSX안에 자바스크립트 값 사용하기</h4>
<p>JSX 내부에 자바스크립트 변수를 보여줘야 할 때에는 {}로 감싸서 사용한다.</p>
<pre><code class="language-javascript">function App() {
  return (
    &lt;&gt;
      &lt;Hello /&gt;
      &lt;div&gt;안녕히계세요.&lt;/div&gt;
      &lt;div&gt;{name}&lt;/div&gt;
    &lt;/&gt;
  );
}</code></pre>
<h4 id="style과-classname">style과 className</h4>
<blockquote>
<p>JSX에서 태그에 style과 CSS class를 설정하는 방법은 인라인 스타일은 객체 형태로 작성해야 하며 -로 구분되어 있는 이름들(background-color)은 붙여서 camelCase형태(backgroundColor)로 네이밍 해주어야 한다.
CSS class를 설정 할 때에는 class=가 아닌 className=으로 설정을 해주어야 한다.
<img src="https://images.velog.io/images/semi_kimm/post/53dca5a9-17dc-40d6-b71b-60c02822e0ee/image.png" alt=""></p>
</blockquote>
<h4 id="appjs-1">App.js</h4>
<pre><code class="language-javascript">import React from &#39;react&#39;;
import Hello from &#39;./Hello&#39;;
import &#39;./App.css&#39;;
function App() {
  const name = &#39;react&#39;;
  const style = {
    backgroundColor: &#39;black&#39;,
    color: &#39;aqua&#39;,
    fontSize: 24,
    padding: &#39;1rem&#39;,
  };
  return (
    &lt;&gt;
      &lt;Hello /&gt;
      &lt;div style={style}&gt;{name}&lt;/div&gt;
      &lt;div&gt;안녕히계세요.&lt;/div&gt;
      &lt;div&gt;{name}&lt;/div&gt;
      &lt;div className=&#39;gray-box&#39;&gt;&lt;/div&gt;
    &lt;/&gt;
  );
}</code></pre>
<h4 id="주석">주석</h4>
<pre><code class="language-javascript">{/* JSX내부의 주석 
주석은 화면에 보이지 않고 중괄호로 감싸지 않으면 화면에 보인다.*/}
&lt;Hello
//열리는 태그 내부에서는 이렇게 주석 작성이 가능하다.
/&gt;</code></pre>
<h3 id="5-props를-통해-컴포넌트에게-값-전달하기">5. props를 통해 컴포넌트에게 값 전달하기</h3>
<blockquote>
<p>props
: properties의 줄임말이며 어떠한 값을 컴포넌트에게 전달할때 props를 사용한다.</p>
</blockquote>
<h4 id="props의-기본-사용법">props의 기본 사용법</h4>
<blockquote>
<p>App컴포넌트에서 Hello컴포넌트를 사용할 때 name이라는 값을 전달한다고 가정</p>
</blockquote>
<h4 id="appjs-2">App.js</h4>
<pre><code class="language-javascript">import React from &#39;react&#39;;
import Hello from &#39;./Hello&#39;;
import &#39;./App.css&#39;;
function App() {
  return (
    &lt;&gt;
      &lt;Hello name=&#39;react&#39; color=&quot;red&quot;/&gt;
    &lt;/&gt;
  );
}</code></pre>
<p>컴포넌트에 전달되는 props는 파라미터를 통해 조회 가능하고 props는 객체 형태로 전달되며 name 값을 조회하려면 props.name을 조회하면 된다.</p>
<h4 id="hellojs-1">Hello.js</h4>
<pre><code class="language-javascript">import React from &#39;react&#39;;
function Hello(props) {
  return &lt;div style={{color: props.color}}&gt;안녕하세요{props.name}&lt;/div&gt;;
}
export default Hello;</code></pre>
<h4 id="여러개의-props-비구조화-할당구조-분해">여러개의 props, 비구조화 할당(=구조 분해)</h4>
<blockquote>
<p>props 내부의 값을 조회 할때마다 props.를 입력하는 것을 개선하기 위해 비구조화 할당 즉, 구조분해문법을 사용한다.</p>
</blockquote>
<h4 id="hellojs-2">Hello.js</h4>
<pre><code class="language-javascript">import React from &#39;react&#39;;
function Hello({ color, name }) {
  return &lt;div style={{ color }}&gt;안녕하세요{name}&lt;/div&gt;;
}
export default Hello;</code></pre>
<h4 id="defaultprops로-기본값-설정">defaultProps로 기본값 설정</h4>
<blockquote>
<p>컴포넌트에 props를 지정하지 않았을 때 기본적으로 사용 할 값을 설정하고 싶으면 컴포넌트에 defualtProps 값을 설정하면 된다.</p>
</blockquote>
<h4 id="hellojs-3">Hello.js</h4>
<pre><code class="language-javascript">import React from &#39;react&#39;;
function Hello({ color, name }) {
  return &lt;div style={{ color }}&gt;안녕하세요{name}&lt;/div&gt;;
}
Hello.defaultProps = {
  name: &#39;이름없음&#39;,
};
export default Hello;</code></pre>
<h4 id="appjs-3">App.js</h4>
<pre><code class="language-javascript">import React from &#39;react&#39;;
import Hello from &#39;./Hello&#39;;
function App() {
  return (
    &lt;&gt;
      &lt;Hello name=&#39;react&#39; color=&#39;red&#39; /&gt;
      {/*name이 없는 Hello 컴포넌트
      -&gt;defalutProps에 의해 값이 배정된다.*/}
      &lt;Hello color=&#39;pink&#39; /&gt;
    &lt;/&gt;
  );
}
export default App;</code></pre>
<h4 id="propschildren">props.children</h4>
<blockquote>
<p>컴포넌트 태그 사이에 넣은 값을 조회하고 싶을 경우 props.children을 조회하면 된다.
먼저 Wrapper.js를 src디렉터리에 추가한다.</p>
</blockquote>
<h4 id="wrapperjspropschileren추가안한">Wrapper.js(props.chileren추가안한)</h4>
<pre><code class="language-javascript">import React from &#39;react&#39;;
function Wrapper() {
  const style = {
    border: &#39;2px solid black&#39;,
    padding: &#39;16px&#39;,
  };
  return &lt;div style={style}&gt;&lt;/div&gt;;
}
export default Wrapper;</code></pre>
<h4 id="appjs-4">App.js</h4>
<pre><code class="language-javascript">import React from &#39;react&#39;;
import Hello from &#39;./Hello&#39;;
import Wrapper from &#39;./Wrapper&#39;;
import &#39;./App.css&#39;;
function App() {
  return (
    &lt;Wrapper&gt;
      &lt;Hello name=&#39;react&#39; color=&#39;red&#39; /&gt;
      &lt;Hello color=&#39;pink&#39; /&gt;
    &lt;/Wrapper&gt;
  );
}
export default App;</code></pre>
<p>Hello 컴포넌트들이 보이지 않는다.
<img src="https://images.velog.io/images/semi_kimm/post/2fe187d8-b93f-40fe-a322-21b36df5c8a7/image.png" alt="">
내부의 내용이 보여지게 하기 위해  Wrapper.js에 props.children을 렌더링해준다.</p>
<h4 id="wrapperjs">Wrapper.js</h4>
<pre><code class="language-javascript">import React from &#39;react&#39;;
function Wrapper({ children }) {
  const style = {
    border: &#39;2px solid black&#39;,
    padding: &#39;16px&#39;,
  };
  return &lt;div style={style}&gt;{children}&lt;/div&gt;;
}
export default Wrapper;</code></pre>
<p><img src="https://images.velog.io/images/semi_kimm/post/7c43ddba-aba2-4dc4-92fc-aa6553750601/image.png" alt=""></p>
<h3 id="6-조건부-렌더링">6. 조건부 렌더링</h3>
<p>조건부 렌더링
: 특정 조건에 따라 다른 결과물을 렌더링 하는 것</p>
<blockquote>
<p>App 컴포넌트에서 Hello 컴포넌트 사용 시 isSpecial 라는 props 사용
(true 값은 자바스크립트 값이기 때문에 사용시에 {}로 감싸준다.)</p>
</blockquote>
<h4 id="appjs-5">App.js</h4>
<pre><code class="language-javascript">import React from &#39;react&#39;;
import Hello from &#39;./Hello&#39;;
import Wrapper from &#39;./Wrapper&#39;;
function App() {
  return (
    &lt;Wrapper&gt;
      &lt;Hello name=&quot;react&quot; color=&quot;red&quot; isSpecial={true}/&gt;
      &lt;Hello color=&quot;pink&quot; /&gt;
    &lt;/Wrapper&gt;
  )
}
export default App;</code></pre>
<p>Hello컴포넌트에서 isSpecial값에 따라 컴포넌트의 좌측에 *가 표시되도록 한다.</p>
<h4 id="hellojs-4">Hello.js</h4>
<pre><code class="language-javascript">import React from &#39;react&#39;;
function Hello({ color, name, isSpecial }) {
  return (
    &lt;div style={{ color }}&gt;
      {/*{isSpecial ? &lt;b&gt;*&lt;/b&gt; : null}*/}
      {/*단축평가논리계산법*/}
      {isSpecial &amp;&amp; &lt;b&gt;*&lt;/b&gt;}
      안녕하세요 {name}
    &lt;/div&gt;
  );
}
Hello.defaultProps = {
  name: &#39;이름없음&#39;
}
export default Hello;</code></pre>
<p>(JSX에서 null, false, undefiend를 렌더링하면 아무것도 나타나지 않게 된다.)</p>
<h4 id="props-값-설정을-생략하면-항상-true-이다">props 값 설정을 생략하면 항상 true 이다.</h4>
<p>isSpecial={true}와 isSpecial 은 동일하다.</p>
<h3 id="7-usestate를-통해-컴포넌트에서-바뀌는-값-관리하기">7. useState를 통해 컴포넌트에서 바뀌는 값 관리하기</h3>
<p>useState
: 리액트의 Hooks 중 하나이며 컴포넌트에서 보여줘야 하는 내용이 사용자 인터랙션에 따라 동적으로 바뀔 수 있도록 한다.</p>
<blockquote>
<h4 id="버튼을-누르면-숫자가-바뀌는-counter-컴포넌트">버튼을 누르면 숫자가 바뀌는 Counter 컴포넌트</h4>
<p>src디렉터리에 Counter.js를 추가한다.</p>
</blockquote>
<h4 id="이벤트-설정">이벤트 설정</h4>
<p>onClick을 사용하여 버튼에 클릭 이벤트를 추가해준다.
리액트에서 엘리먼트에 이벤트를 설정해줄때는
on이벤트이름 = {실행하고싶은함수}
형태로 설정하며 {}안에는 함수형태를 넣어야지 함수를 실행하면 렌더링되는 시점에서 함수가 호출되버리기 때문에 안된다.
<del>잘못된 예시 : onClick={onIncrease()}</del></p>
<h4 id="동적인-값-주기-usestate">동적인 값 주기, useState</h4>
<p>state(상태) : 컴포넌트에서의 동적인 값
useState : 리액트에서 컴포넌트의 상태를 관리해주는 함수</p>
<pre><code class="language-javascript">import React, {useState} from &#39;react&#39;;</code></pre>
<p>위 코드처럼 리액트 패키지에서 useState라는 함수를 불러와 사용한다.</p>
<pre><code class="language-javascript">const [number, setNumber] = useState(0);</code></pre>
<p>useState를 사용할 때는 상태의 기본값을 파라미터로 넣어서 호출하고 함수를 호출하면 배열이 반환되며 첫번째 원소는 현재 상태이고 두번째 원소는 Setter 함수이다.(배열 비구조화 할당을 사용하여 각 원소를 추출하였다.)
Setter 함수 : 파라미터로 전달 받은 값을 최신 상태로 설정한다.</p>
<h4 id="counterjs">Counter.js</h4>
<pre><code class="language-javascript">import React, { useState } from &#39;react&#39;;
function Counter() {
  const [number, setNumber] = useState(0);
  const onIncrease = () =&gt; {
    //console.log(&#39;+1&#39;);
    setNumber(number + 1);
  };
  const onDecrease = () =&gt; {
    //console.log(&#39;-1&#39;);
    setNumber(number - 1);
  };
  return (
    &lt;div&gt;
      &lt;h1&gt;{number}&lt;/h1&gt;
      &lt;button onClick={onIncrease}&gt;+1&lt;/button&gt;
      &lt;button onClick={onDecrease}&gt;-1&lt;/button&gt;
    &lt;/div&gt;
  );
}
export default Counter;</code></pre>
<h4 id="appjs-6">App.js</h4>
<pre><code class="language-javascript">import React from &#39;react&#39;;
import Counter from &#39;./Counter&#39;;
function App() {
  return (
    &lt;Counter /&gt;
  );
}
export default App;</code></pre>
<h4 id="함수형-업데이트">함수형 업데이트</h4>
<p>함수형 업데이트는 주로 컴포넌트를 최적화 하게 될 때 사용한다.</p>
<blockquote>
<p>Setter함수 사용시 업데이트 하고 싶은 새로운 값을 파라미터로 넣어주는 대신 기존 값을 어떻게 업데이트 할 지에 대한 함수를 등록하여 값을 업데이트 할 수 있다.</p>
</blockquote>
<pre><code class="language-javascript">const onIncrease = () =&gt; {
    setNumber(number + 1);
  };</code></pre>
<p>위 코드를 함수형 업데이트를 사용하면</p>
<pre><code class="language-javascript">const onIncrease = () =&gt; {
    setNumber(prevNumber =&gt; prevNumber + 1);
  }</code></pre>
<p>위와 같이 prevNumber라는 값을 업데이트 하는 함수를 파라미터로 사용하여 나타낼 수 있다.</p>
<h3 id="8-input-상태-관리하기">8. input 상태 관리하기</h3>
<p>리액트에서 사용자가 입력할 수 있는 input 태그의 상태를 관리한다.</p>
<blockquote>
<p>input에 입력하는 값이 하단에 나타나게 하고, 초기화 버튼을 누르면 input 값이 비워지도록 구현한다.
useState를 사용하여 input의 값을 관리한다.
input에는 onChange라는 이벤트를 사용하며 이벤트 객체 e를 파라미터로 받아와서 사용하고 e.target은 이벤트가 발생한 input DOM을 가리킨다. e.target.value를 조회하면 현재 input에 입력된 값을 알 수 있다.</p>
</blockquote>
<h4 id="inputsamplejs">InputSample.js</h4>
<pre><code class="language-javascript">import React, { useState } from &#39;react&#39;;
function InputSample() {
  const [text, setText] = useState(&#39;&#39;);
  const onChange = (e) =&gt; {
    setText(e.target.value);
  };
  const onReset = () =&gt; {
    setText(&#39;&#39;);
  };
  return (
    &lt;div&gt;
      &lt;input onChange={onChange} /&gt;
      &lt;button onClick={onReset}&gt;초기화&lt;/button&gt;
      &lt;div&gt;
        &lt;b&gt;값: {text}&lt;/b&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  );
}
export default InputSample;</code></pre>
<h4 id="appjs-7">App.js</h4>
<pre><code class="language-javascript">import React from &#39;react&#39;;
import InputSample from &#39;./InputSample&#39;;
function App() {
  return (
    &lt;InputSample /&gt;
  );
}
export default App;</code></pre>
<h3 id="9-여러개의-input-상태-관리하기">9. 여러개의 input 상태 관리하기</h3>
<blockquote>
<p>input의 개수가 여러개일때 useState를 여러번 사용하고 onChange도 여러개 만들어서 구현할 수 있지만 좋지 않다.
좋은 방법은 input에 name을 설정하고 이벤트가 발생했을 때 이 값을 참조하는 것이다.
그리고, useState에서는 문자열이 아닌 객체 형태의 상태를 관리해야 한다.</p>
</blockquote>
<h4 id="inputsamplejs-1">InputSample.js</h4>
<pre><code class="language-javascript">import React, { useState } from &#39;react&#39;;
function InputSample() {
  const [inputs, setInputs] = useState({
    name: &#39;&#39;,
    nickname: &#39;&#39;,
  });
  const { name, nickname } = inputs; //비구조화할당
  const onChange = (e) =&gt; {
    const { value, name } = e.target;
    setInputs({
      ...inputs, //기존의 input 객체 복사
      [name]: value, //name 키를 가진 값을 value 로 설정
    });
  };
  const onReset = () =&gt; {
    setInputs({
      name: &#39;&#39;,
      nickname: &#39;&#39;,
    });
  };
  return (
    &lt;div&gt;
      &lt;input placeholder=&#39;이름&#39; onChange={onChange} value={name} /&gt;
      &lt;input placeholder=&#39;닉네임&#39; onChange={onChange} value={nickname} /&gt;
      &lt;button onClick={onReset}&gt;초기화&lt;/button&gt;
      &lt;div&gt;
        &lt;b&gt;값:&lt;/b&gt;
        {name} ({nickname})
      &lt;/div&gt;
    &lt;/div&gt;
  );
}
export default InputSample;</code></pre>
<p>리액트에서 객체 수정시 새로운 객체를 만들어서 새로운 객체에 변화를 주고 이것을 상태로 사용해야 한다.
<img src="https://images.velog.io/images/semi_kimm/post/44a5af77-eeef-420c-b7b0-61dd067a157d/image.png" alt="">
이러한 작업을 &quot;불변성을 지킨다&quot;라고 하며 불변성을 지켜야만 리액트 컴포넌트에서 상태가 업데이트 됐음을 확인하고 필요한 리렌더링이 진행될 수 있다. 잘못된 예시로 기존 상태를 직접 수정할 경우 값을 바꿔도 리렌더링이 되지 않는다.</p>
<h4 id="spread-문법">spread 문법</h4>
<p>&#39;...&#39; 문자를 사용한다.</p>
<pre><code>...inputs,</code></pre><p>객체의 내용을 모두 펼쳐서 기존 객체를 복사해준다. 즉, 기존의 것을 건들지 않고 새로운 객체를 만든다.
spread연산자는 배열에서도 사용할 수 있으며 여러번 사용도 가능하다.
<a href="https://learnjs.vlpt.us/useful/07-spread-and-rest.html">spread 참고</a></p>
<h3 id="10-useref로-특정-dom-선택하기">10. useRef로 특정 DOM 선택하기</h3>
<p>JavaScript의 경우 특정 DOM을 선택해야될 때
getElementById,querySelector
같은 DOM Selector함수를 사용하여 DOM을 선택한다.</p>
<p>React에서도 특정 엘리먼트의 크기를 가져오거나 스크롤바 위치를 가져오거나 설정하거나 또는 포커스를 설정해야되는 등의 경우에 DOM을 직접 선택해야 한다.</p>
<p>이때, React에서는 ref라는 것을 사용한다.</p>
<p>함수형 컴포넌트에서 ref를 사용 할 때는 useRef 라는 Hook 함수를 사용한다.</p>
<p>클래스형 컴포넌트에서는 콜백 함수나 React.createRef 라는 함수를 사용한다.</p>
<blockquote>
<p>InputSample 에서 초기화 버튼을 눌렀을 때 input에 포커스가 잡히도록 useRef를 사용해 구현해본다.</p>
</blockquote>
<h4 id="inputsamplejs-2">InputSample.js</h4>
<pre><code class="language-javascript">import React, { useState, useRef } from &#39;react&#39;;
function InputSample() {
  const [inputs, setInputs] = useState({
    name: &#39;&#39;,
    nickname: &#39;&#39;,
  });
  const nameInput = useRef();
  const { name, nickname } = inputs; //비구조화할당
  const onChange = (e) =&gt; {//내용 위 코드 참조
  };
  const onReset = () =&gt; {
    setInputs({
      name: &#39;&#39;,
      nickname: &#39;&#39;,
    });
    nameInput.current.focus();
  };
  return (
    &lt;div&gt;
      &lt;input
        name=&#39;name&#39;
        placeholder=&#39;이름&#39;
        onChange={onChange}
        value={name}
        ref={nameInput}
      /&gt;
      &lt;input
        name=&#39;nickname&#39;
        placeholder=&#39;닉네임&#39;
        onChange={onChange}
        value={nickname}
      /&gt;
      &lt;button onClick={onReset}&gt;초기화&lt;/button&gt;
      &lt;div&gt;
        &lt;b&gt;값:&lt;/b&gt;
        {name} ({nickname})
      &lt;/div&gt;
    &lt;/div&gt;
  );
}
export default InputSample;</code></pre>
<p>useRef()를 사용하여 Ref 객체를 만든다.</p>
<pre><code class="language-javascript">const nameInput = useRef();</code></pre>
<p>만든 객체를 선택하고 싶은 DOM에 ref값으로 설정해준다. 그러면 Ref 객체의 .current 값은 우리가 원하는 DOM을 가리키게 된다.</p>
<pre><code class="language-javascript">&lt;input
        name=&#39;name&#39;
        placeholder=&#39;이름&#39;
        onChange={onChange}
        value={name}
        ref={nameInput}
      /&gt;</code></pre>
<p>onReset 함수에서 특정 DOM에 포커스하는 focus() DOM API를 호출하였다. 여기서 Ref 객체의 .current 값은 우리가 원하는 DOM을 가리킨다.</p>
<pre><code class="language-javascript">const onReset = () =&gt; {
    setInputs({
      name: &#39;&#39;,
      nickname: &#39;&#39;,
    });
    nameInput.current.focus();
  };</code></pre>
<h3 id="11-배열-렌더링하기">11. 배열 렌더링하기</h3>
<blockquote>
</blockquote>
<p>아래 코드는 재사용 되는 코드를 일일히 작성하여 구현한 좋지 않은 코드</p>
<h4 id="userlistjs">UserList.js</h4>
<pre><code class="language-javascript">function UserList() {
  const users = [
    {
      id: 1,
      username: &#39;velopert&#39;,
      email: &#39;public.velopert@gmail.com&#39;,
    },
    {
      id: 2,
      username: &#39;tester&#39;,
      email: &#39;tester@example.com&#39;,
    },
    {
      id: 3,
      username: &#39;liz&#39;,
      email: &#39;liz@example.com&#39;,
    },
  ];
  return (
    &lt;div&gt;
      &lt;div&gt;
        &lt;b&gt;{users[0].username}&lt;/b&gt; &lt;span&gt;({users[0].email})&lt;/span&gt;
      &lt;/div&gt;
      &lt;div&gt;
        &lt;b&gt;{users[1].username}&lt;/b&gt; &lt;span&gt;({users[1].email})&lt;/span&gt;
      &lt;/div&gt;
      &lt;div&gt;
        &lt;b&gt;{users[2].username}&lt;/b&gt; &lt;span&gt;({users[1].email})&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  );
}</code></pre>
<p>컴포넌트를 재사용 가능하도록 수정한다.</p>
<h4 id="userlistjs-1">UserList.js</h4>
<pre><code class="language-javascript">function User({ user }) {
  return (
    &lt;div&gt;
      &lt;b&gt;{user.username}&lt;/b&gt; &lt;span&gt;({user.email})&lt;/span&gt;
    &lt;/div&gt;
  );
}
function UserList() {
  const users = [
    {
      id: 1,
      username: &#39;velopert&#39;,
      email: &#39;public.velopert@gmail.com&#39;,
    },
    {
      id: 2,
      username: &#39;tester&#39;,
      email: &#39;tester@example.com&#39;,
    },
    {
      id: 3,
      username: &#39;liz&#39;,
      email: &#39;liz@example.com&#39;,
    },
  ];
  return (
    &lt;div&gt;
      &lt;User user={users[0]} /&gt;
      &lt;User user={users[1]} /&gt;
      &lt;User user={users[2]} /&gt;
    &lt;/div&gt;
  );
}</code></pre>
<p>두번째 코드와 같은 구현은 배열이 고정적인 경우에는 괜찮지만
이렇게 배열의 인덱스를 하나하나 조회하면서 렌더링하는 방법은 동적인 배열을 렌더링하지 못한다.
동적인 배열을 렌더링해야 할 때는 자바스크립트 배열의 내장함수인 map() 을 사용하여 구현한다.</p>
<h4 id="userlistjs-2">UserList.js</h4>
<pre><code>function User({ user }) {
  return (
    &lt;div&gt;
      &lt;b&gt;{user.username}&lt;/b&gt; &lt;span&gt;({user.email})&lt;/span&gt;
    &lt;/div&gt;
  );
}
function UserList() {
  const users = [
    {
      id: 1,
      username: &#39;velopert&#39;,
      email: &#39;public.velopert@gmail.com&#39;,
    },
    {
      id: 2,
      username: &#39;tester&#39;,
      email: &#39;tester@example.com&#39;,
    },
    {
      id: 3,
      username: &#39;liz&#39;,
      email: &#39;liz@example.com&#39;,
    },
  ];
  return (
    &lt;div&gt;
      {users.map((user) =&gt; (
        &lt;User user={user} /&gt;
      ))}
    &lt;/div&gt;
  );
}</code></pre><p>위와 같이 구현을 할 경우 동적으로 렌더링이 가능하지만 아래와 같은 경고메시지를 확인할 수 있다. 이 경고 메시지는 각 고유 원소에 key가 있어야만 배열이 업데이트 될때 효율적으로 렌더링 될 수 있기 때문에 나타난다.
<img src="https://images.velog.io/images/semi_kimm/post/e644e730-b7cc-482c-b9a6-2e16144eeb93/image.png" alt="">
리액트에서 배열을 렌더링 할때는 key 라는 props를 설정해야 한다.
여기서 key 값은 각 원소들마다 가지고 있는 고유값으로 설정해야한다.
만약 배열 안의 원소가 가지고 있는 고유 값이 없다면 map() 함수를 사용할 때 설정하는 콜백함수의 두번째 파라미터 index를 key 로 사용하면된다.</p>
<h4 id="userlistjs-3">UserList.js</h4>
<pre><code class="language-javascript">function User({ user }) {
  return (
    &lt;div&gt;
      &lt;b&gt;{user.username}&lt;/b&gt; &lt;span&gt;({user.email})&lt;/span&gt;
    &lt;/div&gt;
  );
}
function UserList() {
  const users = [
    {
      id: 1,
      username: &#39;velopert&#39;,
      email: &#39;public.velopert@gmail.com&#39;,
    },
    {
      id: 2,
      username: &#39;tester&#39;,
      email: &#39;tester@example.com&#39;,
    },
    {
      id: 3,
      username: &#39;liz&#39;,
      email: &#39;liz@example.com&#39;,
    },
  ];
  return (
    &lt;div&gt;
      {users.map((user) =&gt; (
        &lt;User user={user} key={user.id} /&gt;
      ))}
    &lt;/div&gt;
  );
}</code></pre>
<p>배열을 렌더링 할때는 고유한 key 값이 있는것이 중요하다. 만약 배열안에 중복되는 key가 있다면 렌더링시 오류 메시지가 콘솔창에 뜨며 업데이트가 제대로 이루어지지 않는다.</p>
<h3 id="12-useref로-컴포넌트-안의-변수-만들기">12. useRef로 컴포넌트 안의 변수 만들기</h3>
<p>useRef의 용도</p>
<ol>
<li>함수형 컴포넌트에서 DOM 선택</li>
<li>컴포넌트 내에서 조회 및 수정 할 수 있는 변수 관리</li>
</ol>
<p>리액트 컴포넌트에서의 상태는 상태를 바꾸는 함수를 호출 후에 그 다음 렌더링 이후에야 업데이트 된 상태를 조회 가능하다.
useRef로 관리하는 변수는 값이 바뀐다고 해서 컴포넌트가 리렌더링되지 않고 설정 후에 바로 조회가 가능하다.</p>
<p>useRef로 관리하는 변수를 사용하여 다음 값을 관리 가능하다.</p>
<ul>
<li>setTimeout, setInterval을 통해 만들어진 id</li>
<li>외부 라이브러리를 사용하여 생성된 인스턴스</li>
<li>scroll 위치</li>
</ul>
<blockquote>
<p>App컴포넌트에서 useRef를 사용한 변수 관리
목적 : 배열에 새 항목을 추가할 때 새 항목에서 사용 할 고유 id 관리
먼저 users 배열을 App에서 선언하고 UserList에 props로 전달하고
App에서 useRef()를 사용하여 nextId라는 변수 생성한다.
이때 useRef()안에 파라미터를 넣어주면 .current값의 기본값이 된다. 즉, nextId의 기본값이 된다.
nextId 값을 수정하기 위해 값을 조회하려면 .current를 조회하면 된다.</p>
</blockquote>
<h4 id="appjs-8">App.js</h4>
<pre><code class="language-javascript">import React from &#39;react&#39;;
import UserList from &#39;./UserList&#39;;
import &#39;./App.css&#39;;
function App() {
  const users = [
    {
      id: 1,
      username: &#39;velopert&#39;,
      email: &#39;public.velopert@gmail.com&#39;,
    },
    {
      id: 2,
      username: &#39;tester&#39;,
      email: &#39;tester@example.com&#39;,
    },
    {
      id: 3,
      username: &#39;liz&#39;,
      email: &#39;liz@example.com&#39;,
    },
  ];
    const nextId = useRef(4);
  const onCreat = () =&gt; {
    nextId.current += 1;
  };
  return (
    &lt;Wrapper&gt;
      &lt;UserList users={users} /&gt;
    &lt;/Wrapper&gt;
  );
}
export default App;</code></pre>
<h4 id="userlistjs-4">UserList.js</h4>
<pre><code class="language-javascript">import React from &#39;react&#39;;
function User({ user }) {
  return (
    &lt;div&gt;
      &lt;b&gt;{user.username}&lt;/b&gt; &lt;span&gt;({user.email})&lt;/span&gt;
    &lt;/div&gt;
  );
}
function UserList({ users }) {
  return (
    &lt;div&gt;
      {users.map((user) =&gt; (
        &lt;User user={user} key={user.id} /&gt;
      ))}
    &lt;/div&gt;
  );
}
export default UserList;</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JavaScript] 타자게임 만들기]]></title>
            <link>https://velog.io/@semi_kimm/VanillaJsTypingGame</link>
            <guid>https://velog.io/@semi_kimm/VanillaJsTypingGame</guid>
            <pubDate>Wed, 06 Jan 2021 15:18:23 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>영상
<a href="https://youtu.be/_CsGSE5gwTA">Vanilla 자바스크립트 타자게임 만들기! 실전코스</a> </p>
</blockquote>
<h3 id="타자-게임-동작-방식">타자 게임 동작 방식</h3>
<p>하단 게임시작 버튼 click시 카운트 다운이 시작되면서 버튼이 게임중으로 변경된다.
주어진 시간 안에 제시어를 input 창에 입력하면 획득 점수가 쌓인다.
제시어는 랜덤하게 주어진다.
단어를 시간안에 작성하지 못할 경우에는 게임이 종료가 되면서 하단 버튼이 다시 게임 시작으로 변경된다.
다시 게임 시작을 하면 점수가 초기화되면서 게임을 다시 진행할 수 있다.</p>
<blockquote>
<p>완성 코드
<a href="https://github.com/SemiKimm/Front-end-Study/tree/main/VanillaJS-Typing-Game-Make">VanillaJS-Typing-Game-Make</a></p>
</blockquote>
<h3 id="setinterval">setInterval()</h3>
<p><em>setInterval(fn, delay)</em>
일정시간마다 함수를 실행한다.</p>
<h3 id="clearinterval">clearInterval()</h3>
<p><em>clearInterval(setInterval로 생성된 변수)</em>
setInterval()로 반복하고 있는 것을 멈추게 한다.</p>
<h3 id="flex_css속성">flex_css속성</h3>
<p>하나의 플렉스 아이템이 자신의 컨테이너가 차지하는 공간에 맞추기 위해 크기를 키우거나 줄이는 방법을 설정하는 속성이며 flex-grow, flex-shrink, flex-basis의 단축 속성이다.
flex 속성은 한 개에서 세 개의 값을 사용해 지정할 수 있다.
<em>(1) 값이 한 개일 때, 그 값은 다음 중 하나여야 한다.
    - number를 지정하면 flex-shrink이다.
      - lenght 또는 percentage를 지정하면 flex-basis이다.
      - none, auto, initial 중 하나를 지정할 수 있다.
(2) 값이 두 개일 때, 첫 번째 값은 number여야 하며 flex-grow가 된다.
  두 번째 값은 다음 중 하나여야 한다.
      - number를 지정하면 flex-shrink이다.
      - length, percentage, 또는 auto를 지정하면 flex-basis이다.
(3) 값이 세 개일 때 다음 순서를 따라야 한다.
      1. flex-grow에 사용할 number
      2. flex-shrink에 사용할 number
      3. flex-basis에 사용할 length, percentage, 또는 auto</em></p>
<blockquote>
<p>initial
: 아이템 크기가 각각의 width와 height 속성에 따라 정해지고 플렉스 컨테이너의 크기를 넘지 않기 위해 최소 크기로 줄어들 수 있지만 남은 공간을 채우기 위해 늘어나지는 않는다. flex: 0 1 auto와 동일하다.
auto
: 아이템 크기가 각각의 width와 height속성에 따라 정해진다. 플렉스 컨테이너의 크기를 넘지 않기 위해 최소 크기로 줄어들 수 있고 남은 공간을 채우기 위해 늘어날 수 있다. flex: 1 1 auto와 동일하다.
none
: 아이템 크기가 각각의 width와 height 속성에 따라 정해진다. 컨테이너의 크기에 관계 없이 변하지 않는다. flex: 0 0 auto와 동일하다.
flex-grow
: 플렉스 아이템의 flex-grow를 지정한다. 음수 값은 유효하지 않으며 생략 시 기본값은 0이다.
flex-shrink
: 플렉스 아이템의 flex-shrink를 지정하며 음수 값은 유효하지 않고 생략 시 기본값은 1이다.
flex-basis
: 플렉스 아이템의 flex-basis를 지정하au 0을 지정하려면 flex-grow 또는 flex-shrink로 읽히지 않도록 단위를 붙여야 한다. 생략 시 기본값은 auto이다.</p>
</blockquote>
<ul>
<li>한 개 또는 두 개의 단위 없는 숫자 값을 사용할 때, flex-basis의 값은 auto가 아니라 0이 된다.</li>
</ul>
<h3 id="grid_css속성">grid_css속성</h3>
<p>shorthand property이며 외재적인 속성인 (grid-template-rows, grid-template-columns, grid-template-areas), 값과 내재적인 속성인 (grid-auto-rows, grid-auto-columns, grid-auto-flow), 값을 한번에 설정한다.</p>
<h3 id="rel_html속성">rel_html속성</h3>
<p>링크된 문서와의 관계를 지정하며 a, area, link요소의 속성으로 사용된다. rel속성은 사용자와는 직접 연결되지 않지만 브라우저나 검색엔진에 링크 관계에 대한 정보를 주어 사용자의 요청에 더 정확한 대응이 가능하게 해준다. 
rel에 2가지 이상의 속성값을 지정할 때에는 속성값을 띄어쓰기로 구분한다. 
rel은 href속성의 추가 정보이므로 href속성이 있을 때에만 지정한다.</p>
<h3 id="참고">참고</h3>
<p><a href="https://xn--xy1bk56a.run/axios/guide/refs.html#%EC%8B%9C%EB%A9%98%ED%8B%B1-%EB%B2%84%EC%A0%84-semvers">Axios</a>
<a href="https://developer.mozilla.org/ko/docs/Web/CSS/flex">flex_css</a>
<a href="https://developer.mozilla.org/ko/docs/Web/CSS/grid">grid_css</a>
<a href="https://m.blog.naver.com/PostView.nhn?blogId=zoomen1004&amp;logNo=220693042851&amp;proxyReferer=https:%2F%2Fwww.google.com%2F">rel_html</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] 리스트]]></title>
            <link>https://velog.io/@semi_kimm/List</link>
            <guid>https://velog.io/@semi_kimm/List</guid>
            <pubDate>Tue, 05 Jan 2021 17:59:49 GMT</pubDate>
            <description><![CDATA[<h3 id="데이터를-순서대로-나열한-자료구조">데이터를 순서대로 나열한 자료구조</h3>
<p>(삽입 연산, 탐색 연산, 삭제 연산)</p>
<h3 id="연결리스트">연결리스트</h3>
<p> 물리적으로 흩어져 있는 자료들을 서로 연결하여 하나로 묶는 방법
노드와 포인터로 구현한다.</p>
<p>노드 : 메모리의 어떤 위치에나 있을 수 있으며 다른 노드로 가기 위해서는 현재 노드가 가지고 있는 포인터를 이용하며 데이터 필드와 링크 필드로 구성되어 있다.</p>
<p>데이터 필드 : 저장할 데이터를 가진다.</p>
<p>링크 필드 : 다른 노드를 가리키는 포인터가 저장된다.</p>
<h4 id="연결리스트의-장단점">연결리스트의 장단점</h4>
<p>장점 : 크기가 제한되지 않고, 중간에서 쉽게 삽입하거나 삭제할 수 있는 유연한 리스트 구현이 가능하다.
데이터를 저장할 공간이 필요할 때마다 동적으로 공간을 만들어서 쉽게 추가 가능하다.
단점 : 구현이 복잡하며 임의의 항목(i번째 항목)을 추출하려고 할 때 배열을 사용하는 방법보다 시간이 많이 걸린다.
데이터와 포인터를 저장해야 하므로 메모리 공간을 많이 사용한다.</p>
<h4 id="연결리스트의-종류">연결리스트의 종류</h4>
<p>단순 연결 리스트 : 하나의 방향으로만 연결되어 있는 연결 리스트이다. 체인(chain)이라고도 하며 마지막 노드의 링크는 NULL값을 가진다.
원현 연결 리스트 : 단순 연결 리스트와 동일하며 단, 마지막 노드의 링크가 첫 번째 노드를 가리킨다.
이중 연결 리스트 : 각 노드마다 2개의 링크가 존재하며 하나의 링크는 앞에 있는 노드를 다른 하나의 링크는 뒤에 있는 노드를 가리킨다.</p>
<h4 id="포인터로-연결-리스트-만들기">포인터로 연결 리스트 만들기</h4>
<p><a href="https://github.com/SemiKimm/Doit_algorithm/commit/1351ffb5a08e799da65ea0144d79cb006ed5ce47">LinkedList.java</a></p>
<ul>
<li><p>노드 생성</p>
<pre><code class="language-java">  class Node&lt;E&gt; {
      private E data;
      private Node&lt;E&gt; next;

      // 노드 생성자
      Node(E data, Node&lt;E&gt; next) {
          this.data = data;
          this.next = next;
      }
  }

  private Node&lt;E&gt; head; // 머리 노드
  private Node&lt;E&gt; crnt; // 선택 노드

  // LinkedList&lt;E&gt;의 생성자
  public LinkedList() {
      head = crnt = null;
  }</code></pre>
</li>
<li><p>삽입
<em>꼬리노드에 노드를 삽입하는 addLast메서드 
리스트가 비어있는 경우 즉, head==null일 경우 addFirst메서드를 사용하여
노드를 삽입한다. 그렇지 않은 경우 ptr에 head를 삽입 후에 while문을 사용하여 리스트의 꼬리로 이동시킨 후 삽입할 노드를
생성하고 선택 노드로 설정한다.</em></p>
<pre><code class="language-java">  public void addFirst(E obj) {
      Node&lt;E&gt; ptr = head;
      head = crnt = new Node&lt;E&gt;(obj, ptr);
  }
     public void addLast(E obj) {
      if (head == null)
          addFirst(obj);
      else {
          Node&lt;E&gt; ptr = head;
          while (ptr != null)
              ptr = ptr.next;
          ptr.next = crnt = new Node&lt;E&gt;(obj, null);
      }
  }</code></pre>
</li>
<li><p>탐색
_      검색을 수행하는 search 메서드 
obj : 검색할 때 key가 되는 데이터를 가지는 object 
c : 첫 번째 매개변수와 연결</p>
<pre><code>리스트의 개별 노드 안에 있는 데이터를 비교하기 위한 comparator 매개 변수 comparator c 에 의해 obj와 선택한 노드의
데이터를 비교하여 그 결과가 0이면 검색 조건이 성립하는것으로 본다 _</code></pre><pre><code class="language-java">  public E search(E obj, Comparator&lt;? super E&gt; c) {
      Node&lt;E&gt; ptr = head; // 첫번째 노드부터 탐색

      while (ptr != null) {
          if (c.compare(obj, ptr.data) == 0) { // 검색 성공
              crnt = ptr;
              return ptr.data;
          }
          ptr = ptr.next; // 다음 노드 선택
      }
      return null; // ptr이 비어있다면 null이라면 검색 실패
  }
</code></pre>
</li>
</ul>
<pre><code>- 삭제
_선택한 노드를 삭제하는 remove()메서드
리스트가 비지 않은 상태에서 선택한 노드를 p라고 하고 p가 head이면 removeFirst()메서드를 사용하여 삭제한다.
그 외의 경우에는 ptr을 사용하여 ptr.next가 p가 될때까지 탐색하고 p가 나오지 않고 ptr이 null이 되면 return 을 사용하여 메서드를 끝낸다.(리스트 내에 p라는 노드 존재 안하는 경우이다)
ptr.next가 p가 되면 ptr이 p.next를 가리키도록하여 p를 어디에서도 참조 하지 않도록 하여 노드 p를 삭제한다._
```java
    public void remove(Node&lt;E&gt; p) {
        if(head!=null) {
            if(p==head)
                removeFirst();
            else {
                Node&lt;E&gt; ptr=head;

                while(ptr.next!=p) { 
                    ptr=ptr.next;
                    if(ptr==null) return; //p가 리스트에 없는 경우
                }
                ptr.next=p.next;
                crnt=ptr;
            }
        }
    }</code></pre><h4 id="runner-기법">Runner 기법</h4>
<p>연결리스트를 순회할 때 두 개의 포인터를 동시에 사용하는 기법이다. 이때 한 포인터가 다른 포인터보다 앞서도록 한다. 앞선 포인터가 따라오는 포인터보다 항상 지정된 개수만큼을 앞서도록 할 수도 있고, 아니면 따라오는 포인터를 여러 노드를 한 번에 뛰어넘도록 설정할 수도 있다.</p>
<p>다음 코드 참고
_ 꼬리노드를 삭제하는 removeLast() 메서드
리스트가 비어있지 않은 상태에서 만약 노드가 1개 뿐이라면 removeFirst()메서드를 사용하여 삭제하고
그렇지 않다면 꼬리노드를 탐색할 ptr과 ptr바로 앞의 노드를 가리킬 pre를 생성하고 꼬리노드를 찾으면
꼬리노드 앞의 노드인 pre의 다음 노드 pre.next가 null을 가리키도록 설정하여
pre를 꼬리 노드로 설정한다._</p>
<pre><code class="language-java">    public void removeLast() {
        if (head != null) {
            if (head.next == null)
                removeFirst();
            else {
                Node&lt;E&gt; ptr = head;
                Node&lt;E&gt; pre = head;

                while (ptr != null) {
                    pre = ptr;
                    ptr = ptr.next;
                }
                pre.next = null;
                crnt = pre;
            }
        }
    }</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Dependency Injection 의존성 주입]]></title>
            <link>https://velog.io/@semi_kimm/Dependency-Injection-%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%A3%BC%EC%9E%85</link>
            <guid>https://velog.io/@semi_kimm/Dependency-Injection-%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%A3%BC%EC%9E%85</guid>
            <pubDate>Mon, 28 Dec 2020 19:13:07 GMT</pubDate>
            <description><![CDATA[<h4 id="패스트캠퍼스-springboot_eatgo-레스토랑백엔드서비스-9강-강의노트">패스트캠퍼스 SpringBoot_eatgo 레스토랑백엔드서비스 9강 강의노트</h4>
<h3 id="의존성">의존성</h3>
<p>의존 관계 
: 둘 이상의 객체가 서로 협력하는 관계</p>
<blockquote>
</blockquote>
<ul>
<li>예시
A객체는 B객체에 의존한다 =
A는 B를 사용한다
즉, 기술적인 관점에서 B의 변화는 A에게 영향을 준다</li>
<li>적용 
restaurants Controller는 restaurants Repository를 사용한다 =
Controller는 Repository에 의존한다
restaurants Controller에서 Repository를 직접 생성(객체 생성의 책임 = controller)
이후 직접 멤버 변수에 할당(=Controller에 Repository 연결)</li>
</ul>
<p>객체 생성과 연결을 컨트롤러가 아닌 별도로 담당할 수 있는데 이것을 spring ioc container를 통해 가능하다.</p>
<p>객체간의 의존성을 낮추는 의존성 제어를 위해 Spring IoC 컨테이터가 사용된다.</p>
<p>&#39;의존성 주입&#39;이란 객체의 생성과 연결을 Spring에서 직접 처리 하는 것이며 사용할 객체를 다양하게 변경 가능한 장점이 있다.
이를 위해, Spring에서는 @Component와 @Autowired 을 지원한다.
<a href="https://velog.io/@wlsdud2194/what-is-di">의존성 주입(DI) 개념 참고</a></p>
<h3 id="component">@Component</h3>
<p><img src="https://images.velog.io/images/semi_kimm/post/1d86fc8a-83dd-4604-a4de-2bb7636cf1a6/image.png" alt="">
컨테이너 
: 작성한 코드를 spring에서 위임받아 독립적으로 처리하는 것
@Component
: 컨테이너 안에 하나의 bean으로 등록시키기 위해 사용하는 annotation이며 
@Component는 개발자가 직접 컨트롤할 수 있는 클래스(직접 만든)를 Bean으로 등록하고 싶은 경우 (선언된 Class를 Bean으로 등록) 에 사용한다.
bean
: 자주 사용하는 객체를 Singleton 객체로 생성해놓고 어디서든 불러서 쓸 수 있는 것을
Spring 에서 Bean 이라는 이름을 붙인 것.
클래스를 한번 만들어놓고 재사용하기 편하게 하기 위함.</p>
<h3 id="autowired">@Autowired</h3>
<p><img src="https://images.velog.io/images/semi_kimm/post/559f3c89-bf23-4e30-8702-62bcbf119e2c/image.png" alt="">
@Autowired
: Container에 있는 Spring Bean을 찾아 주입시켜주는 Annotation이며 IoC 컨테이너에 있는 Spring bean을 찾아 주입한다.</p>
<p><a href="https://devlog-wjdrbs96.tistory.com/165">많이한 참고</a></p>
<p>의존성 주입을 사용하는 이유</p>
<ol>
<li>재사용성을 높여준다.</li>
<li>테스트에 용이하다.</li>
<li>코드를 단순화 시켜준다.</li>
<li>사용하는 이유를 파악하기 수월하고 코드가 읽기 쉬워지는 점이 있다.</li>
<li>종속성이 감소하기 때문에 변경에 민감하지 않다.</li>
<li>결합도(coupling)는 낮추면서 유연성과 확장성은 향상 시킬 수 있다.</li>
<li>객체간의 의존관계를 설정할 수 있다.</li>
</ol>
]]></description>
        </item>
    </channel>
</rss>