<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>dongjae0324_.log</title>
        <link>https://velog.io/</link>
        <description>개발기록지</description>
        <lastBuildDate>Sun, 13 Nov 2022 16:29:42 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>dongjae0324_.log</title>
            <url>https://velog.velcdn.com/images/dongjae0324_/profile/a2caaf90-cf1d-461f-9f9d-fcaab73d6358/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. dongjae0324_.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/dongjae0324_" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[ReactNative] 
failed to build iOS project. We ran "xcodebuild" command but it exited with error code 65.]]></title>
            <link>https://velog.io/@dongjae0324_/ReactNative-failed-to-build-iOS-project.-We-ran-xcodebuild-command-but-it-exited-with-error-code-65</link>
            <guid>https://velog.io/@dongjae0324_/ReactNative-failed-to-build-iOS-project.-We-ran-xcodebuild-command-but-it-exited-with-error-code-65</guid>
            <pubDate>Sun, 13 Nov 2022 16:29:42 GMT</pubDate>
            <description><![CDATA[<p>Xcode와 MacOS를 업데이트 한 후, RN 앱을 ios 디바이스로 실행하고자 했더니 다음과 같은 에러가 떴다.</p>
<p>해당 내용에 대해 검색을 해보니, 꽤 흔한 에러인 것 같았다.
다만 같은 error code 65 더라도 발생 원인이 사람마다 달랐던 것 같다. 
그래서 pod를 재설치한다던지, DerivedData를 단순히 삭제하는 것에서 문제가 해결되지 않았다. </p>
<p>내가 맞이한 에러의 정확한 원인은 Signing 과 관련있었다.
(error: Signing for ~ requires a development team~)
<img src="https://velog.velcdn.com/images/dongjae0324_/post/cd29d502-abcb-4a86-888e-be9ebc18aeb3/image.png" alt=""></p>
<p>결국 문제는 해당 pod에 None으로 되어있는 Signing을 바꿔주기만 하면 해결되었다. </p>
<p><img src="https://velog.velcdn.com/images/dongjae0324_/post/34ac8a77-132e-4615-851d-dcac6e13f0bb/image.png" alt=""></p>
<p>해당 에러에 대한 스택오버플로우 글이 있으니 참고바란다. 
<a href="https://stackoverflow.com/questions/59062663/xcode-signing-for-grpc-c-grpccertificates-cpp-requires-a-development-team">https://stackoverflow.com/questions/59062663/xcode-signing-for-grpc-c-grpccertificates-cpp-requires-a-development-team</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[리액트 네이티브는 어떻게 작동하는가?]]></title>
            <link>https://velog.io/@dongjae0324_/%EB%A6%AC%EC%95%A1%ED%8A%B8-%EB%84%A4%EC%9D%B4%ED%8B%B0%EB%B8%8C%EB%8A%94-%EC%96%B4%EB%96%BB%EA%B2%8C-%EC%9E%91%EB%8F%99%ED%95%98%EB%8A%94%EA%B0%80</link>
            <guid>https://velog.io/@dongjae0324_/%EB%A6%AC%EC%95%A1%ED%8A%B8-%EB%84%A4%EC%9D%B4%ED%8B%B0%EB%B8%8C%EB%8A%94-%EC%96%B4%EB%96%BB%EA%B2%8C-%EC%9E%91%EB%8F%99%ED%95%98%EB%8A%94%EA%B0%80</guid>
            <pubDate>Wed, 17 Aug 2022 02:14:58 GMT</pubDate>
            <description><![CDATA[<p><a href="https://www.youtube.com/watch?v=1ojA5mLWts8&amp;t=837s">https://www.youtube.com/watch?v=1ojA5mLWts8&amp;t=837s</a></p>
<p>이에 대해 정리하기 위해선 우선 DOM 과 가상 DOM의 개념에 대해서 알아야 한다. </p>
<p>HTML 을 주문서라고 한다면 이를 실체화시키는 것은 웹 브라우저의 몫이다. (예를 들어, div, p, input tag 의 실질적 역할) </p>
<p>  <strong>HTML 주문서를 가지고 실제 작동하는 객체 형태로 만들어 놓은 것을 DOM</strong> 이라고 한다. 공식 문서에서는 DOM을 <strong>‘HTML이나 XML 문서를 실체로 나타낸 API 라고 정의</strong>한다.’ 그렇다면 가상 DOM은 무엇이며 react native 에서는 왜 이러한 방식을 차용하고 있을까. </p>
<h3 id="물리-dom-과-가상-dom">물리 DOM 과 가상 DOM</h3>
<p>  앱에서 버튼을 누르고 스크롤을 하는 등 사용자가 여러가지 작업을 하면 매번 화면은 달라진다. 변화가 생길 때 마다 실제 DOM 을 가지고 조작을 한다면 이는 매우 무거울 것이며 속도가 느리기 때문에 사용자 입장에서는 큰 불편일 것이다. </p>
<p>   그래서 react native 는 화면을 보여주기 전에 자바스크립트로 만들어진 가상 DOM을 만든다. 그 다음 실제 DOM 과 가상 DOM을 비교하고 전, 후로 발생하는 차이만큼만 화면에 반영하여 보여준다. <strong>(Diffing)</strong>(얄코의 라디오에서는 집을 DOM, 미니어처를 가상 DOM 으로 비유하며, 가구를 재배치하는 상황을 이야기한다.) </p>
<p>   특정한 시점이 되면 react native는 가상 DOM을 가지고 실제 DOM을 조작하는데, 이를 수행하는 패키지를 렌더러라고 한다 그리고 그 시점은 ‘렌더링 시점&#39; 이라고 부른다. react 와 react native는 모두 react 라는 패키지를 이용하는데 이 패키지가 가상 DOM을 만드는 역할을 한다. (ex) React.createElement) </p>
<p>_React : JSX → (with react package) → 가상 DOM → (with DOM renderer) → 실제 DOM _</p>
<p>_ React Native : JSX → (with react package) → 가상 DOM → (with native renderer) → 실제 DOM    (UI for android/ios) _</p>
<p>참고로 react native 의 렌더러인 (native renderer)의 모습은 확인할 수 없다. 그 이유는 렌더링 작업이 네이티브 모듈안에서 이루어지기 때문이다. (네이티브 모듈 쪽에서는 JavaScriptCore 라는 자바스크립트 엔진이 돌아간다). </p>
<p><strong>리액트네이티브가 렌더링 되면 두 가지 스레드가 생기는데 (UI thread, Javascript thread) 이 둘은 서로 메세지 큐 방식으로 서로 데이터를 주고받는다고 한다. 이런 방식의 프레임워크를 브리지 방식 프레임워크</strong>라고 말한다.</p>
<h3 id="정리"><strong>정리</strong></h3>
<p>정리하자면 리액트 네이티브는 자바스크립트 엔진을 이용하여 네이티브 모듈들과 소통한다. 이를 브릿지 방식이라고 한다 (자바스크립트와 네이티브의 연결). 결국 이 브릿지 방식은 네이티브 방식과 비교해 한 단계를 더 거치기 때문에 렌더링 속도에서 한계를 갖는다. 최근, 메타는 더 이상 브릿지 방식을 차용하지 않겠다고 발표하기도 했다. </p>
<p>모든 컴포넌트들을 재렌더링 하는 것은 손해이다. 사용자가 특정 행동을 했을때 변한 부분만 화면에 반영해주면 된다. 물리 dom이 수정해야 할 그림이라고 한다면, 가상 dom은 연습장이라고 보면 된다. 우선 연습장에 그려보고 수정되어야 할 부분만 반영하는 것이다. </p>
<About React Native Bridge> 

<p><a href="https://dev.to/wjimmycook/how-the-react-native-bridge-works-and-how-it-will-change-in-the-near-future-4ekc">https://dev.to/wjimmycook/how-the-react-native-bridge-works-and-how-it-will-change-in-the-near-future-4ekc</a></p>
<p><a href="https://velog.io/@koreanhole/React-Native%EC%97%90-%EB%8C%80%ED%95%B4%EC%84%9C">https://velog.io/@koreanhole/React-Native에-대해서</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React Native, Android] 에뮬레터 실행시 "debugger and device times have drifted" 경고]]></title>
            <link>https://velog.io/@dongjae0324_/React-Native-Android-%EC%97%90%EB%AE%AC%EB%A0%88%ED%84%B0-%EC%8B%A4%ED%96%89%EC%8B%9C-debugger-and-device-times-have-drifted-%EA%B2%BD%EA%B3%A0</link>
            <guid>https://velog.io/@dongjae0324_/React-Native-Android-%EC%97%90%EB%AE%AC%EB%A0%88%ED%84%B0-%EC%8B%A4%ED%96%89%EC%8B%9C-debugger-and-device-times-have-drifted-%EA%B2%BD%EA%B3%A0</guid>
            <pubDate>Thu, 09 Jun 2022 06:43:38 GMT</pubDate>
            <description><![CDATA[<p>에러는 아니지만 이러한 경고가 떴을시.
이는 디버깅하는 시간과 안드로이드 에뮬레이터 시간이 맞지 않아서 생기는 경고인 것 같다. </p>
<p>깃헙에 내용을 참고해보니,
<a href="https://github.com/facebook/react-native/issues/8720">https://github.com/facebook/react-native/issues/8720</a>
<img src="https://velog.velcdn.com/images/dongjae0324_/post/6f3ff413-3c3e-4d80-9f20-28215063445c/image.png" alt=""></p>
<p>에뮬레이터의 시간을 바꿔주어야 한다는데,
방법은 다음과 같다.</p>
<p>1) 에뮬레이터 안에서 Settings(설정) 창으로 이동 (에뮬레이터 설정 아님!)
2) Date &amp; Time 이동
3) 시간 자동설정된거 다 꺼주고, 자신의 현재 시간 맞추어 달력에서 조정</p>
<p>이렇게 하면 경고 해결!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Node.js/ Express] 간단한 CRUD 작업해보기]]></title>
            <link>https://velog.io/@dongjae0324_/Node.js-Express-%EA%B0%84%EB%8B%A8%ED%95%9C-CRUD-%EC%9E%91%EC%97%85%ED%95%B4%EB%B3%B4%EA%B8%B0</link>
            <guid>https://velog.io/@dongjae0324_/Node.js-Express-%EA%B0%84%EB%8B%A8%ED%95%9C-CRUD-%EC%9E%91%EC%97%85%ED%95%B4%EB%B3%B4%EA%B8%B0</guid>
            <pubDate>Fri, 27 May 2022 05:34:49 GMT</pubDate>
            <description><![CDATA[<p>오늘은 express를 통해서 간단한 crud 작업을 해볼 예정이다. 
crud란 create, read, update, delete 
서버 입장에서 post, get, put, delete 를 생각하면 된다. </p>
<p>우선 express 서버를 하나 만들어보자.</p>
<pre><code>const dotenv = require(&#39;dotenv&#39;)  //.env파일에 접근하기 위한 모듈
dotenv.config() //.env파일에 접근가능. 

const express = require(&#39;express&#39;) 
const morgan = require(&#39;morgan&#39;) //서버 요청을 쉽게 확인할 수 있는 모듈

const app = express() 
app.set(&#39;port&#39;, process.env.PORT || 3000) //port라는 전역변수? 생성. env파일에 PORT 정해져있지 않으면 default 3000
app.use(morgan(&#39;dev&#39;))                     
app.get(&#39;/&#39;, (req, res) =&gt; {res.send(&quot;메인화면입니다&quot;)}) 
app.listen(app.get(&#39;port&#39;), () =&gt; {console.log(`서버 ${app.get(&#39;port&#39;)}번 포트에서 연결됨) 
</code></pre><p>다음과 같이 간단한 서버를 만들어보았다. 
.env 파일에 PORT가 지정되어있지 않으므로 3000번 포트에 연결되었다. 
서버 연결에 성공하면 콘솔에 <strong>서버 3000번 포트에서 연결됨</strong> 이 로깅될 것이다. localhost:3000 에 접속하면   <strong>메인화면입니다</strong> 라는 문자열이 보일 것이다. </p>
<h3 id="get">Get</h3>
<p>get 요청은 위에서도 해보았지만 이는 문자열(html)을 보여주는 get요청에 불과했다. 이번에는 데이터를 가져오는 get요청을 진행해보자. db가 없으니 직접 만들어보자. </p>
<pre><code>const housedata = [
  { 
    id: 1, 
    owner: &quot;홍길동&quot;,
    builtyear: 2001, 
    description: &quot;빨간 벽돌로 지어진 집&quot; 
  }, 
  { 
      id: 2, 
    owner: &quot;철수&quot;,
    builtyear: 1998, 
    description: &quot;녹물 나오지만 시세는 비싼 집&quot;
  }
]    </code></pre><p>집과 관련된 데이터를 직접 만들어보았다. 
localhost:3000/houses라는 url로 접속했을때 클라이언트가 해당 데이터를 볼 수 있도록 해보자. 맨 위 서버 코드를 수정하자. </p>
<pre><code>...(중략)
const app = express()
app.set(&#39;port&#39;, process.env.PORT || 3000) 
app.use(morgan(&#39;dev&#39;)) 

app.get(&#39;/&#39;, (req, res) =&gt; {res.send(&quot;메인화면 입니다&quot;)}) 

app.get(&#39;/houses, (req, res) =&gt; {res.send(housedata)}) //위에서 만든 데이터 보냄. 

app.listen(app.get(&#39;port&#39;), () =&gt; {console.log(`서버 ${app.get(&#39;port&#39;)}번 포트에서 연결됨)
</code></pre><p>postman에서 url을 접속하면 다음과 같은 결과가 나온다. 
<img src="https://velog.velcdn.com/images/dongjae0324_/post/91b59a3e-557f-43a6-a6c1-287e06da0646/image.png" alt=""></p>
<p>그렇다면 이번엔 url뒤에 id를 붙였을 경우 해당 id 에 관련된 자료만 send해보자. </p>
<pre><code>app.get(&#39;/houses/:id&#39;, (req, res) =&gt; {
    const correctdata = housedata.find( house =&gt; house.id === parseInt(req.params.id)) 

    if (!correctdata) {
        res.status(404).send(&quot;해당 id의 데이터를 찾을 수 없습니다&quot;) 
    } else {
        res.status(200).send(correctdata)
    }
})</code></pre><p>id가 없을 경우 404 오류를 띄우며  데이터를 찾을 수 없다는 문자열을 보여주고, id가 있으면 해당 데이터를 추출하여 보여준다. parseInt를 쓴 이유는 req.params.id가 숫자가 아닌 문자이기 때문이다. </p>
<p>localhost:3000/houses/1 의 결과를 보자. 
<img src="https://velog.velcdn.com/images/dongjae0324_/post/7445f787-a99c-44f3-86ac-d2a6245df1d2/image.png" alt=""></p>
<p>id가 1인 집의 데이터가 성공적으로 보여진다. 
다음은 id가 3인 결과를 보자. 
<img src="https://velog.velcdn.com/images/dongjae0324_/post/337faa29-46e3-45a1-8200-825f1ada4415/image.png" alt=""></p>
<p>id와 관련된 데이터가 없으므로 오류 메시지가 뜬다. 
다음은 post 작업을 해보자. </p>
<h3 id="post">POST</h3>
<pre><code>post는 req.body에서 데이터를 가져오기 때문에 서버단에서 이를 해석해주어야한다. json 형식의 데이터를 해석해주는 express.json()을 사용 해야한다. 

app.use(morgan(&#39;dev&#39;)) 뒤에
app.use(express.json())을 추가하자. </code></pre><p>housedata에 req.body에서 받아올 데이터를 추가해보자. </p>
<pre><code>app.post(&#39;/houses&#39;, (req, res) =&gt; { 
    const newdata = {
        id: housedata.length+1,
        owner: req.body.owner,
        builtyear: req.body.builtyear, 
        description: req.body.description
    }

    if(!req.body.owner || !req.body.builtyear || !req.body.description){
        res.status(404).send(&quot;필수 데이터가 없습니다&quot;)
    }
        housedata.push(newdata)
        res.status(200).send(&quot;데이터가 저장되었습니다&quot;)

})</code></pre><p>body에서 보내는 데이터 중 owner, builtyear, description 등이 없으면 404, 필수 데이터가 누락되었다는 문자열을 보내고 모두 있다면 데이터를 저장한다. </p>
<p>영희의 집에 대한 데이터를 다음과 같이 json 형태의 파일로 보내면, 데이터가 저장되었다는 문자열을 볼 수 있다. </p>
<p><img src="https://velog.velcdn.com/images/dongjae0324_/post/389df0ae-b49a-474b-9466-bcfd30c52e47/image.png" alt=""></p>
<p>그리고 나서, get을 통해 해당 데이터를 열람해보자. 위에 
app.get(&#39;/houses&#39;, ... 중략) 을 통해 데이터를 받아왔었다. 동일한 작업을 하면</p>
<p><img src="https://velog.velcdn.com/images/dongjae0324_/post/e9ebc040-1554-4cf4-9d70-18c36444ec43/image.png" alt=""></p>
<p>다음과 같이 영희의 데이터가 housedata에 추가된 것을 볼 수 있다. 
다음은 put 작업을 해보자. </p>
<h3 id="put">PUT</h3>
<p>post가 완전한 데이터를 생성해주는 역할을 한다면 put은 데이터를 수정하는 역할을 한다.
데이터를 수정하는 코드를 다음과 같이 짜보았다. </p>
<pre><code>app.put(&#39;/houses/:id&#39;, (req, res)=&gt; {
    const correctdata = housedata.find( house =&gt; house.id === parseInt(req.params.id)) 

    if (!correctdata) {
        return res.status(404).send(&quot;해당 id의 데이터를 찾을 수 없습니다&quot;) 
    } 

    for (key in req.body) {
        correctdata[`${key}`] = req.body[`${key}`] 
    }

    housedata[parseInt(req.params.id)-1] = correctdata
    res.send(&quot;데이터를 성공적으로 수정하였습니다.&quot;)
})</code></pre><p>우선 post때랑 동일하게 housedata로 부터 해당 id의 데이터가 있는지 확인하고 없으면 404(에러)를 띄운다. 
만약 correctdata (우리가 수정하고자 하는 데이터)가 있으면 해당 데이터의 각 항목 값을 req.body에 실려온 수정사항으로 바꾼다. </p>
<p>req.body에 for 문을 쓴 이유는, req.body에 들어있는 항목만 바꿔주기 위해서이다.
해당  라우터를 통해 id: 1 인 홍길동의 데이터를 바꿔보자. </p>
<p>알고보니 &#39;홍길동&#39;의 집이 2001년이 아닌 1998년에 지어졌다고 하며, 빨간 벽돌이 아니라 회색 벽돌로 지어진 집이었다고 해보자. </p>
<p><img src="https://velog.velcdn.com/images/dongjae0324_/post/008d0c97-d160-4da5-8983-1ee0dc447222/image.png" alt="">
<img src="https://velog.velcdn.com/images/dongjae0324_/post/20e75a7d-a4c5-4e73-a3f4-a7366510379d/image.png" alt=""></p>
<p>성공적으로 데이터가 바뀌었음을 알 수 있다. 그렇다면 마지막으로 delete를 통해 데이터를 삭제해보자. </p>
<h3 id="delete">Delete</h3>
<p>delete는 비교적 간단하다. javascript의 splice 메서드를 통해 작업을 진행해보았다. </p>
<pre><code>app.delete(&quot;/houses/:id&quot;, (req, res)=&gt; {
    const correctdata = housedata.find( house =&gt; house.id === parseInt(req.params.id)) 

    if (!correctdata) {
        return res.status(404).send(&quot;해당 id의 데이터를 찾을 수 없습니다&quot;) 
    } 

    housedata.splice(parseInt(req.params.id)-1,1)
    res.send(&quot;데이터를 성공적으로 삭제했습니다&quot;)
})</code></pre><p>위와 마찬가지로 해당 id가 있는 데이터를 찾고 없으면 에러를 반환한다. 해당 id가 있는 데이터를 원본(housedata)에서 삭제해주었다. </p>
<p>delete : localhost3000/houses/1 을 실행하였더니 홍길동의 집에 대한 데이터를 사라지고 철수와 영희의 데이터만 남았다. </p>
<p><img src="https://velog.velcdn.com/images/dongjae0324_/post/6035dbb8-7af7-4135-b8e0-81bf0a3ae92c/image.png" alt=""></p>
<h3 id="결론">결론</h3>
<p>파이어베이스로 어플의 백엔드를 구현시켜놓아서 백엔드의 경험이 전무했는데 
노드와 express 를 사용하여 직접 데이터를 가공해보니 나름 흥미가 생기는 것 같다.
아직 초보지만 얼른 배워서 실무에 적용시켜보고 싶다.  달려보자~!!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[RN] Android emulator에서 아무것도 없는 하얀 화면이 뜰 때/ React Navigation 사용]]></title>
            <link>https://velog.io/@dongjae0324_/RN-Android-emulator%EC%97%90%EC%84%9C-%EC%95%84%EB%AC%B4%EA%B2%83%EB%8F%84-%EC%97%86%EB%8A%94-%ED%95%98%EC%96%80-%ED%99%94%EB%A9%B4%EC%9D%B4-%EB%9C%B0-%EB%95%8C-React-Navigation-%EC%82%AC%EC%9A%A9</link>
            <guid>https://velog.io/@dongjae0324_/RN-Android-emulator%EC%97%90%EC%84%9C-%EC%95%84%EB%AC%B4%EA%B2%83%EB%8F%84-%EC%97%86%EB%8A%94-%ED%95%98%EC%96%80-%ED%99%94%EB%A9%B4%EC%9D%B4-%EB%9C%B0-%EB%95%8C-React-Navigation-%EC%82%AC%EC%9A%A9</guid>
            <pubDate>Wed, 25 May 2022 10:57:11 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/dongjae0324_/post/0583deec-59bf-4b95-9ebc-510d9d2ea3d0/image.png" alt=""></p>
<p>다음과 같이 아무것도 없는 하얀 화면이 뜰 때가 있습니다. 
빨간 에러 화면도 아니라 디버깅을 어떻게 해야할지 막막하죠.</p>
<p>이때 켜둔 metro를 보시면 이유를 알 수 있습니다. 
metro에 혹시 다음과 같은 에러가 뜨시는지 확인해주세요.</p>
<pre><code>React Native:Module RCTEventEmitter is not a registered callable module..</code></pre><p>이는 react navigation을 사용하실때 react-native-gesture-handler를 설치하지 않아서 생기는 문제인데요, 이를 설치하고 메트로를 재실행해주시면 됩니다. </p>
<pre><code>npm i react-native-gesture-handler //제스쳐 핸들러 모듈 다운

react-native start --reset-cache //캐시를 지우고 메트로 실행

react-native run-android      //안드로이드 에뮬레이터 실행</code></pre><p>해당 에러에 대한 추가정보는 
<a href="https://stackoverflow.com/questions/57107601/react-nativemodule-rcteventemitter-is-not-a-registered-callable-module-calling">https://stackoverflow.com/questions/57107601/react-nativemodule-rcteventemitter-is-not-a-registered-callable-module-calling</a></p>
<p>이곳을 참고해주세요!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[자바스크립트] 동기와 비동기/ 콜백함수(Callback function) ]]></title>
            <link>https://velog.io/@dongjae0324_/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EB%8F%99%EA%B8%B0%EC%99%80-%EB%B9%84%EB%8F%99%EA%B8%B0-%EC%BD%9C%EB%B0%B1%ED%95%A8%EC%88%98Callback-function</link>
            <guid>https://velog.io/@dongjae0324_/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EB%8F%99%EA%B8%B0%EC%99%80-%EB%B9%84%EB%8F%99%EA%B8%B0-%EC%BD%9C%EB%B0%B1%ED%95%A8%EC%88%98Callback-function</guid>
            <pubDate>Thu, 19 May 2022 05:33:07 GMT</pubDate>
            <description><![CDATA[<h3 id="동기와-비동기">동기와 비동기?</h3>
<p>동기는 말 그대로 프로그램이 순차적으로 위에서부터 아래로 실행되는 것을 말한다. 
예를 들면 우리의 console.log. 백날 쳐보지 않아도 콘솔창의 값이 어떻게 나올지 알 수 있다. </p>
<pre><code>console.log(&quot;안녕&quot;)
console.log(&quot;나는&quot;)
console.log(&quot;프로그래머&quot;) 

//실행결과
안녕
나는
프로그래머</code></pre><p>반대로 비동기는 프로그램이 순차적으로 실행되지 않는, 언제 실행이 마무리될지 모르는 것을 말한다. 예를 들면 JS의 비동기적 함수에는 setTimeout이 있다. 또한, 서버에 특정한 요청을 하는 경우도 대게 비동기적으로 처리된다. </p>
<p>자바스크립트는 기본적으로 동기적이고 setTimeout이나 서버요청 같은 비동기적인 예외 상황이 있다고 보면 된다. </p>
<p>그래서 가끔,코드가 동기적으로 처리되겠거니 생각하고 서버에서 어떤 값을 요청받으면 엉뚱하게 그 값이 undefined가 나올 떄가 있다. 예를 들면 다음과 같은 경우이다. </p>
<pre><code>function getData() {
    var tableData;
    $.get(&#39;https: 서버 URL&#39;, function (response) {
        tableData = response;
    });
    return tableData;
}

console.log(getData()); // undefined</code></pre><p>_해당 코드는 콜백함수를 설명하는 어떤 블로그를 들어가도 볼 수 있을만큼 흔하다. _</p>
<p>순서를 보자면 이렇다. 우선 getData 함수가 호출되면 tableData라는 변수가 선언된다. 초기화가 안되어있으니 변수는 undefined이다. 이후 ajax의 메서드가 &#39;임의의 URL에 get 요청을 보낸다. 이 요청은 비동기적으로 실행된다.</p>
<p>[참고: <em>비동기적으로 실행된다는건 프로그래밍적으로 호출스택이 아닌 백그라운드에서 실행됨을 의미한다. 간략하게 말해서 one track -&gt; two track으로 일이 동시에 진행되는 것. 이는 자바스크립트의 이벤트 루프를 다루는 포스팅에서 자세히 설명함.</em> ] </p>
<p>서버 URL 뒤에는 요청값을 URL에서 받았을 때 실행되는 콜백함수가 있다. 콜백함수는 tableData 변수에 response 값을 넣어준다.  그리고 tableData가 반환된다.</p>
<p>모든 코드가 동기적으로 실행된다면 tableData에는 response가 들어갔을 것이고, console.log(getData())를 했을 때 undefined가 아닌 서버의 response 값이 나와야 한다. 하지만 값은 예상과 다르게 undefined이다.</p>
<p>그 이유는 ajax 메서드가 미처 URL에서 response를 가져오기도 전에 tableData가 반환되었기 때문이다. </p>
<p>그렇다면 이를 어떻게 해결해야할까? 서버에서 값을 가져왔는데 undefined이면 큰일나지 않는가? 여기서의 해법 중 하나가 콜백함수이다. </p>
<h3 id="콜백함수callback-function">콜백함수(Callback function)</h3>
<p>콜백함수의 본래 정의는 특정 시점(특정 이벤트가 발생했을 때)에 호출되는 함수이다. 다음 간단한 예제를 보자. </p>
<pre><code>const sampleFuncion = (func) =&gt; { 
    console.log(&quot;안녕 나는&quot;) 
    func()
} 

const printProgrammer = () =&gt; {
    console.log(&quot;프로그래머&quot;) 
} 

sampleFunction(printProgrammer) 

//실행결과 
안녕 나는 
프로그래머

//console.log(&quot;안녕 나는&quot;)이 호출되고 (이벤트가 발생하고) &#39;프로그래머&#39;를 출력하는 함수가 호출된다. </code></pre><p>이정도의 예제로 콜백함수가 무엇인지는 단번에 이해가 되었으리라 생각한다.
더 중요한건, 이 콜백함수를 통해서 어떻게 비동기처리를 해결할 수 있을까에 대한 고민이다. </p>
<p>콜백함수를 이용해서 위의 서버예제를 바꾸어보겠다. return값에 undefined가 아닌 response가 있도록! 두 코드를 모두 적었으니 비교해보고 차이점이 무엇인지 생각해보면 좋겠다. </p>
<pre><code>&lt;기존&gt; 
function getData() {
    var tableData;
    $.get(&#39;https: 서버 URL&#39;, function (response) {
        tableData = response;
    });
    return tableData;
}

console.log(getData()); // undefined

&lt;콜백함수 이용&gt; 

function getData() {
    var tableData;
    $.get(&#39;https: 서버 URL&#39;, function (response) {
        tableData = response;
        console.log(tableData) //response 
    });
}</code></pre><p>기존처럼 비동기처리 이후 return을 받지않고, 비동기처리의 콜백함수에서 작업을 수행하면 된다. </p>
<p>ajax 메서드 뒤에 이미 콜백함수가 있기 때문에 해당 예시가 적절해보이지 않아 다른 예시를 만들어보았다. 다른 예시는 setTimeout을 가지고 만든 예시이다. </p>
<p>setTimeout 메서드는 setTimeout(콜백함수, 특정시간) 이렇게 생겼으며, 특정시간 이후에 콜백함수를 호출한다. 시간은 밀리세컨드로, 3000 이라고 하면 3초이다. </p>
<pre><code>const arr = []

const getUserInfo = () =&gt; {
  setTimeout(()=&gt;{arr.push(&quot;유진&quot;)}, 2000)
}

getUserInfo() 
console.log(arr[0]) //결과값은 undefined</code></pre><p>setTimeout 함수에 대해 너무 깊게 생각하지 말고 우선 getUserInfo의 역할만 생각하자. getUserInfo는 호출되고 2초뒤에 빈 배열 arr에 &quot;유진&quot;을 추가한다. 이게 서버에서 &quot;유진&quot;이라는 값을 가져오는거랑 동일하다고 보면 된다. </p>
<p>getUserInfo를 호출하고 console.log를 출력했을때 결과값이 undefined가 나오는 것을 볼 수 있다. 이는 아까 서버 예시랑 마찬가지로 &quot;유진&quot;이 배열에 push되기 이전에 출력되었기 때문이다. </p>
<p>그렇다면 &quot;유진&quot;을 출력하기 위해선 어떻게 할까?
이를 콜백함수를 통해서 해결해보자. </p>
<pre><code>const arr = [] 

const print = (x) =&gt; {
  console.log(x)
}

const getUserInfoCallBack = (func) =&gt; {
  setTimeout(()=&gt; {arr.push(&quot;유진&quot;); func(arr[0])}, 2000)
}

getUserInfoCallBack(print) //결과값 &quot;유진&quot; 
</code></pre><p>print는 그저 매개변수를 출력하는 함수이다. 그리고 getUserInfoCallBack에는 func라는 함수인자가 있으며, 이는 setTimeout이 2초 뒤에 호출하는 함수 안에서 호출된다. </p>
<p>따라서 arr.push로 이미 &quot;유진&quot;이 push되고 이것이 이후 print 함수의 호출에 의해 출력되는 것이다. 따라서 결과값이 이전과 다르게 &quot;유진&quot;이 나온다. </p>
<h3 id="콜백지옥">콜백지옥</h3>
<p>그런데, <strong>이렇게 비동기처리를 할때 콜백함수를 이용하게 되면 콜백함수 안에 콜백함수를 집어 넣는 &#39;콜백지옥&#39;에 빠질 확률이 높다.</strong> </p>
<p>1초마다 초를 표시하는 타이머 예시를 통해 &#39;콜백지옥&#39;을 보여주겠다. </p>
<pre><code>setTimeout(()=&gt;{
console.log(&#39;1초&#39;)
setTimeout(()=&gt;{ 
    console.log(&#39;2초&#39;) 
    setTimeout(()=&gt;{
        console.log(&#39;3초&#39;)
        setTimeout(()=&gt;{
            console.log(&#39;4초&#39;) 
        },1000)
    }, 1000)
}, 1000) </code></pre><p>다음 코드를 실행하면
1초가 지난 다음 콘솔에 &#39;1초&#39; 
그 다음 1초가 지나면 또 콘솔에 &#39;2초&#39; 
... &#39;4초&#39;까지 출력된다. </p>
<h3 id="결론">결론</h3>
<p>요약하자면, 콜백함수는 간단히 말해 이후(later) 혹은 특정 이벤트 후 호출되는 함수일 뿐이며 이러한 함수를 중첩시켜서 비동기적인 코드를 동기적으로 실행되도록 만들 수 있다. </p>
<p>하지만 콜백함수를 여러번 중첩시킬 경우 &#39;콜백지옥&#39;과 같이 가독성이 심하게 떨어지는 코드가 만들어질 수 있다. </p>
<p>따라서 콜백함수를 가지고 비동기처리를 하는 것은 추천되지 않으며
프러미스/ async await 등의 방법이 있다.
프러미스에 관해서는 다음 포스팅에 자세히 다루도록 하겠다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[RN] Android 플레이스토어 출시후 앱 업데이트하기]]></title>
            <link>https://velog.io/@dongjae0324_/RN-Android-%ED%94%8C%EB%A0%88%EC%9D%B4%EC%8A%A4%ED%86%A0%EC%96%B4-%EC%B6%9C%EC%8B%9C%ED%9B%84-%EC%95%B1-%EC%97%85%EB%8D%B0%EC%9D%B4%ED%8A%B8%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@dongjae0324_/RN-Android-%ED%94%8C%EB%A0%88%EC%9D%B4%EC%8A%A4%ED%86%A0%EC%96%B4-%EC%B6%9C%EC%8B%9C%ED%9B%84-%EC%95%B1-%EC%97%85%EB%8D%B0%EC%9D%B4%ED%8A%B8%ED%95%98%EA%B8%B0</guid>
            <pubDate>Tue, 17 May 2022 07:15:22 GMT</pubDate>
            <description><![CDATA[<p>플레이스토어에 앱을 올린 후 업데이트를 진행해보자. 
경험상 업데이트는 2~3시간 안에 플레이스토어에 반영이 되었던 것 같다.</p>
<p>mac을 기준으로 설명을 진행하니 참고! </p>
<p>만약 build.gradle에서 defualtConfig를 수정하지 않았다면 1st step부터 실행.
수정하였다면 2nd step으로 바로 넘어가자! </p>
<h3 id="1st-step">1st step</h3>
<pre><code>프로젝트 폴더 &gt; android &gt; app &gt; build.gradle 로 이동
*build.gradle이 두개 존재함에 주의 

build.gradle에 보면 해당 부분이 있다.

__________________________________________

android {
    ndkVersion rootProject.ext.ndkVersion

    compileSdkVersion rootProject.ext.compileSdkVersion

    defaultConfig {
        ...
        versionCode 3
        versionName &quot;1.2&quot;
        ... 
    }
_________________________________________

versionCode는 이전보다 높은 숫자 (ex) 1이었다면 2로) 
versionName도 이전보다 높은 숫자 (ex) 1.1이었다면 1.2로. 회사마다 1.0.1 이렇게 3자리를 사용하는 경우도 있다. 내부의 규칙에 따름) 
로 수정. </code></pre><h3 id="2nd-step">2nd step</h3>
<pre><code>cd android 
// 안드로이트 폴더로 진입 

1) ./gradlew clean 
// cleaning gradle - 캐시와 불필요한 파일들의 삭제 

2) ./gradlew bundleRelease
// 안드로이드 앱 번들 생성 
</code></pre><p>이러면 AAB (Android App Bundle)이 만들어질 것이다. 에러가 나는 경우도 있음. 
성공적으로 build가 되었다면 해당 번들을 다음의 경로에서 찾아볼 수 있다. </p>
<p>프로젝트 폴더&gt; android &gt; app &gt; build &gt; outputs &gt; bundle &gt; release </p>
<p>해당 파일을 play console에 올려주면 끝! </p>
<p></p>
<p>*추가) 
relase 된 번들을 테스트해보고 싶다면 다음 코드를 실행시키면 된다. </p>
<pre><code>npx react-native run-android --variant=release</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[2] 리액트 네이티브에 리덕스 적용하기]]></title>
            <link>https://velog.io/@dongjae0324_/2-%EB%A6%AC%EC%95%A1%ED%8A%B8-%EB%84%A4%EC%9D%B4%ED%8B%B0%EB%B8%8C%EC%97%90-%EB%A6%AC%EB%8D%95%EC%8A%A4-%EC%A0%81%EC%9A%A9%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@dongjae0324_/2-%EB%A6%AC%EC%95%A1%ED%8A%B8-%EB%84%A4%EC%9D%B4%ED%8B%B0%EB%B8%8C%EC%97%90-%EB%A6%AC%EB%8D%95%EC%8A%A4-%EC%A0%81%EC%9A%A9%ED%95%98%EA%B8%B0</guid>
            <pubDate>Mon, 02 May 2022 05:12:55 GMT</pubDate>
            <description><![CDATA[<p>리덕스의 첫번째 포스팅에선 리덕스에 대한 개념 위주의 소개글을 적었었다. 
하지만 실질적으로 리액트 네이티브에 어떻게 적용이 되는지 알아야 사용할 수 있지 않은가. 그래서 현재 나의 경험을 토대로 리덕스를 어떻게 사용하고 있는지 적어보겠다. </p>
<p> 우선 간단하게 다시 개념을 복기하면.. 
 상태 정보(state)를 저장하는  공간인 store 
 상태 정보를 수정하는 (완전히 뒤바꾸는) 유일한 도구인 reducer 
 그리고 action (상태 수정 요청) 을 데리고 다니는 dispatch 가 있었다.
 개념은 헷갈릴 수 있지만 예시를 보면 금방 이해할 수 있을 것이다. </p>
<p> 우선 본 포스팅에서 나아가 더 많은 정보를 알고 싶으면 
 리덕스 공식 홈페이지  _<a href="https://lunit.gitbook.io/redux-in-korean/_%08">https://lunit.gitbook.io/redux-in-korean/_</a> 를  참고하시길!</p>
<pre><code>폴더구조

Store - actions - authActions.js

      - reducers - index.js
                   - authReducers.js   
      - types.js</code></pre><p>예시로 사용자 로그인, 회원가입 정보에 대한 상태를 관리해보겠다. actions를 정의하기 전 action들의 type을 작성하자. 이는 types.js에 작성한다. </p>
<pre><code>&lt;types.js&gt; 
export const SIGN-IN = &quot;sign-In&quot; 
export const SIGN-UP = &quot;sign-up&quot;</code></pre><p>action은 상태를 어떻게 해달라는 요청이라고 볼 수 있다. 모든 요청에는 어떤 요청인지에 대한 자기만의 이름이 부여되어있다. 그게 actions의 type 이다. types.js에는 redux 관리 창에 보이는 action type에 대한 string 값이 저장되어있다. </p>
<p>즉 예를 들어 SIGN-IN 은 actions의 type이 될 것이고 &#39;sign-in&quot; 은 SIGN-IN 이라는 action이 불릴때마다 redux 관리 창에 보여지는 이름이 된다. </p>
<p>이번에는 실제 actions들을 작성해보겠다. </p>
<pre><code>&lt;authActions.js&gt;
import {SIGN_IN, SIGN_UP} from &#39;../types&#39;

export function signIn(data) { 
   return {
         type: SIGN_IN,
         payload: {
            phone: data.phoneNumber,
            authenticationNumber:data.authenticationNumber
        }     
 }

 export function signUp(data) { 

   return {
         type: SIGN_UP,
         payload: {
            name: data.name, 
            email: data.email, 
            sex: data.sex
        }     
 }</code></pre><p>현재 로그인과 회원가입에 대한 action을 만들어보았다. 
signIn 이라는 action은 <em>type과 payload가 포함된 객체를 return</em> 한다. type은 이전에 말했듯이 요청의 이름이고, payload는 요청할때 보내주는 자료이다. 이 자료를 reducer가 받아서 store에 저장되어 있는 state 값을 변경해준다. </p>
<p>signIn(data) -&gt; {type / payload: {data.phone, data.authen..}} </p>
<p>이제 reducer를 작성해보자. reducers 폴더의 하위 파일인 authReducer.js 를 보자. reducer는 action의 요청을 받아 실질적으로 state를 수정하는 역할을 한다. 이전의 포스팅에서 state를 수정한다기보다는 통째로 바꾼다고 했는데, 아래의 reducer의 모습을 보면 그 이유를 알 수 있다. </p>
<pre><code>&lt;authReducers.js&gt;
import {SIGN_IN, SIGN_UP} from &#39;../types&#39;

export default function(state={}, action) {
    switch(action.type) {

        case SIGN_IN: 
            return {
                ...state,
                auth: {
                    phone: action.payload.phone || false,
                    authenticationNumber: action.payload.authenticationNumber || false 

                }
            }

        case SIGN_UP: 

            return {
                ...state,
                auth: {
                    phone: state.auth.phone,
                    authenticationNumber: state.auth.authenticationNumber, 
                    name: action.payload.name || false,
                    email: action.payload.email || false,
                    sex: action.payload.sex || false, 

                }
            }   
        defualt: 
            return state 
     }
}

</code></pre><p>reducer는 현재의 state와 action을 매개변수로 받는다. 초기의 state는 빈 object로 setting 되어있다. state={}. 이후, 코드를 보면 reducer는 switch문을 통해 어떤 action 인지 판별한다. </p>
<p>현재 사용자의 입장에서는 SIGN_IN 후 SIGN-UP 을 한다. 원래대로라면 SIGN-UP이 회원가입, SIGN-IN이 로그인이라 SIGN-UP 후 SIGN-IN의 순서가 맞지만 그 부분은 양해부탁한다..</p>
<p>각설하고, SIGN_UP case의 return 값을 보자. return 값은 object로 {... state, auth: { 새로운 내용 }} 의 형태를 띤다. 즉, 기존의 state 위에 새로운 내용을 덮어쓰기 하겠다는 의미이다. (통째로 바꾼다!)</p>
<p>SIGN_IN에서 받은 phone과 authenticationNumber는 SIGN_UP에서도 가져가야하는 (필요한) 정보이므로 </p>
<p>phone: state.auth.phone,
authenticationNumber: state.auth.authenticationNumber 
의 정보가 return값에 포함되어있는 것을 볼 수 있다.
만일 SIGN_UP return값에 phone과 authenticationNumber에 대한 정보가 없다면 SIGN_IN이 끝나고 SIGN_UP이 되었을때 store에는 phone, authenticationNumber가 사라지고 name, email, sex에 대한 정보만 남아있을 것이다. 이러면 state에 정보를 보관하는 의미가 없어진다. </p>
<p>action이 보낸 type이 존재하지 않으면 reducer는 원래의 state를 return하게 된다. </p>
<p>reducers 폴더 하위의 index.js에는 reducer들을 통합하고 이름을 붙여줄 수 있는 공간이 마련되어있다. </p>
<pre><code>&lt;index.js&gt;
import { combineReducers } from &#39;redux&#39;; 
import User from &#39;./auth_reducer&#39;;

const rootReducer = combineReducers ({
    User
});

export default rootReducer; </code></pre><p>현재 우리의 예제에서는 Authentication에 대한 reducer인 auth_reducer 만 만들었지만, 사실 reducer는 여러 종류일 수 있다.
예를 들면 사용자의 대여 반납 정보인 borrow_reducer, return_reducer도 만들 수 있는 것이다. 이렇게 reducer의 종류를 나눠놓으면 state를 관리하기 매우 용이해질 것이다. </p>
<p>index.js를 보면 auth_reducer를 User라는 이름으로(내가 지정한 이름!)import 했고 이를 combineReducers 라는 redux의 함수를 통해서 묶어주었다. </p>
<p>이전에 auth_reducer에서 auth라는 하위 카테고리에 정보를 지정했던 것이 기억나는가? 그렇다면 redux의 state가 어떻게 표현되는지 알아보자! </p>
<p>SIGN_IN과 SIGN_UP을 거치면 우리는 </p>
<pre><code>User - auth { phone ~, authentica... ... sex ~ }</code></pre><p>의 state를 갖게 된다. </p>
<p>지금까지 action과 reducer의 개념을 토대로 실질적인 생김새?에 대해서 살펴보았고, 어떤 원리로 동작하는지 알아보았다. 다시 쉽게 정리하면 우리는 어떤 요청에 따라 state를 관리하게 되는데, 그 요청의 이름이 action의 type이다. action은 type과 함께 가공할 재료들인 payload를 reducer에게 가져다준다. (실질적인 component에서 어떻게 이러한 과정이 일어나는지는 3편에서 작성하겠다.) 그러면 reducer는 action이 주는 값을 받아 switch문에서 type을 찾고 가공할 데이터를 가지고 미리 짜여진 양식에 따라 state를 덮어써버린다. rootreducer는 단지 여러개의 reducer를 묶어놓은 함수일 뿐이다. </p>
<p>state 값을 어떻게 가져오는지, 그리고 어떻게 수정하는지에 대해서는 다음 포스팅에서 적어보겠다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React Native, Android]  Module RCTEventEmitter is not a registered callable module 에러 해결]]></title>
            <link>https://velog.io/@dongjae0324_/React-Native-Android-Module-RCTEventEmitter-is-not-a-registered-callable-module-%EC%97%90%EB%9F%AC-%ED%95%B4%EA%B2%B0</link>
            <guid>https://velog.io/@dongjae0324_/React-Native-Android-Module-RCTEventEmitter-is-not-a-registered-callable-module-%EC%97%90%EB%9F%AC-%ED%95%B4%EA%B2%B0</guid>
            <pubDate>Wed, 30 Mar 2022 05:05:30 GMT</pubDate>
            <description><![CDATA[<p>[현상]
안드로이드 에뮬레이터에 앱 빌드를 하고 나서  흰색 blank screen 만 보임. 디버거 연결도 안되고 아무것도 할 수 없는 상태. 우연히 메트로에서 에러를 보았는데 
해당 에러의 내용이 제목과 같았다. </p>
<p>[해결방법] 
우선 메트로에서 react-native start --reset-cache를 하고 다시 메트로, 에뮬레이터 실행을 했는데 작동을 하지 않음. 그러다 우연히 </p>
<p><a href="https://stackoverflow.com/questions/57107601/react-nativemodule-rcteventemitter-is-not-a-registered-callable-module-calling">https://stackoverflow.com/questions/57107601/react-nativemodule-rcteventemitter-is-not-a-registered-callable-module-calling</a></p>
<p>다음 글을 발견했고, 
npm i react-navigation 
npm i react-natvie-gesture-handler 를 차례대로 실행 (모듈설치) </p>
<p>이후 
react-native start --reset-cache
react-native run-android 실행했더니 해결되었다. </p>
<p>진짜 안드로이드는 알다가도 모르겠다는..</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[1] Redux - 주요 개념 총정리]]></title>
            <link>https://velog.io/@dongjae0324_/1-Redux-%ED%8C%8C%ED%97%A4%EC%B9%98%EA%B8%B0</link>
            <guid>https://velog.io/@dongjae0324_/1-Redux-%ED%8C%8C%ED%97%A4%EC%B9%98%EA%B8%B0</guid>
            <pubDate>Wed, 23 Mar 2022 17:28:07 GMT</pubDate>
            <description><![CDATA[<p>Redux를 모르고 어플리케이션을 개발하려고 했던 스스로에게 많은 반성을...
한 component의 state를 props로 줄줄이 자식에게 먹여주었던  미련함을 이젠 떨칠 필요가 있었다.   어플리케이션의 기능이 하나 둘 늘어갈수록 기하급수적으로 늘어나는 수고를 이젠 감당할 수 없었다고..</p>
<p>리덕스가 무엇인지, 그리고 어떻게 사용하는지 정리해보겠다. 
그리고 후속편엔 리덕스를 리액트 네이티브에 어떻게 연결하는지 알아보겠다. 리액트 네이티브에 리덕스를 연결할 땐 제법 생소한 개념들이 쓰이기도 해서... </p>
<p>결국 최종목표는 이거다. 
&quot;state를 컴포넌트 내부말고 완전히 따로 저장해놓고 필요할 때 수정할거임.. &quot; </p>
<blockquote>
<p>리덕스의 전체 그림 (개요도) 
<img src="https://images.velog.io/images/dongjae0324_/post/e475a435-33bd-4c68-b382-2b4f888d0359/1598521393339redux.png" alt="">
from <a href="https://chanyeong.com/blog/post/21">https://chanyeong.com/blog/post/21</a></p>
</blockquote>
<p>*<em>0) store *</em>
Store에는 state가 보관되어있고, 여러가지 내장함수들이 포함되어있다. 현재 상태값을 불러오는 getState(), action을 운반하는 dispatch, 상태를 수정하는 reducer.. 등등이 담겨있다. 우선 모든 함수들을 구체적으로 알려고 노력하기 보다 전체적인 흐름을 보길 바란다. </p>
<p>*<em>1) state *</em>
state는 그냥 객체이다. 여기엔 온갖 잡다한 정보가 들어갈 수 있다. 사용자의 이메일이라든지, 성별이라든지, 누른 버튼이라든지.. 아무거나.
근데 이 state 를 update하는 행위는 매우  조심스럽게 이루어져야 한다. 그 이유는 javascript 의 immutability와 관계되어있다. 해당 내용에 대해서는 </p>
<p><a href="https://stackoverflow.com/questions/34385243/why-is-immutability-so-important-or-needed-in-javascript">https://stackoverflow.com/questions/34385243/why-is-immutability-so-important-or-needed-in-javascript</a></p>
<p>를 참고하면 더 자세히 알 수 있다. 이에 대한 별도의 블로그 글도 곧 올리겠다. 
아무튼 이 state는 되게 소중(?)하게 다루어져야 한다. 그래서 함부로 접근할 수 없고 reducer 라는 친구를 통해서만 수정 가능하다.</p>
<blockquote>
<p>{ information: {  }, sex: &#39;male&#39;,        color:&#39;yellow&#39;} </p>
</blockquote>
<p><strong>2) reducer</strong>
이름이 왜 reducer인지는 모르겠으나 state를 수정할 수 있는 권한을 가진 유일한 함수이다. immutability를 고려하면 수정보다는 완전히 새로운 state로 기존의 state를 대체한다는게 더 맞는 표현인 것 같다. 
reducer는 기존 state와 action을 파라미터 값으로 가져온다. 그리고 action의 종류에 따라서 반환할 새로운 state를 결정한다. 즉, reducer의 return 값은 기존 state를 대체할 새로운 state 라는 것! 아래는 reducer의 예시이다.</p>
<p>구조에 대해서는 이후에 살펴볼 예정이니 지금은 하는 역할만 알아두면 될 것 같다. action의 종류에 따라 새로운 state를 뱉는다! </p>
<pre><code>const reducer = (state = initialState, action) =&gt; { 

  switch (action.type) {
    case &quot;Order&quot; :      //action의 type(종류)이 &#39;Order&#39;일때! 
     const Copy1 = Object.assign({}, state, ~); 
     return Copy1;    //새로운 state로 Copy1 반환 
    case &quot;Pay&quot;: 
     return ~ 
    default: 
     return Object.assign({}, state);    //action에 해당되는게 없으면 기존 state반환
   }
} 
</code></pre><p>*<em>3) action *</em>
state를 수정하고 싶으면 reducer한테 이야기하라면서. 구체적으로 어떻게 수정하고 싶은데? 를 말해주는게 action이다. action도 그냥 객체인데, 이 안에는 type과 그 내용이 담겨있다. 이때 type 명시는 필수이다! 그래야 reducer가 명령을 알아먹고 state를 입맛대로 바꿔줄 수 있기 때문이다. </p>
<pre><code>{ 
  type: &quot;Order&quot;,
  food: {
            menu: &quot;Pizza&quot;, 
          size: &quot;Medium&quot;... 
        } 
} </code></pre><p>*<em>4) dispatch *</em>
action이 저런 객체라고 한다면, reducer는 도대체 action을 어떻게 알아먹고 작동을 할까? 덩그러니 객체만 작성한다고 해서 reducer가 반응할리가 없으니까.
이때 등장하는 개념이 dispatch이다. 그냥 action을 태우고 다니는 함수라고 생각하면 된다. dispatch가 action을 태우면 reducer가 action을 알아먹고 action type에 따른 새로운 state를 뱉는다. </p>
<p>dispatch가 하는 일은 reducer에게 action을 넘겨주는 일이라고 보면 된다. javascript 코드는 매우 간단하다..</p>
<pre><code>store.dispatch(action)  //이러면 reducer가 action 알아먹음. </code></pre><p>지금까지의 과정을 그림으로 간략하게 나타내면 다음과 같다. </p>
<blockquote>
</blockquote>
<p><img src="https://images.velog.io/images/dongjae0324_/post/ce84d843-a16d-445e-b960-aeabdbbcf522/img2.png" alt="">
from esri</p>
<p>그런데 이밖에도 getState() 와 subscribe 라는 함수가 있다. 
하지만 이 둘은 매우 직관적이므로 짧은 설명만 덧붙이고 자세한건 이후의 글에서 다루겠다. 
getState()는 말그대로 현재의 state를 받아오는 함수! </p>
<p>subscribe는 말그대로 구독인데, 이건 유투브 알림설정하고 비슷한 맥락이다. 새로운 영상이 올라오면 구독자에게 알림이 오는 것처럼, 바뀐 state가 있다면 해당 state를 쓴 component에게 rerender하라고 알림이 온다 (실제로는 rerender를 시켜주는 것)! </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[ReactNative  Android] keypad 로 인해 element 들이 밀려 올라올때]]></title>
            <link>https://velog.io/@dongjae0324_/%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-%EB%A6%AC%EC%95%A1%ED%8A%B8%EB%84%A4%EC%9D%B4%ED%8B%B0%EB%B8%8C-keypad-%EB%A1%9C-%EC%9D%B8%ED%95%B4-element-%EB%93%A4%EC%9D%B4-%EB%B0%80%EB%A0%A4-%EC%98%AC%EB%9D%BC%EC%98%AC%EB%95%8C</link>
            <guid>https://velog.io/@dongjae0324_/%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-%EB%A6%AC%EC%95%A1%ED%8A%B8%EB%84%A4%EC%9D%B4%ED%8B%B0%EB%B8%8C-keypad-%EB%A1%9C-%EC%9D%B8%ED%95%B4-element-%EB%93%A4%EC%9D%B4-%EB%B0%80%EB%A0%A4-%EC%98%AC%EB%9D%BC%EC%98%AC%EB%95%8C</guid>
            <pubDate>Tue, 22 Mar 2022 11:11:58 GMT</pubDate>
            <description><![CDATA[<p>input을 넣게 되면 작동할 때 keypad가 뜨기 마련이다. 
아이폰에선 이 keypad가 screen위로 올라오는데 ( keypad가 UI 가림) 
안드로이드에선 keypad screen을 분할하는 것처럼 뜨게 된다 ( keypad가 UI를 위로 밀어냄) </p>
<p>예시를 보여주자면, 
이러한 회원가입창이 있다고 했을 때, 아이디를 입력하려고 input을 누르는 순간, (인증하기) 버튼이 위로 올라온다는 것.
<img src="https://images.velog.io/images/dongjae0324_/post/e6e406a5-02c9-4b1c-b147-9cf13b7c1094/image.png" alt=""></p>
<p><img src="https://images.velog.io/images/dongjae0324_/post/971f33e1-9d9e-49d8-bd62-5e6c9871ef35/image.png" alt=""></p>
<p>이는 안드로이드에서 keypad가 올라오면 view를 resize 해주기 때문이라고 한다. </p>
<p>이걸 해결하는 방법은 
android &gt; app &gt; src &gt; main &gt; AndroidManifest.xml
에서 </p>
<pre><code>&lt;activity 
   android:name=&quot;.MainActivity&quot;
   ...
   android:windowSoftInputMode=&quot;adjustResize&quot;&gt;</code></pre><p>여기 보이는 &quot;adjustResize&quot; 를 &quot;adjustPan&quot; 으로 바꿔주면 된다. </p>
<pre><code>&lt;activity 
   android:name=&quot;.MainActivity&quot;
   ...
   android:windowSoftInputMode=&quot;adjustPan&quot;&gt;</code></pre><p>이러면 keyboard 위로 올라오는 UI 때문에 고생할 필요가 없다! 
ReactNative 프로젝트에선 adjustResize가 기본값이니 참고하시길.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[딥러닝 논문] SSD(Single Shot Multibox Detector)  _ Defualt Box]]></title>
            <link>https://velog.io/@dongjae0324_/%EB%94%A5%EB%9F%AC%EB%8B%9D-%EB%85%BC%EB%AC%B8-SSDSingle-Shot-Multibox-Detectior-Defualt-Box</link>
            <guid>https://velog.io/@dongjae0324_/%EB%94%A5%EB%9F%AC%EB%8B%9D-%EB%85%BC%EB%AC%B8-SSDSingle-Shot-Multibox-Detectior-Defualt-Box</guid>
            <pubDate>Thu, 10 Mar 2022 16:01:13 GMT</pubDate>
            <description><![CDATA[<h3 id="how-to-generate-default-boxes-in-ssd">How to generate default boxes in SSD</h3>
<ul>
<li>Anchor box의 개념에 대해선 다른 글에서 다루어보겠다. 원리적으로 보았을 때 Anchor box와 Default box의 개념은 거의 비슷하다 (SSD 저자도 이와 같이 설명). 본 글은 SSD 논문에 나와있는 Default box를 만드는 방법에 대해 알려주고 이를 임의의 사진에 적용해볼 수 있는 코드를 제공한다. </li>
</ul>
<p>&nbsp;&nbsp;&nbsp;Anchor box는 각각의 grid(pixel)마다 만들어 놓은 정해진 크기의 box들이다. 이러한 box들을 가지고 우리는 사물의 bounding box를 예측한다. object의 모양이 여러가지이기 때문에 Anchor box들의 모양도 마찬가지로 여러가지이다 (옆으로 넓은 것, 위로 높은 것.. 반듯하게 네모난 것). 아래의 그림을 보면 이해하기 쉬울 것이다. </p>
<p><img src="https://images.velog.io/images/dongjae0324_/post/0bd57674-5164-4630-b3cb-f5be775f38f1/image.png" alt=""></p>
<p>위의 그림에선 두 종류의 Anchor box가 보여진다. 
Anchor box 의 기초적인 개념은 다음 Andrew Ng의 강의에서 볼 수 있다.  <a href="https://www.youtube.com/watch?v=RTlwl2bv0Tg">https://www.youtube.com/watch?v=RTlwl2bv0Tg</a></p>
<h3 id="description-of-default-boxes-in-paper">Description of Default boxes in paper</h3>
<blockquote>
<p>&nbsp;&nbsp;<em>At each feature map cell, <strong>we predict the offsets relative to the default box shapes in the cell, as well as the per-class scores that indicate the presence of a class instance in each of those boxes. *<em>Specifically, for each box out of k at a given location, we compute c class scores and the 4 offsets relative to the original default box shape. This results in a total of (c + 4)k filters that are applied around each location in the feature map, yielding *</em>(c + 4)kmn outputs</strong> for a m × n feature map.</em> </p>
</blockquote>
<p>&nbsp;&nbsp;&nbsp; 하나의 default box당 c개의 클래스(Object classification)와 4개의 좌표 (Offset - cX, cY, W, H)에 대한 정보가 나온다. 이는 object의 분류와 bounding box의 예측이 한번에 이루어지고 있음을 말한다. (classification &amp; bounding box regression) </p>
<p>&nbsp;&nbsp;&nbsp;[c개 클래스의 예시 (강아지, 고양이, 사람, 배경)/ 좌표 예시(정중앙 x, 정중앙 y, 폭, 높이) ] - 한 개의 box 당 C+4의 정보</p>
<p>&nbsp;&nbsp;&nbsp;한 grid 당 k개의 default boxes가 있다고 한다면  m x n feature map에선 (c+4) x k x (mxn) 만큼의 정보가 나온다. 위의 (c+4)Kmn output이 나오는 이유. </p>
<blockquote>
<p><em>Previous works [10,11] have shown that using feature maps from the lower layers can improve semantic segmentation quality because the lower layers capture more fine details of the input objects.</em>... <em><strong>we use both the lower and upper feature maps for detection.</strong></em> </p>
</blockquote>
<p>&nbsp;&nbsp;&nbsp;convolutional layer들을 통과할수록 원본 이미지는 추상적으로 변한다. 따라서 convolutional layer들을 많이 통과하지 않은, 덜 추상적인 (feature maps from lower layer) 피쳐맵을 detection에 사용하는게 성능면에서 상대적으로 우수하다. SSD의 저자들은 lower layer 부터 higer layer들의 피쳐맵에 default box들을 모두 반영하기로 하였다. </p>
<blockquote>
<p>We design the tiling of default boxes so that specific feature maps learn to be
responsive to particular scales of the objects. Suppose we want to use m feature maps
for prediction. The scale of the default boxes for each feature map is computed as: <img src="https://images.velog.io/images/dongjae0324_/post/0f20ce53-f953-4afe-9438-beac1938f77b/image.png" alt=""> where smin is 0.2 and smax is 0.9, meaning the lowest layer has a scale of 0.2 and
the highest layer has a scale of 0.9, and all layers in between are regularly spaced.</p>
</blockquote>
<p>&nbsp;&nbsp;&nbsp; m개의 피쳐맵을 사용한다고 가정하자. 마지막 m번째 피쳐맵은 이미지가 가장 왜곡된(추상화된) 피쳐맵일 것이다. SSD의 저자들은 각 피쳐맵들에 적용할 defualt boxes들의 비율을 위의 수식으로 지정해놓았다. 비율은 피쳐맵에 대한 default box의 상대적인 크기라고 보면 된다. 그렇기에 피쳐맵의 사이즈가 가장 작은 m번째 피쳐맵의 default box는 가장 큰 비율을 가진다. (Smax = 0.9) 
<img src="https://images.velog.io/images/dongjae0324_/post/033727c3-637c-44ac-92e1-c8a35d42dbfe/image.png" alt="">
 위의 그림을 보면 수식에서 도출된 비율이 무엇을 의미하는지 알 수 있을 것이다. </p>
<p><img src="https://images.velog.io/images/dongjae0324_/post/5a48b44d-4106-4489-9b3b-4a4c35d818ac/image.png" alt="">
위의 그림에서 4x4 feature map (8x8 feature map보다 추상화된) 의 default box의 크기가 피쳐맵 대비 더 크다는 것을 볼 수 있는데, 이게 곧 S(8x8) &lt; S(4x4) 를 의미한다.  </p>
<p>&nbsp;&nbsp;&nbsp;<strong>아니 default boxes들의 모양이 한 종류가 아니라면서 이는 무슨 종류의 default box를 기준으로 둔 비율인가?</strong></p>
<p>이러한 의문점이 생기는 것이 지극히 정상이다. 위의 비율은 기준이 되는 기본 정사각형 모양의default box의 비율이다. 바로 다음에 다양한 종류의 default box의 size를 구하는 식이 등장한다. </p>
<blockquote>
<p><img src="https://images.velog.io/images/dongjae0324_/post/66116733-dd66-4cfe-87c0-dd77ad77582b/image.png" alt=""></p>
</blockquote>
<p>&nbsp;&nbsp;&nbsp;여기서 {1,2,3,1/2,1/3}은 서로다른 5개 종류의 default box를 말한다. 물론 이러한 5개 default box들이 각각의 grid 마다 그려져 있을 것이다. 각 종류의 width와 height를 구하는 식을 보면 1이 기본, 2와 3이 옆으로 뚱뚱한 default box, 그리고 1/2, 1/3이 위로 길쭉한 default box라는 것을 알 수 있다. </p>
<p>&nbsp;&nbsp;&nbsp;위의 내용을 추가하면 다음과 같다.
<img src="https://images.velog.io/images/dongjae0324_/post/56829360-ed22-41bc-86fa-847101db5ba7/image.png" alt=""></p>
<blockquote>
<p><img src="https://images.velog.io/images/dongjae0324_/post/9b57aace-1ce1-4845-9cb1-30a3ac53f988/image.png" alt=""></p>
</blockquote>
<p>그런데 SSD의 저자들은 여기서 그치지 않고 한 종류의 default box를 추가한다. 위의 내용을 모두 종합하면 다음과 같다. </p>
<p><img src="https://images.velog.io/images/dongjae0324_/post/9a3d8b04-6110-478e-ac3d-4899f6845b0c/image.png" alt=""></p>
<p>그 아래의 내용은 default box의 center에 대한 내용인데 이는 각 그리드( pixel ) 의 중심이라고 이해하면 된다. 마지막 저자의 말처럼, 이는 저자들의 방식일 뿐이지 누군가는 다른 비율과 크기의 default box를 사용할 수 있다. </p>
]]></description>
        </item>
    </channel>
</rss>