<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>yund.log</title>
        <link>https://velog.io/</link>
        <description>거침없이 한 달음에!</description>
        <lastBuildDate>Sun, 01 Oct 2023 12:18:21 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>yund.log</title>
            <url>https://images.velog.io/images/yund_272/profile/8d5a4930-6b7f-4a35-9c12-b96f71c01426/메인_1.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. yund.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/yund_272" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[BOJ 15649] N과 M(1) 파이썬 풀이]]></title>
            <link>https://velog.io/@yund_272/BOJ-15649-N%EA%B3%BC-M1-%ED%8C%8C%EC%9D%B4%EC%8D%AC-%ED%92%80%EC%9D%B4</link>
            <guid>https://velog.io/@yund_272/BOJ-15649-N%EA%B3%BC-M1-%ED%8C%8C%EC%9D%B4%EC%8D%AC-%ED%92%80%EC%9D%B4</guid>
            <pubDate>Sun, 01 Oct 2023 12:18:21 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/yund_272/post/ed8f3d32-15fe-4892-b282-624efd5b7606/image.png" alt=""></p>
<h2 id="문제">문제</h2>
<p><img src="https://velog.velcdn.com/images/yund_272/post/f8746a4b-12a6-4f98-8751-3eef34cfa8e4/image.png" alt=""></p>
<p>​
​</p>
<h2 id="백트레킹">백트레킹</h2>
<blockquote>
</blockquote>
<h3 id="💡-백트레킹">💡 백트레킹</h3>
<p>해를 찾는 도중 해가 아니어서 막히면 되돌아가서 다시 해를 찾아가는 기법
(모든 경우의 수를 탐색하는 대신, 조건을 걸어 유망한 경우로 탐색하기)</p>
<blockquote>
<blockquote>
<p>불필요한 부분을 줄이고 최대한 올바른 쪽으로 간다!
  → <u><strong>특정한 조건을 만족하는 경우</strong></u>만 살펴보는 것</p>
</blockquote>
</blockquote>
<p>​</p>
<h3 id="깊이-우선-탐색dfs-과의-차이점">깊이 우선 탐색(DFS) 과의 차이점</h3>
<p>DFS는 가능한 모든 경로를 탐색하므로 경우의 수를 줄이지 못한다.
N! 가지의 경우의 수를 가진 문제는 DFS로 풀지 못함!</p>
<p>​</p>
<h3 id="문제풀이-팁">문제풀이 팁</h3>
<p>조건문 등을 걸어서 답이 절대 될 수 없는 상황을 정의 
   → 그러한 상황일 때 탐색 중지, 그 이전으로 돌아가 다른 경우 탐색하게끔</p>
<p>​
​</p>
<h2 id="코드">코드</h2>
<pre><code class="language-python">def backTracking () :
    if len(s) == m : # m개가 쌓이면 출력
        print(&#39; &#39;.join(map(str, s)))
        return

    for i in range(1, n+1) :
        if visited[i] :
            continue
        visited[i] = True
        s.append(i)
        backTracking()
        s.pop()
        visited[i] = False


n, m = map(int, input().split())
s = []
visited = [False] * (n+1)

backTracking()</code></pre>
<p>​
​</p>
<h2 id="풀이">풀이</h2>
<ol>
<li>문제 조건인 &#39;1부터 N까지 자연수 중에서 중복 없이 M개를 고른 수열&#39;을 위해 if문을 걸어주었다.</li>
<li>이후에는 첫번째에 쓰인 수를 피해 중복 없이 수열을 만들어야하므로 visited 배열을 사용했다. 이미 방문한 수일 경우 if문을 통해 continue되고, 방문하지 않은 경우 s배열에 해당 수(i)를 추가해준다.</li>
<li>다음 줄에서 재귀방식으로 다시 backTracking 함수를 부르고 위 내용을 반복한다.</li>
<li>첫번째 if문에서 s배열에 m개만큼 숫자가 쌓이면 이를 출력한 후 return하여 함수를 빠져나온다.</li>
<li>이를 반복한다.</li>
</ol>
<p>​</p>
<h3 id="상세-풀이">상세 풀이</h3>
<p>n = 4, m = 2일 경우 실행될 코드를 한 줄씩 풀어본다면 아래와 같다.</p>
<pre><code>n = 4
m = 2
visited = [False, False, False, False, False]

backtracking() -&gt;
    len(s) =&gt; 0. if문 넘어감
    i = 1
        visited =&gt; False이므로 if조건 해당 안됨
        visited[1] = True
        s.append(1)
        backTracking()
            len(s) =&gt; 1. if문 넘어감
            i = 1
                visited[1] =&gt; True이므로 if조건 해당됨
            i = 2
                visited =&gt; False이므로 if조건 해당 안됨
                visited[2] = True
                s.append(2)
                backTracking()
                    len(s) =&gt; 2. if문 들어감
                        print -&gt; “1 2”
                        return
                s.pop() =====&gt; 1
                visited[2] = False
            i = 3
                visited[3] =&gt; False이므로 if조건 해당 안됨
                visited[3] =&gt; True
                s.append(3) ========&gt; 1 3
                backTracking()
                    len(s) =&gt; 2. if문 들어감
                        print -&gt; “1 3”
                        return
                s.pop() ======&gt; 1
                visited[3] = False =====&gt; [False, true, false, false, false]
            i = 4
                visited[4] =&gt; False이므로 if조건 해당 안됨
                visited[4] =&gt; True
                s.append(4) ========&gt; 1 4
                backTracking()
                    len(s) =&gt; 2. if문 들어감
                        print -&gt; “1 4”
                        return
                s.pop() ======&gt; 1
                visited[4] = False =====&gt; [False, True, False, False, False]
        s.pop() ======&gt; []
        visited[1] = False ========&gt; [False, False, False, False, False]
    i = 2
        visited =&gt; False이므로 if조건 해당 안됨
        visited[2] = True
        s.append(2) ========&gt; [2]
        backTracking()
            len(s) =&gt; 1. if문 넘어감
            i = 1
                visited[1] =&gt; False이므로 if조건 해당안됨
                visited[1] = True
                s.append(1) ========&gt; [2, 1]
                backTracking()
                    len(s) =&gt; 2. if문 들어감
                        print -&gt; “2 1”
                        return
                s.pop() =====&gt; 2
                visited[1] = False
            i = 2
                visited =&gt; True이므로 if조건 해당 됨
            i = 3
                .
                .
                .</code></pre><p>​
​</p>
<h2 id="결과">결과</h2>
<p><img src="https://velog.velcdn.com/images/yund_272/post/9aa4e044-6ae8-42d9-a584-a622bfe59396/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[리액트 CORS 에러 해결 기록]]></title>
            <link>https://velog.io/@yund_272/%EB%A6%AC%EC%95%A1%ED%8A%B8-CORS-%EC%97%90%EB%9F%AC-%ED%95%B4%EA%B2%B0-%EA%B8%B0%EB%A1%9D</link>
            <guid>https://velog.io/@yund_272/%EB%A6%AC%EC%95%A1%ED%8A%B8-CORS-%EC%97%90%EB%9F%AC-%ED%95%B4%EA%B2%B0-%EA%B8%B0%EB%A1%9D</guid>
            <pubDate>Fri, 16 Sep 2022 02:50:03 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/yund_272/post/481707b3-c9bf-44f9-8132-7da174bcc2ca/image.png" alt="썸네일"></p>
<p>웹개발자라면 피해갈 수 없다는 CORS 에러.. 드디어 나도 맞닥뜨리고 말았다. 네이버 영화검색 API를 적용하며 에러를 발견했고, 삽질했던 기록을 남겨두려한다.
​
​
​</p>
<h2 id="cors">CORS</h2>
<p>CORS는 <strong>교차 출처 리소스 공유(Cross-Origin Resource Sharing, CORS)</strong>이며, 다른 출처의 자원에 접근할 수 있는지 권한을 검사하는 관문이기도 하다.</p>
<p><img src="https://velog.velcdn.com/images/yund_272/post/3f5f77da-65bd-4664-86b5-8b7849763605/image.png" alt="CORS 에러 캡처"></p>
<blockquote>
<p>~~ has been blocked by CORS policy: Response to preflight request doesn&#39;t pass access control check: No &#39;Access-Control-Allow-Origin&#39; header is present on the requested resource.</p>
</blockquote>
<p>^^.. 많이들 보셨을 에러메시지. 당신은 CORS 정책에 의해 차단되었으며 요청한 리소스에 ACAO 헤더가 없다. 돌아가시오~!</p>
<p>메시지를 보면 Access-Control-Allow-Origin 헤더를 넣으면 될 것 같은데, 나는 네이버의 API를 사용하려고 했으므로 직접 서버 코드를 수정할 수 없었다. 해결을 위해 구글링을 해보니 package.json에 프록시 관련 코드를 넣거나 라이브러리를 통해 프록시를 구축하는 등의 방법이 있었다.
​
​</p>
<h2 id="프록시-설정하기">프록시 설정하기</h2>
<h3 id="packagejson에-proxy-추가하기">package.json에 proxy 추가하기?</h3>
<p><img src="https://velog.velcdn.com/images/yund_272/post/d5ba81d3-d6fe-4704-8b6e-390a8f350f1e/image.png" alt="">
package.json에 API 주소를 써넣는 방법으로 우회할 수 있다고 했지만 에러는 해결되지 않았다. 게다가 이는 개발 단계에서만 유효하여 배포 후에는 먹히지 않는다고 하며, 하나의 주소만 쓸 수 있어 다양한 처리가 불가능한 단점이 있었다.
​</p>
<h3 id="라이브러리를-사용해-proxy-설정-완료하기">라이브러리를 사용해 proxy 설정 완료하기!</h3>
<p>그래서 라이브러리를 사용해 설정하기로 했다. 
<code>npm i http-proxy-middleware</code></p>
<p>설치 후 <code>./src</code> 폴더에 <code>setupProxy.js</code> 파일을 만든 후 아래 내용을 작성해주었다.</p>
<pre><code class="language-javascript">const { createProxyMiddleware } = require(&quot;http-proxy-middleware&quot;);

module.exports = function (app) {
  app.use(
    &quot;/naver_api&quot;,
    createProxyMiddleware({
       target: &quot;https://openapi.naver.com&quot;,
       pathRewrite: {
       //naver_api로 시작되는 url을 자동 인식 -&gt; 프록시 처리, /naver_api는 &quot;&quot;로 대체됨
         &quot;^/naver_api&quot;: &quot;&quot;,
       },
      changeOrigin: true,
    })
  );
};
</code></pre>
<p>이렇게 코드를 작성해두면 브라우저에서 naver_api로 시작되는 요청을 보낼 때 설정된 proxy에 의해 변환되어 타겟 url로 보내진다. 
<span style="color: gray"> 다만.. 문제가 생겼다. 이 코드는 대거 수정되게 된다..  </span>
​
​</p>
<h2 id="프록시-설정-완료-그런데">프록시 설정 완료! 그런데..</h2>
<h3 id="값-리턴이-왜-안돼">값 리턴이 왜 안돼?!</h3>
<p>모두 잘 설정했다고 생각했고, CORS 에러도 해결되었다. 그런데.. API서버에 요청한 값이 리턴되지 않았다. </p>
<p><img src="https://velog.velcdn.com/images/yund_272/post/0c49a01e-d9a1-4347-b354-c5902b8bb7d7/image.png" alt="">
개발자 도구 - 네트워크에서 나의 요청을 확인해봤다. 이상하다? 상태코드 200으로 잘 뜨는데 왜 로그를 찍어보면 데이터가 계속 undefined로 나오는 거지? 😱</p>
<p><img src="https://velog.velcdn.com/images/yund_272/post/a92c36f9-ec69-4bc9-ab8e-e5904c05d244/image.png" alt=""></p>
<blockquote>
<p>error_code: &quot;052&quot;, message: &quot;naver_api : partner does not exists. (등록된 파트너가 없습니다.)&quot;</p>
</blockquote>
<p>여기서 미리보기를 확인한 결과.. 에러를 자세히보니 메시지에 <strong>&quot;naver_api&quot;</strong>가 눈에 띄었다. 
부랴부랴 헤더로 돌아가 요청 URL을 확인하니, <code>http://localhost:3000/naver_api/v1/search/movie.json?query=~~</code>
구분하겠다고 썼던 naver_api가 rewrite처리 되지 않고 그대로 살아서 네이버 API의 요청 URL(<a href="https://openapi.naver.com/v1/search/movie.json">https://openapi.naver.com/v1/search/movie.json</a>) 과 다른 주소가 되어 버렸던 거였다.
​</p>
<h3 id="해결">해결</h3>
<p><code>setupProxy.js</code>를 아래처럼 수정하였다.</p>
<pre><code class="language-javascript">const { createProxyMiddleware } = require(&quot;http-proxy-middleware&quot;);

module.exports = function (app) {
  app.use(
    &quot;/v1&quot;,
    createProxyMiddleware({
       target: &quot;https://openapi.naver.com&quot;,
      changeOrigin: true,
    })
  );
};
</code></pre>
<p>수정 후 axios.get 부분의 url도 </p>
<pre><code class="language-javascript">const naverMovieSearch = axios.create({
  headers: {
    &quot;X-Naver-Client-Id&quot;: `${keys.NAVER_CLIENT_ID}`,
    &quot;X-Naver-Client-Secret&quot;: `${keys.NAVER_CLIENT_SECRET}`,
  },
});

export const movieSearch = (params) =&gt; {
  return naverMovieSearch.get(&quot;/v1/search/movie.json&quot;, { params });
};</code></pre>
<p>이렇게 변경해주어 성공적으로 값을 받아올 수 있었다.
<img src="https://velog.velcdn.com/images/yund_272/post/da500faf-d9c5-45cc-bbd5-d313c3bb444a/image.png" alt=""></p>
<p>​
​</p>
<h2 id="정리">정리</h2>
<blockquote>
</blockquote>
<ol>
<li>CORS 해결 위해 <code>http-proxy-middleware</code> 라이브러리 설치</li>
<li><code>setupProxy.js</code> 설정</li>
<li>/v1으로 시작하는 url 요청이 프록시를 통과하여 자원에 접근 성공</li>
</ol>
<p>라이브러리 설치 후 셋업 파일을 설정할 때 구글링으로 알아낸 코드를 그대로 복사 붙여넣기 해서 사용했었던 게 문제인 것 같다. 아무리 기본 틀이라고 해도 내 코드와 완벽히 맞아떨어지지 않을 수 있다는 걸 잊었다..😢 문서나 사용법을 숙지하는 것이 느닷없는 에러를 줄이는 길인 것 같다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[프밍 챌린지 후기]]></title>
            <link>https://velog.io/@yund_272/%ED%94%84%EB%B0%8D-%EC%B1%8C%EB%A6%B0%EC%A7%80-%ED%9B%84%EA%B8%B0</link>
            <guid>https://velog.io/@yund_272/%ED%94%84%EB%B0%8D-%EC%B1%8C%EB%A6%B0%EC%A7%80-%ED%9B%84%EA%B8%B0</guid>
            <pubDate>Mon, 16 May 2022 16:30:03 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/yund_272/post/6cd5f9e2-4f78-4e1b-9d93-9a08e3f41add/image.png" alt="https://github.com/pming-kr/pming-content"></p>
<p>22년 04월 26일 ~ 05월 11일 까지 진행한 프밍 챌린지!
기간동안 다양한 개발 컨텐츠를 소비하고 3일에 한 번씩 가장 의미있었던 컨텐츠를 깃헙에 기고하는 방식으로 진행되었다. 총 5회의 기고를 남기게 되는 셈!
5회 기고를 완료해 챌린지를 성공했고, 그 후기를 남겨보려한다.</p>
<p>​</p>
<p>이전에도 블로그, 유튜브 등을 돌아다니며 개발 컨텐츠들을 접하곤 했지만 읽고나서 스르르 까먹거나 다음에 읽어야지~하고 잊혀지는 것들이 종종 있었기에..😌 이 챌린지를 진행하면서 기록에 대한 중요성을 다시 깨닫게 되었다. 또, 기고할 때 컨텐츠의 TL;DR을 남기도록 되어있던 점 때문에 중요한 부분을 어떻게 정리할지, 어떻게 전달해야할지 고민하면서 읽었던 것 같다. 글쓰기 실력을 높이고 싶다는 생각도 덤으로 따라왔고.</p>
<p>좋은 컨텐츠들을 쉽게 접하게 되고, 읽고 나눌 기회가 주어진다는 점에서 굉장히 유익했던 챌린지였다. 다만 3일동안 괜찮은 컨텐츠를 발견하지 못 했을 때..는 내 마음가짐이 &#39;기고를 위한 글 찾기&#39;가 되어버려서 조금 조급해지기도 했다. 심금을 울리는 글을 찾아야한다는 어떤.. 아주 약간의 부담..?(ㅎㅎ)</p>
<p>​</p>
<p>아무튼, 챌린저분들이 올려주시는 정제된 컨텐츠들이 좋아서 글이 올라올 때마다 최대한 읽게 됐던 것 같다. 그 중에 마음에 박히는 글이 있어 TIL 기록도 시작하게 되었고, 더 다양한 분야의 컨텐츠를 소비해야겠다는 생각도 들었다 :)
이번 챌린지는 끝났지만 괜찮은 컨텐츠를 발견하면 프밍에도 계속 기고해보려한다!</p>
<p>#프밍챌린지_1기 후기 끝😋
<img src="https://velog.velcdn.com/images/yund_272/post/2286e22d-7ec9-4c98-9f0e-d3c47905fe99/image.png" alt=""></p>
<p><a href="https://github.com/pming-kr/pming-content">✅ 프밍 깃허브</a>
<a href="https://www.notion.so/3861c57635994eb2bf1c2d2cc3d6f1d9">✅ 프밍 챌린지 노션</a>
⬆️ 관심있는 분들은 링크들 확인하세요!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[warning] React <img> 태그 ESLint 오류]]></title>
            <link>https://velog.io/@yund_272/warning-React-img-%ED%83%9C%EA%B7%B8-ESLint-%EC%98%A4%EB%A5%98</link>
            <guid>https://velog.io/@yund_272/warning-React-img-%ED%83%9C%EA%B7%B8-ESLint-%EC%98%A4%EB%A5%98</guid>
            <pubDate>Tue, 29 Mar 2022 08:27:35 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/yund_272/post/ad46f7b1-3e0f-4297-9c7f-1eec1b954568/image.png" alt=""></p>
<blockquote>
<p>img elements must have an alt prop, either with meaningful text, or an empty string for decorative images. <em>eslintjsx-a11y/alt-text</em></p>
</blockquote>
<pre><code class="language-javascript">&lt;img src={location.state.thumbnail} /&gt;</code></pre>
<p>리액트에서 이렇게 작성했을때, 위와 같은 에러가 뜬다면</p>
<pre><code class="language-javascript">&lt;img src={location.state.thumbnail} alt={location.state.thumbnail} /&gt;</code></pre>
<p>이렇게, alt 부분을 추가해주면 된다.</p>
<p>alt속성은 이미지를 보여줄 수 없는 경우, 또는 스크린리더 사용 시 등에 보이는 대체텍스트를 정의해주는 것이다.
ESLint extention에서 웹 접근성을 충족하기 위해 강제 아닌 강제(?)를 시켜주어 알게 된 내용이라 정리한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[리액트 CKEditor5 적용기]]></title>
            <link>https://velog.io/@yund_272/%EB%A6%AC%EC%95%A1%ED%8A%B8-CKEditor5-%EC%A0%81%EC%9A%A9%EA%B8%B0-88vylruv</link>
            <guid>https://velog.io/@yund_272/%EB%A6%AC%EC%95%A1%ED%8A%B8-CKEditor5-%EC%A0%81%EC%9A%A9%EA%B8%B0-88vylruv</guid>
            <pubDate>Wed, 23 Feb 2022 17:05:58 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/yund_272/post/79eee823-8668-4755-b692-0b049c295422/image.png" alt=""></p>
<p>프로젝트에 WYSIWYG 에디터를 삽입하고자 찾아본 결과 CKEditor가 나온지 오래되기도 했고 많이들 사용한다는 말에 설치하게 되었다. 적용 결과 사용도 쉽고 UI도 깔끔해서, 추후에도 사용해보고자 그 과정을 정리한다.</p>
<h2 id="1-설치">1. 설치</h2>
<p>npm이나 yarn을 이용하여 라이브러리를 설치한다. ClassicEditor를 구현하므로 두번째 라이브러리도 함께 설치해준다.
<code>npm install --save @ckeditor/ckeditor5-react @ckeditor/ckeditor5-build-classic</code></p>
<p>​
​​
​</p>
<h2 id="2-코드-구현">2. 코드 구현</h2>
<h3 id="1-기본-구현">1) 기본 구현</h3>
<pre><code class="language-javascript">import React, { Component } from &#39;react&#39;;
import { CKEditor } from &#39;@ckeditor/ckeditor5-react&#39;;
import ClassicEditor from &#39;@ckeditor/ckeditor5-build-classic&#39;;

class App extends Component {
    render() {
        return (
            &lt;div className=&quot;App&quot;&gt;
                &lt;h2&gt;Using CKEditor 5 build in React&lt;/h2&gt;
                &lt;CKEditor
                    editor={ ClassicEditor }
                    data=&quot;&lt;p&gt;Hello from CKEditor 5!&lt;/p&gt;&quot;
                    onReady={ editor =&gt; {
                        // You can store the &quot;editor&quot; and use when it is needed.
                        console.log( &#39;Editor is ready to use!&#39;, editor );
                    } }
                    onChange={ ( event, editor ) =&gt; {
                        const data = editor.getData();
                        console.log( { event, editor, data } );
                    } }
                    onBlur={ ( event, editor ) =&gt; {
                        console.log( &#39;Blur.&#39;, editor );
                    } }
                    onFocus={ ( event, editor ) =&gt; {
                        console.log( &#39;Focus.&#39;, editor );
                    } }
                /&gt;
            &lt;/div&gt;
        );
    }
}

export default App;
</code></pre>
<p><text style="color: gray"> || 출처 : </text><a href="https://ckeditor.com/docs/ckeditor5/latest/builds/guides/integration/frameworks/react.html">ckeditor 공식 문서</a>
기본 구현은 이렇게 하고, 기타 필요한 옵션이나 기능이 있다면 직접 커스텀하면 된다! 아직은 크게 커스텀할 부분은 없었어서 내가 적용한 아~주 작은 부분만 정리했다. 추후 코드 수정 시 이 글도 수정하려한다.
​</p>
<h4 id="1-placeholder-적용">(1) placeholder 적용</h4>
<p>기본 구현을 마치면 화면 로드 시 data 부분에 써있는 내용이 보여진다. 이건 사용자가 직접 지우고 사용을 해야하기 때문에 placeholder가 필요했다. 
하단 내용처럼 수정해주었다.</p>
<pre><code class="language-javascript">&lt;CKEditor
    editor={ClassicEditor}
        config={{
            placeholder: &quot;내용을 입력하세요.&quot;,
        }}
    onReady={(editor) =&gt; {
      ~
         ~</code></pre>
<p>이 config에서 에디터 기본 기능을 넣고 뺄 수도 있지만 나는 기본 그대로 사용했다.</p>
<h4 id="2-에디터-css-적용">(2) 에디터 css 적용</h4>
<p>에디터 자체에 들어가는 스타일인 것 같다.</p>
<pre><code class="language-css">.ck.ck-editor__editable:not(.ck-editor__nested-editable) {
  min-height: 400px;
  margin-bottom: 20px;
}</code></pre>
<p>​
​
결과는 아래와 같다!<img src="https://images.velog.io/images/yund_272/post/48a131c1-8363-415b-a820-b2790d96d6d1/image.png" alt=""></p>
<h3 id="2-데이터-html-파싱">2) 데이터 HTML 파싱</h3>
<p><code>npm i react-html-parser</code>
CKEditor로 작성한 data는 html 형태(ex. &lt; p&gt;안녕하세요&lt;/ p&gt;)로 저장된다.
html parser를 다운 받아 저장된 데이터를 &#39;태그가 적용된&#39; 형태로 보여지게끔 했다. </p>
<pre><code class="language-javascript">import ReactHtmlParser from &quot;react-html-parser&quot;;

~

//viewContent는 저장된 글 내용을 보여주는 state이며,
//별도의 버튼에 onClick 이벤트로 글 내용을 state에 저장하게 했다.
{viewContent.map((ele) =&gt; (
      &lt;div className=&quot;temp_postTest&quot;&gt;
         &lt;h3&gt;{ele.title}&lt;/h3&gt;
      &lt;div&gt;{ReactHtmlParser(ele.content)}&lt;/div&gt;
   &lt;/div&gt;
))}</code></pre>
<p><img src="https://images.velog.io/images/yund_272/post/b4085a9f-e985-4a0f-af2a-46b58ace6d19/image.png" alt="">
글을 state에 저장하고 파싱한 후 보여준 모습이다. 
​
​​
​</p>
<h2 id="3-구현-중-맞닥뜨린-에러">3. 구현 중 맞닥뜨린 에러</h2>
<h3 id="1-react-html-parser---buffer-모듈을-찾지-못-함">1) react-html-parser -&gt; buffer 모듈을 찾지 못 함</h3>
<pre><code>Module not found: Error: Can&#39;t resolve &#39;buffer&#39; in &#39;/Users/~~~/node_modules/readable-stream/lib&#39;

BREAKING CHANGE: webpack &lt; 5 used to include polyfills for node.js core modules by default.
This is no longer the case. Verify if you need this module and configure a polyfill for it.

If you want to include a polyfill, you need to:
    - add a fallback &#39;resolve.fallback: { &quot;buffer&quot;: require.resolve(&quot;buffer/&quot;) }&#39;
    - install &#39;buffer&#39;
If you don&#39;t want to include a polyfill, you can use an empty module like this:
    resolve.fallback: { &quot;buffer&quot;: false }</code></pre><p>버퍼 모듈을 찾을 수 없고, 폴리필 어쩌구~ 하던 에러 내용. CKEditor를 사용하기 위해 검색하면서 웹팩을 직접 갈아야 한다는 글들을 봐서 그런지 괜히 어렵게 생각했었다.. 🤔
굳이 그럴 필요는 없는 것 같고, 일단 지금까지 구현한 내용을 보면 저 buffer라는 모듈을 다운받아주면 되었다!</p>
<p><code>npm install buffer</code></p>
<p>싹~ 해결됩니다.</p>
<p>​
​​
​</p>
<h2 id="마무리">마무리</h2>
<p>조금 헤맨 부분도 있지만 잘 커스텀하면 글쓰기 기능을 가진 웹페이지에서 유용하게 쓰일 것 같다. 굿!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[SASS, SCSS]]></title>
            <link>https://velog.io/@yund_272/SASS-SCSS</link>
            <guid>https://velog.io/@yund_272/SASS-SCSS</guid>
            <pubDate>Wed, 03 Nov 2021 06:24:35 GMT</pubDate>
            <description><![CDATA[<p>211007 TIL</p>
<h2 id="sasssyntactically-awesome-style-sheets">SASS(Syntactically Awesome Style Sheets)</h2>
<p><strong>#문법적으로 대박 멋진 스타일시트!</strong></p>
<p>웹페이지에 필수적이지만 사용하기에 어려움&amp;헷갈림이 많은 css를 유지보수 하기 쉽게 만들어준다. SASS는 CSS 전처리기로, CSS가 만들어지기 전에 변수, 조건문, 내장함수 등의 다양한 문법을 사용할 수 있다.</p>
<p>비슷한 전처리기로는 SCSS, Less, Stylus 등이 있다. 이들은 문법이나 작동 방식이 조금 다르지만 모두 비슷한 일을 한다.</p>
<h3 id="특징">특징</h3>
<ul>
<li>들여쓰기 문법을 사용한다 (+ 줄바꿈)
​
​
​<h2 id="scsssassy-css">SCSS(Sassy CSS)</h2>
</li>
</ul>
<p><strong>#멋진 CSSㅋ</strong></p>
<p>SCSS는 기존의 CSS 작성 방식과 유사하고, CSS에 좀 더 호환될 수 있도록 도입되었다. 대괄호와 세미콜론을 사용해서 좀 더 친숙하게 사용 가능하다. SASS가 2010년 5월에 버전3로 업그레이드 되며 갖춰진 새로운 문법 체계이며, 공식 문서도 SCSS로 작성되어있다.</p>
<h3 id="특징-1">특징</h3>
<ul>
<li><p>CSS를 구조화하여 사용할 수 있다</p>
</li>
<li><p>SASS보다 더 넓은 범용성, 호환성을 가진다</p>
</li>
<li><p>대괄호와 세미콜론을 사용한다.
​
​
​</p>
<h2 id="공통점">공통점</h2>
</li>
<li><p>두 문법 모두 스타일에 변수를 만들어서 적용할 수 있다.</p>
</li>
<li><p><code>@mixin</code>을 선언하여 사이트 전체에서 재사용 가능한 css 속성 그룹을 만들 수 있다.</p>
<p>  <img src="https://images.velog.io/images/yund_272/post/e5c6ea55-5308-49d2-8ed4-875b9def5dc0/image.png" alt="">출처 : <a href="https://sass-lang.com/guide">https://sass-lang.com/guide</a></p>
</li>
</ul>
<ul>
<li><code>@extend</code>로 css 속성 집합 공유가 가능하다.</li>
<li>컴파일 후 일반 css 문법으로 바꾸어 적용한다</li>
</ul>
<h2 id="">  ​</h2>
<p>   <a href="https://www.sassmeister.com/">SassMeister | The Sass Playground!</a>
** 설치 없이 컴파일을 테스트할 수 있는 사이트**</p>
<hr>
<p>리액트 템플릿을 찾아보다가 발견한 SCSS. 평생 헷갈리고 헤멜 줄 알았던 css도 뭔가 가능성이 보이는 것 같다 😄 특히 @mixin이 정말 자주 쓰일 것 같다! 지금 하는 프로젝트에도 적용해봐야겠다.</p>
<p>​
​
참고 링크
<a href="https://nykim.work/97">https://nykim.work/97</a>
<a href="https://sass-lang.com/">https://sass-lang.com/</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[AJAX, Axios]]></title>
            <link>https://velog.io/@yund_272/AJAX-Axios</link>
            <guid>https://velog.io/@yund_272/AJAX-Axios</guid>
            <pubDate>Wed, 29 Sep 2021 09:28:58 GMT</pubDate>
            <description><![CDATA[<h2 id="210929-til">210929 TIL</h2>
<p>만들고있는 프로젝트에서 라이브러리를 바꾸면서 서버 연결 방식이 axios에서 ajax로 바뀌었다. (라이브러리가 ajax 방식의 서버 업로드를 기본 지원함) </p>
<p>새로 사용하는 라이브러리는 FilePond(<a href="https://github.com/pqina/react-filepond)%EB%9D%BC%EB%8A%94">https://github.com/pqina/react-filepond)라는</a> 건데, css 디자인과 애니메이션을 모두 제공하여 예쁘고 사용성이 좋다. 각종 props도 잘 정의되어 있어서 그대로 쓰기 좋았다. 더 잘 사용하기 위해 업로드 방식을 알아봤다.</p>
<h3 id="filepond-라이브러리-업로드-방식">FilePond 라이브러리 업로드 방식</h3>
<ul>
<li>POST 방식으로 URL에 config와 form data를 담아서 보냈음<ul>
<li>헤더 타입 : multipart/form-data</li>
</ul>
</li>
<li>공식 Docs에서 제공하는 업로드 프로세스<ol>
<li>FilePond는 POST 요청을 사용하여 <code>my-file.jpg</code> 파일을 <code>multipart/form-data</code>로 업로드합니다.</li>
<li><strong>서버</strong>는 파일을 고유한 위치에 저장합니다.
<code>tmp/12345/my-file.jpg</code></li>
<li><strong>서버</strong>는 <code>text/plain</code> 응답에서 고유한 위치 ID<code>12345</code>를 반환합니다.</li>
<li><strong>FilePond</strong>는 숨겨진 입력 필드에 고유 ID <code>12345</code>를 저장 합니다.</li>
<li><strong>클라이언트</strong>는 고유 ID를 가진 숨겨진 입력 필드가 포함된 FilePond 상위 양식을 제출합니다.</li>
<li><strong>서버</strong>는 고유 ID를 사용하여 <code>tmp/12345/my-file.jpg</code>를 최종 위치 로 이동 하고 <code>tmp/12345</code> 폴더를 제거 합니다.</li>
</ol>
</li>
</ul>
<p>​
​
ajax와 Flask의 연결성도 괜찮은 것 같아 더 조사해보려고 한다. 이에따라 ajax, axios의 특징, 차이를 정리해보았다.</p>
<p>그전에.. 기존에 사용했던 코드도 같이 기록해둔다. axios도 모듈만 설치하면 아주 간단하게 사용할 수 있어서, 다른 프로젝트에서도 사용해보려고 한다.</p>
<h3 id="기존에-사용했던-코드---axios-방식">기존에 사용했던 코드 - axios 방식</h3>
<pre><code class="language-javascript">const [selectedFiles, setSelectedFiles] = useState(null);

//파일 전송 핸들러
  function submitFileHandler() {
    const formData = new FormData();

    formData.append(
      //&quot;uploadFile&quot;, //name값으로 string 메시지
      selectedFiles, //value값은 파일 정보
      selectedFiles.name // filename값은 파일명
    );

    const config = {
      headers: {
        &quot;content-type&quot;: &#39;multipart/form-data&#39;
      }
    };

    axios.post(UPLOAD_URL, formData, config)
     .then(res =&gt; {console.log(&#39;send ok&#39;, res)})
     .catch(err =&gt; {console.log(&#39;send fail&#39;, err)})
  }</code></pre>
<ul>
<li>이런식으로, POST 방식으로 URL에 config와 form data를 담아서 보냈었다.<ul>
<li>헤더 타입 : multipart/form-data</li>
</ul>
</li>
</ul>
<p>​
​</p>
<hr>
<h2 id="ajax-axios">AJAX, AXIOS</h2>
<blockquote>
<p><strong>AJAX</strong></p>
</blockquote>
<ul>
<li>Asynchronous Javascript And XML. 비동기식 자바스크립트 XML</li>
<li>자바스크립트를 사용해 웹서버와 클라이언트간 비동기적으로 XML 데이터를 교환하고 조작하기 위한 웹 기술</li>
<li>전체 페이지를 새로 고치지 않고도 페이지의 일부만을 위한 데이터를 로드하는 기법</li>
<li>백그라운드에서 데이터 주고받기 가능<ul>
<li>JSON</li>
<li>XML</li>
<li>HTML</li>
<li>텍스트 파일 등</li>
</ul>
</li>
<li>jQuery의 AJAX가 통상적임! (순수 ajax는 잘 안 씀)
​</li>
</ul>
<blockquote>
<p><strong>AXIOS</strong></p>
</blockquote>
<ul>
<li>브라우저, node.js를 위한 promise를 기반한 HTTP 통신 라이브러리</li>
<li>promise 객체로 return 해주기 때문에 response 데이터를 다루기 쉬움</li>
<li>es6 문법을 사용함</li>
<li>비동기 방식으로 HTTP 데이터 통신 가능</li>
<li>자동으로 JSON 데이터로 변형시켜줌</li>
<li>크로스브라우징에 특화되어 있어 브라우저 호환성이 뛰어남
<img src="https://images.velog.io/images/yund_272/post/bedf0bec-a713-4773-a029-cc796187b974/image.png" alt=""></li>
</ul>
<p>​
​</p>
<h3 id="ajax-axios-차이">AJAX, AXIOS 차이</h3>
<blockquote>
<p><strong>AJAX</strong></p>
</blockquote>
<ul>
<li>promise 기반이 아님</li>
<li>jQuery를 사용해야함(?)</li>
<li>error, success, complete 상태가 있어 실행 흐름 조절 가능</li>
</ul>
<blockquote>
<p><strong>AXIOS</strong></p>
</blockquote>
<ul>
<li>라이브러리 설치가 필요함</li>
<li>응답 시간 초과 설정 가능</li>
<li>요청 중단, 취소 가능</li>
<li>js의 내장 라이브러리인 fetch보다 더 많은 기능을 제공함</li>
</ul>
<p>​
둘 다 비동기식 통신에서 많이쓰이는 방법이므로, 자기에게 편한 것을 쓰면 될 것 같다!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Mac에서 Git token 설정하기]]></title>
            <link>https://velog.io/@yund_272/Mac%EC%97%90%EC%84%9C-Git-token-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@yund_272/Mac%EC%97%90%EC%84%9C-Git-token-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0</guid>
            <pubDate>Sun, 15 Aug 2021 16:59:06 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/yund_272/post/fea870c9-edeb-4eb7-80a8-e51d9d502397/github.png" alt=""></p>
<p>GitHub에서 기존 터미널 상에서 아이디와 비밀번호만으로 push를 사용할 수 있었던 방법을 보안상의 이유로 막아버렸다.</p>
<blockquote>
<p>Support for password authentication was removed on August 13, 2021. Please use a personal access token instead.</p>
</blockquote>
<p>한참 전부터 메일 등으로 안내했던 터라 Personal Access Token은 만들어놨었는데, 이를 내 맥북에 등록해두지 않아 위와 같은 에러 메시지가 출력되었다.</p>
<p>토큰을 만든 후 맥북에 적용하는 방법을 기록한다.</p>
<hr>
<p><img src="https://images.velog.io/images/yund_272/post/3b045676-1b40-4547-908b-f13e4c23de71/image.png" alt=""> 1. 키체인 접근 앱을 실행한다.
<img src="https://images.velog.io/images/yund_272/post/3450f1a1-83c0-4421-9e63-0af9da1e27fa/image.png" alt=""> 2. 검색창에 <code>github.com</code> 을 검색
<img src="https://images.velog.io/images/yund_272/post/b2352e4d-638f-4434-b5ea-2625f1f13c08/image.png" alt=""> 3. &#39;인터넷 암호&#39; 종류로 표시되는 github.com을 더블 클릭해 암호 보기 체크박스를 선택한다.</p>
<p>4, Mac 암호를 입력해 잠겨있던 박스를 열고 발급받은 토큰을 넣은 후 <code>변경 사항 저장</code> 버튼을 클릭한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Nomad Coder] 리액트 Hooks 강의 정리]]></title>
            <link>https://velog.io/@yund_272/Nomad-Coder-%EC%8B%A4%EC%A0%84%ED%98%95-%EB%A6%AC%EC%95%A1%ED%8A%B8-Hooks-%EA%B0%95%EC%9D%98-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@yund_272/Nomad-Coder-%EC%8B%A4%EC%A0%84%ED%98%95-%EB%A6%AC%EC%95%A1%ED%8A%B8-Hooks-%EA%B0%95%EC%9D%98-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Sat, 07 Aug 2021 17:03:53 GMT</pubDate>
            <description><![CDATA[<h2 id="hooks란">Hooks란?</h2>
<p>React 버전 16.8부터 React 요소로 새로 추가된 기능이다. 
기존 Class 기반의 코드가 아니어도 상태값 등을 사용해 <strong>함수형 방식의 프로그래밍</strong>을 할 수 있다.</p>
<p>또한, Hook을 통해 <strong>서로 비슷한 것을 하는 작은 함수의 묶음</strong>으로 컴포넌트를 나누는 방법을 사용할 수 있게 된다.  또한 이러한 로직의 추적을 쉽게 할 수 있도록 리듀서를 활용해 컴포넌트의 지역 상태 값을 관리하도록 할 수 있다.</p>
<p>(<a href="https://ko.reactjs.org/docs/hooks-intro.html">https://ko.reactjs.org/docs/hooks-intro.html</a> 참고)</p>
<p>​
​</p>
<h2 id="hooks의-장점">Hooks의 장점</h2>
<ul>
<li>코드가 예뻐진다! 😝 간결하며 직관적이다.</li>
<li>class를 사용하지 않고 함수형 프로그래밍이 가능하다.</li>
<li>보다 짧은 코드로 state를 사용할 수 있다.<ul>
<li>원래 state를 사용하려면 <code>this</code>같은 문장 규칙, <code>render</code>를 사용하는 방법을 생각했어야 했음<ul>
<li>state 선언</li>
<li>render() 내에 이벤트 작성할 경우 함수로 풀어내어 this.setState(state ⇒ { return (item: state.item + 1) }) 이런식으로 굉장히 길어짐</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>​
​</p>
<hr>
<h2 id="hooks의-종류">Hooks의 종류</h2>
<p><span style='color : gray'>이 글에선 Nomad Coder 강의로 배운 종류만 기록한다.</span></p>
<h3 id="usestate">useState</h3>
<blockquote>
<pre><code class="language-javascript">const [ item, setItem ] = useState();</code></pre>
</blockquote>
<pre><code>
- state값을 초기화 시켜준다.
- 초기에 initialState를 세팅할 수 있는 옵션을 제공한다.
→ ()에 값 지정 가능
- array를 return 해야 한다. 여기서는 item, setItem 요소를 가진다.
- **항상 2개의 value를 return**
  - value = item, 값
  - 만약 item만 사용한다면
```const item = useState(1)[0]```
- 사용 예시
  - 출력 :: `&lt;h1&gt; { item } &lt;/h1&gt;` 
  - 카운터 하나 올리기 :: `const plusItem = () ⇒ setItem(item + 1);`

​
​


### useEffect
&gt;```javascript
useEffect(function, [dependency]);</code></pre><ul>
<li><p>component가 mount 되자마자, 또는 화면이 새로고침되면 실행된다.</p>
<ul>
<li>컴포넌트가 렌더링 되면 특정 작업을 실행하도록 할 수 있다.</li>
<li>모든 변화를 감시하며, 화면이 새로고침되면(state의 갱신...) useEffect를 실행한다.</li>
</ul>
</li>
<li><p>두 개의 인자는 function으로써의 <strong>effect, dependency</strong>를 가진다.</p>
<ul>
<li>첫번째 인자는 useEffect로부터 function이 리턴되는 것이며, 이는 <code>componentWillUnmount</code>와 같다.</li>
<li>만약 dependency(deps)가 있다면 effect는 deps 리스트에 있는 값일 때만 값이 변하도록 활성화된다.</li>
<li><strong>두번째 인자에 어떠한 값이 존재하고, <span style='color:royalblue'>그 값의 state가 변하면 </span><span style='color: purple'>useEffect를 실행</span>시킨다.</strong></li>
</ul>
</li>
<li><p><strong>만약 dependency에 <span style='color:royalblue'>빈배열( [] )</span>이 들어있다면 <span style='color:purple'>component가 mount되었을 때 한 번만 실행</span>되고 더이상 실행되지 않을 것이다.</strong></p>
</li>
<li><p><code>componentWillUnmount</code>, <code>componentDidMount</code>, <code>componentWillUpdate</code>와 비슷함</p>
</li>
<li><p>dependency에 빈배열이 들어가 있는 상태에서 useEffect안에 <strong>function</strong>을 넣으면 <code>componentDidMount</code>, <code>componentDidUpdate</code>때 호출될 것임</p>
<ul>
<li>만약 deps가 존재한다면 function은 <code>componentDidMount</code>일 때만 호출됨<ul>
<li><code>componentWillUnmount</code> 로부터  function 리턴 받음. 이를 <strong>Clean Up Function</strong>이라 부른다!</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>​
​</p>
<h3 id="useref">useRef</h3>
<blockquote>
<pre><code class="language-javascript">const refContainer = useRef (initialValue);</code></pre>
</blockquote>
<pre><code>
- DOM 노드나 React 엘리먼트에 직접 접근하기 위해서 사용하기도 함
- 기존 함수형 컴포넌트 내부에 선언된 변수와 그것이 감싸는 데이터는 해당 컴포넌트가 호출될 때마다 **초기화됨**. (리렌더링)
  - 반면 useRef로 관리되는 변수는 값이 바뀌어도 리렌더링 되지 않음. 
  → &lt;span style=&#39;color:purple&#39;&gt;**리렌더링 없이 값을 변화시킬 수 있음!!!**&lt;/span&gt;
  - current가 가리키는 값은 React에 의해 기억되기에 직접 변경하기 전까지는 해당 컴포넌트가 호출될 때마다 동일함</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[라라랜드 픽셀아트]]></title>
            <link>https://velog.io/@yund_272/%EB%9D%BC%EB%9D%BC%EB%9E%9C%EB%93%9C-%ED%94%BD%EC%85%80%EC%95%84%ED%8A%B8</link>
            <guid>https://velog.io/@yund_272/%EB%9D%BC%EB%9D%BC%EB%9E%9C%EB%93%9C-%ED%94%BD%EC%85%80%EC%95%84%ED%8A%B8</guid>
            <pubDate>Fri, 30 Jul 2021 13:24:10 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/yund_272/post/7568fb89-bb0a-4948-a654-468db60ba71d/%E1%84%85%E1%85%A1%E1%84%85%E1%85%A1%E1%84%85%E1%85%A2%E1%86%AB%E1%84%83%E1%85%B3-%E1%84%8B%E1%85%AA%E1%86%AB%E1%84%89%E1%85%A5%E1%86%BC.png" alt=""></p>
<hr>
<p>라라랜드 픽셀아트 제작</p>
<p>Tool ::<span style = 'color:orange'>  Illustrator </span>
181003</p>
<p><img src="https://images.velog.io/images/yund_272/post/cf30f7a9-74c7-484e-94e2-52a39f24aeae/image.png" alt=""><img src="https://images.velog.io/images/yund_272/post/f6ca9951-f4e3-47da-8db6-f6d9bf597423/image.png" alt=""><img src="https://images.velog.io/images/yund_272/post/6a5e78bb-bd42-4004-9405-ffb840b59a96/image.png" alt=""><img src="https://images.velog.io/images/yund_272/post/5eab1467-1032-46ec-be60-6cb6fdedd8ad/image.png" alt=""><img src="https://images.velog.io/images/yund_272/post/1159231a-c6b6-4cdc-8194-4881a1131386/image.png" alt=""><img src="https://images.velog.io/images/yund_272/post/19d65f00-acd2-478e-8870-a860586c5aee/image.png" alt=""><img src="https://images.velog.io/images/yund_272/post/5c5b76d6-51ed-4f38-9739-5e0f0d1fa040/image.png" alt=""><img src="https://images.velog.io/images/yund_272/post/84873fb2-f069-44f2-b3de-19cbf6608414/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[강아지 일러스트]]></title>
            <link>https://velog.io/@yund_272/%EA%B0%95%EC%95%84%EC%A7%80-%EC%9D%BC%EB%9F%AC%EC%8A%A4%ED%8A%B8</link>
            <guid>https://velog.io/@yund_272/%EA%B0%95%EC%95%84%EC%A7%80-%EC%9D%BC%EB%9F%AC%EC%8A%A4%ED%8A%B8</guid>
            <pubDate>Fri, 30 Jul 2021 12:53:20 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/yund_272/post/fbd78c52-6b65-4f92-9a53-acf63c6c2089/%E1%84%8B%E1%85%AA%E1%86%AB%E1%84%89%E1%85%A5%E1%86%BC_1%E1%84%92%E1%85%AA%E1%84%8B%E1%85%B5%E1%84%90%E1%85%B3.png" alt=""></p>
<p> <img src="https://images.velog.io/images/yund_272/post/8187f542-472a-4c93-b15a-09f8162c5b49/%E1%84%8B%E1%85%AA%E1%86%AB%E1%84%89%E1%85%A5%E1%86%BC_2%E1%84%8B%E1%85%A9%E1%84%91%E1%85%B3%E1%84%92%E1%85%AA%E1%84%8B%E1%85%B5%E1%84%90%E1%85%B3.png" alt=""></p>
<p>  <img src="https://images.velog.io/images/yund_272/post/752f8af7-c9e3-4c5a-bb68-722a503045c7/%E1%84%8B%E1%85%AA%E1%86%AB%E1%84%89%E1%85%A5%E1%86%BC_3%E1%84%80%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB.png" alt=""></p>
<hr>
<p>친구네 강아지 도니 일러스트 배경화면.</p>
<p>원본 사진은 이것!</p>
<p><img src="https://images.velog.io/images/yund_272/post/d63bc4db-2914-4488-9529-1ca081449afc/%E1%84%8D%E1%85%A1%E1%86%BC%E1%84%80%E1%85%B1%E1%84%8B%E1%85%A7%E1%84%8B%E1%85%AE%E1%86%AB%20%E1%84%8B%E1%85%AF%E1%86%AB%E1%84%87%E1%85%A9%E1%86%AB.jpg" alt=""></p>
<p>Tool ::<span style = 'color:orange'>  Illustrator </span>
181003</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Warning] componentWillReceiveProps has been renamed, and is not recommended for use.]]></title>
            <link>https://velog.io/@yund_272/Warning-componentWillReceiveProps-has-been-renamed-and-is-not-recommended-for-use</link>
            <guid>https://velog.io/@yund_272/Warning-componentWillReceiveProps-has-been-renamed-and-is-not-recommended-for-use</guid>
            <pubDate>Thu, 29 Jul 2021 17:34:52 GMT</pubDate>
            <description><![CDATA[<p>React-Native 컴포넌트 중 &#39;react-native-action-button&#39; 플로팅 버튼(<a href="https://github.com/mastermoo/react-native-action-button)%EC%9D%84">https://github.com/mastermoo/react-native-action-button)을</a> 사용할 경우,</p>
<blockquote>
<p>Warning: componentWillReceiveProps has been renamed, and is not recommended for use. See <a href="https://reactjs.org/link/unsafe-component-lifecycles">https://reactjs.org/link/unsafe-component-lifecycles</a> for details.</p>
</blockquote>
<p>이러한 warning이 발생한다.
​</p>
<p>이는 ActionButton 코드 상에 사용되었던 <strong>componentWillReceiveProps</strong>이 <strong>UNSAFE_componentWillReceiveProps</strong>으로 이름이 변경되었으며, 17버전부터는 사용이 중단되고 새로운 이름만 작동하도록 변경되었기 때문이다. </p>
<p>​</p>
<p>​</p>
<hr>
<p><img src="https://images.velog.io/images/yund_272/post/6fc908e4-16e7-4a8e-b293-3d578d620106/image.png" alt="">
워닝이 났을 경우 터미널에 위 같은 안내문구가 나오는데, 안내된 대로 </p>
<pre><code>npx react-codemod rename-unsafe-lifecycles</code></pre><p>를 실행하면 해결될... 줄 알았으나, 나같은 경우 죄다 skipped만 됐다. </p>
<p>​
​</p>
<p>docs를 찾아본 결과,
<img src="https://images.velog.io/images/yund_272/post/1353355d-3f5e-48c3-a991-1794f8280221/image.png" alt=""></p>
<p>이제는 componentWillReceiveProps 자체를 사용해선 안된다고 하여,</p>
<p>문제가 된 컴포넌트를 제시된 방법으로 <strong>&#39;componentDidUpdate&#39;</strong>로 바꿔주니 워닝이 사라졌다.</p>
<p>​</p>
<p>​</p>
<p>​</p>
<p>내가 사용했던 react-native-action-button의 경우
<img src="https://images.velog.io/images/yund_272/post/20a4dcef-6301-448b-a7ae-93b3eb2bc706/image.png" alt=""></p>
<p>ActionButtons.js 에서 42번째 라인의 </p>
<p>componentWillReceiveProps   =&gt;  <strong>componentDidUpdate</strong> 로 변경하면 해결된다.</p>
<p>​</p>
<p>​</p>
<p>​</p>
<p>출처 : </p>
<p><a href="https://ko.reactjs.org/docs/react-component.html#updating">https://ko.reactjs.org/docs/react-component.html#updating</a></p>
<p><a href="https://github.com/mastermoo/react-native-action-button/issues/365#issuecomment-797476260">https://github.com/mastermoo/react-native-action-button/issues/365#issuecomment-797476260</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[.gitignore 설정 방법]]></title>
            <link>https://velog.io/@yund_272/.gitignore-%EC%84%A4%EC%A0%95-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@yund_272/.gitignore-%EC%84%A4%EC%A0%95-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Thu, 29 Jul 2021 17:29:50 GMT</pubDate>
            <description><![CDATA[<p>git이 해당 폴더, 확장자 등을 <strong>추적하지 않도록</strong> 미리 등록해두는 방법이다. 
git으로 관리하지 않아도 될 파일을 <strong>무시</strong>하게끔 해준다.</p>
<p>​</p>
<ol>
<li><p>프로젝트의 홈으로 진입</p>
</li>
<li><p>Mac의 경우 터미널에 <strong><code>ls -a</code></strong> 명령 입력</p>
<p> Windows의 경우 <strong><code>dir /a</code></strong>   명령 입력 시 모든 파일, 폴더 출력됨</p>
</li>
<li><p>여기서 .gitignore 파일을 찾아   *<em><code>vi .gitignore</code>  *</em></p>
</li>
<li><p>i를 눌러 편집모드로 변경, 하단에 필요한 내용 삽입 후 esc를 눌러 빠져나옴</p>
</li>
<li><p>확인 후 <strong><code>:wq!</code></strong> 해 저장</p>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[git에 올려선 안 될 파일까지 커밋했을 경우 해결방법 (history에 올라간 파일 삭제, hprof)]]></title>
            <link>https://velog.io/@yund_272/git%EC%97%90-%EC%98%AC%EB%A0%A4%EC%84%A0-%EC%95%88-%EB%90%A0-%ED%8C%8C%EC%9D%BC%EA%B9%8C%EC%A7%80-%EC%BB%A4%EB%B0%8B%ED%96%88%EC%9D%84-%EA%B2%BD%EC%9A%B0-%ED%95%B4%EA%B2%B0%EB%B0%A9%EB%B2%95-history%EC%97%90-%EC%98%AC%EB%9D%BC%EA%B0%84-%ED%8C%8C%EC%9D%BC-%EC%82%AD%EC%A0%9C-hprof</link>
            <guid>https://velog.io/@yund_272/git%EC%97%90-%EC%98%AC%EB%A0%A4%EC%84%A0-%EC%95%88-%EB%90%A0-%ED%8C%8C%EC%9D%BC%EA%B9%8C%EC%A7%80-%EC%BB%A4%EB%B0%8B%ED%96%88%EC%9D%84-%EA%B2%BD%EC%9A%B0-%ED%95%B4%EA%B2%B0%EB%B0%A9%EB%B2%95-history%EC%97%90-%EC%98%AC%EB%9D%BC%EA%B0%84-%ED%8C%8C%EC%9D%BC-%EC%82%AD%EC%A0%9C-hprof</guid>
            <pubDate>Thu, 29 Jul 2021 17:23:26 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>remote: error: GH001: Large files detected. You may want to try Git Large File Storage - <a href="https://git-lfs.github.com">https://git-lfs.github.com</a>.</p>
</blockquote>
<blockquote>
<p>remote: error: File android/java_pid<del>~</del>.hprof is 407.24 MB; this exceeds GitHub&#39;s file size limit of 100.00 MB</p>
</blockquote>
<p>​</p>
<p>리액트네이티브 개발을 하면서, 라이브러리 패키지 업데이트나 gradle 업그레이드를 했을 경우 가끔씩 hprof 파일이 생성됐다. 이는 자바 heap 덤프 파일이라고 하며 꽤 큰 용량을 가지고 있었다.</p>
<p>그래서 이것을 자칫 삭제하지 않고 커밋하면 push가 되지 않는 난감한 상황이 발생되었다.</p>
<p>그럴 때 쓸 수 있는 해결 방법이다.</p>
<p>​</p>
<p>​</p>
<pre><code>$ git filter-branch --tree-filter &#39;rm -rf android/java_pid~~~.hprof**&#39; HEAD</code></pre><p>위 명령으로 Git이 해당 파일을 추적해 커밋되지 않도록 설정할 수 있다.</p>
<p>​</p>
<p>​</p>
<hr>
<p>​</p>
<p>그러나 내 경우엔.. hprof 파일이 포함된 채로 커밋한 후 푸시가 안 돼 당황하다가 파일을 지워버리고.. 지운 기록까지 커밋해버렸다.. ^^;</p>
<p>​
​</p>
<p>그럴 땐 이 방법을 쓰면 된다.</p>
<p><strong>Git 기록에서 파일을 영구적으로 삭제하는 방법</strong>이다.</p>
<pre><code>$ git filter-branch -f --index-filter &#39;git rm --cached --ignore-unmatch android/java_pid~~~.hprof&#39; --prune-empty -- --all</code></pre><p><img src="https://images.velog.io/images/yund_272/post/3a5b1793-68dd-4ae3-9f0a-e30362d9b2b7/image.png" alt="">실행하면 이렇게 Rewrite를 주루룩 한다.</p>
<p>​</p>
<pre><code>$ git push --force --all</code></pre><p>그다음 강제 푸시 해버리면 된다.</p>
<p>History를 확인해보면 골치였던 hprof 파일 기록이 싹 삭제되었을 것이다.</p>
<p>​</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Invariant Violation: Module AppRegistry is not a registered callable module (calling runApplication)]]></title>
            <link>https://velog.io/@yund_272/Invariant-Violation-Module-AppRegistry-is-not-a-registered-callable-module-calling-runApplication</link>
            <guid>https://velog.io/@yund_272/Invariant-Violation-Module-AppRegistry-is-not-a-registered-callable-module-calling-runApplication</guid>
            <pubDate>Thu, 29 Jul 2021 17:16:11 GMT</pubDate>
            <description><![CDATA[<h4 id="invariant-violation-module-appregistry-is-not-a-registered-callable-module-calling-runapplication--에러">Invariant Violation: Module AppRegistry is not a registered callable module (calling runApplication)  에러</h4>
<p>​</p>
<p>터미널에 아래 명령을 작성하면 된다.</p>
<pre><code>react-native start --reset-cache
react-native run-ios</code></pre><p>​</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Android error] couldn't find DSO to load: libjscexecutor.so]]></title>
            <link>https://velog.io/@yund_272/Android-error-couldnt-find-DSO-to-load-libjscexecutor.so</link>
            <guid>https://velog.io/@yund_272/Android-error-couldnt-find-DSO-to-load-libjscexecutor.so</guid>
            <pubDate>Thu, 29 Jul 2021 17:11:15 GMT</pubDate>
            <description><![CDATA[<p>에러 발생 당시 React-Native Version 
:: <a href="mailto:react-native@0.63.4">react-native@0.63.4</a> | MIT | deps: 27 | versions: 559</p>
<p>​</p>
<pre><code>npm install hermesvm
npm install jsc-android</code></pre><p>npm 또는 yarn으로 패키지를 설치한 후 하단 코드 존재 여부 확인 및 추가</p>
<p>​
​</p>
<blockquote>
<p>build.gradle (Project)</p>
</blockquote>
<pre><code class="language-java">allprojects {
    repositories {
        mavenLocal()
        maven {
            // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
            url(&quot;$rootDir/../node_modules/react-native/android&quot;)
        }
        maven {
            // Android JSC is installed from npm
            url(&quot;$rootDir/../node_modules/jsc-android/dist&quot;)
        }

        google()
        jcenter()
   }
}</code></pre>
<p>​
​</p>
<blockquote>
<p>build.gradle (app)</p>
</blockquote>
<pre><code class="language-java">project.ext.react = [
    entryFile: &quot;index.js&quot;, ///해당 라인 추가...
    enableHermes: false,  // clean and rebuild if changing
]

dependencies {
    if (enableHermes) {
        //def hermesPath = &quot;../../node_modules/hermes-engine/android/&quot;;
        def hermesPath = &quot;../../node_modules/hermesvm/android/&quot;; ///해당 라인 추가...
        debugImplementation files(hermesPath + &quot;hermes-debug.aar&quot;)
        releaseImplementation files(hermesPath + &quot;hermes-release.aar&quot;)
    } else {
        implementation jscFlavor
    }
}</code></pre>
<p>추가로 minSdkVersion도 문제일까 싶어 20이상으로 수정해주었다.</p>
<p>그리고 해결!</p>
<p>​</p>
<p>​</p>
<p>​</p>
<p>​</p>
<p>참고한 링크</p>
<p><a href="https://github.com/facebook/react-native/issues/25537">https://github.com/facebook/react-native/issues/25537</a></p>
<p>​</p>
]]></description>
        </item>
    </channel>
</rss>