<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>chez_kwak.log</title>
        <link>https://velog.io/</link>
        <description>Hello, World!</description>
        <lastBuildDate>Tue, 21 May 2024 05:35:09 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>chez_kwak.log</title>
            <url>https://velog.velcdn.com/images/chez_kwak/profile/de503e8b-3cf0-41e9-bf94-86a7694cfd86/image.JPG</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. chez_kwak.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/chez_kwak" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[React-Native] Axios Request 모듈화를 통한 서버 통신 구현]]></title>
            <link>https://velog.io/@chez_kwak/React-Native-Axios-Request-%EB%AA%A8%EB%93%88%ED%99%94%EB%A5%BC-%ED%86%B5%ED%95%9C-%EC%84%9C%EB%B2%84-%ED%86%B5%EC%8B%A0-%EA%B5%AC%ED%98%84</link>
            <guid>https://velog.io/@chez_kwak/React-Native-Axios-Request-%EB%AA%A8%EB%93%88%ED%99%94%EB%A5%BC-%ED%86%B5%ED%95%9C-%EC%84%9C%EB%B2%84-%ED%86%B5%EC%8B%A0-%EA%B5%AC%ED%98%84</guid>
            <pubDate>Tue, 21 May 2024 05:35:09 GMT</pubDate>
            <description><![CDATA[<p>React Native에서는 서버와 통신하기 위해 <a href="https://axios-http.com/kr/docs/intro">Axios</a> 라이브러리를 사용한다.
토큰 저장 방식은 react-native-keychain을 사용했다.</p>
<blockquote>
<p><a href="https://velog.io/@chez_kwak/React-Native-react-native-keychain%EC%9D%84-%ED%99%9C%EC%9A%A9%ED%95%9C-storage-%EA%B4%80%EB%A6%AC">react-native-keychain을 활용한 storage 관리</a></p>
</blockquote>
<h2 id="axios-instance-생성하기">Axios Instance 생성하기</h2>
<p>API_URL은 env에 저장해두고 꺼내온다.</p>
<pre><code class="language-typescript">const instance = axios.create({
    baseURL: API_URL,
    withCredentials: true,
    timeout: 2000,
});</code></pre>
<blockquote>
<p>사용자 지정 config를 넣어 Axios Instance를 생성할 수 있다.</p>
</blockquote>
<h2 id="axios-interceptors-사용하기">Axios Interceptors 사용하기</h2>
<ul>
<li><p>default header 처리</p>
<pre><code class="language-typescript">instance.defaults.headers[&#39;Set-Cookie&#39;] = `refresh_token=${refreshToken}`;</code></pre>
<blockquote>
<p>refreshToken을 header에 입력한다.</p>
</blockquote>
</li>
<li><p>request 인터셉터 처리</p>
<pre><code class="language-typescript">instance.interceptors.request.use(
  async config =&gt; {
    config.headers[&#39;Content-Type&#39;] = &#39;application/json&#39;;
    config.headers[&#39;Authorization&#39;] = `Bearer ${accessToken}`;
    return config;
  },
  (err: unknown) =&gt; {
    Promise.reject(err);
  },
);</code></pre>
<blockquote>
<p>request 요청을 보낼 때, 기본으로 넣을 accessToken을 설정한다.
header를 Axios 인스턴스 생성 시점에 입력할 수도 있지만, 나는 interceptor 단계에서 처리해줬다.</p>
</blockquote>
</li>
</ul>
<ul>
<li>response 인터셉터 처리<pre><code class="language-typescript">instance.interceptors.response.use(
  async response =&gt; {
    const { config } = response;
    const originalRequest = config;
    if (response.status === 401) { // 401: Unauthorized
      // 토큰 만료 혹은 로그인 정보 없음
      removeAccessToken();
      return await instance
        .post(&#39;/users/reissue-token&#39;, { // 토큰 재발급
          loginId: loginId,
          refreshToken: refreshToken,
        })
        .then(async res =&gt; { // accessToken과 refreshToken 저장
          setAccessToken(res.data.result.accessToken);
          setRefreshToken(res.data.result.refreshToken);
          // 헤더에 새로운 accessToken 입력
          originalRequest.headers.Authorization = `${res.data.result.accessToken}`;
          return axios(originalRequest);
        });
    }
    // 로그인 정보가 있는 경우 (일반 요청)
    return response.data;
  },
  (err: unknown) =&gt; {
    Promise.reject(err);
  },
);</code></pre>
<blockquote>
<p>response에서 일괄적으로 401 토큰이 유효하지 않은 Unauthorized 에러가 발생한다면, accessToken을 삭제하고, refreshToken으로 재발급을 요청해 새로운 accessToken을 발급받는다.</p>
</blockquote>
</li>
</ul>
<h2 id="request-모듈화하기">Request 모듈화하기</h2>
<ul>
<li>request 생성<pre><code class="language-typescript">const instance = createInstance(); // 위에서 생성한 인스턴스를 불러오기
</code></pre>
</li>
</ul>
<p>const defaultRequest = async (path: string, body: (url: string) =&gt; any) =&gt; {
  try {
      const response = body(path);
      return response;
  } catch (err) {
      console.error(err);
  }
};</p>
<pre><code>&gt; 기본 request 모듈을 만든다.
path: URL path
body: 입력할 data 또는 params

- 메소드 구현
```typescript
const post = async (path: string, data: any) =&gt; {
    return await defaultRequest(path, async url =&gt; {
      const response = (await instance).post(url, data);
      return response;
    });
};

const get = async (path: string, params: any) =&gt; {
    return await defaultRequest(path, async url =&gt; {
      const response = (await instance).get(url, {
        params: params,
      });
      return response;
    });
};

const patch = async (path: string, data: any) =&gt; {
    return await defaultRequest(path, async url =&gt; {
      const response = (await instance).patch(url, data);
      return response;
    });
};</code></pre><h2 id="request-모듈-사용하기">Request 모듈 사용하기</h2>
<ul>
<li>request 모듈 사용 예시</li>
</ul>
<pre><code class="language-typescript">const request = Request();    // 위에서 정의한 Request 모듈을 불러온다.

const duplicateCheck = async () =&gt; {
  const response = await request.post(&#39;/users/loginId&#39;, {
      loginId: form.loginId,
  });
  if (response.isSuccess) { // 서버에서 isSuccess라는 응답을 준다.
      setCheck({ ...check, loginId: true });
  }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React-Native] react-native-keychain을 활용한 storage 관리]]></title>
            <link>https://velog.io/@chez_kwak/React-Native-react-native-keychain%EC%9D%84-%ED%99%9C%EC%9A%A9%ED%95%9C-storage-%EA%B4%80%EB%A6%AC</link>
            <guid>https://velog.io/@chez_kwak/React-Native-react-native-keychain%EC%9D%84-%ED%99%9C%EC%9A%A9%ED%95%9C-storage-%EA%B4%80%EB%A6%AC</guid>
            <pubDate>Tue, 21 May 2024 05:17:02 GMT</pubDate>
            <description><![CDATA[<p>React에서는 토큰 저장을 위해 localStorage나 sessionStorage를 사용한다. React Native에서는 이와 비슷하게 AsyncStorage라는 게 존재하지만, 나는 본 프로젝트에 <a href="https://github.com/oblador/react-native-keychain">react-native-keychain</a>이라는 라이브러리를 사용하여 사용자 인증 정보를 저장했다.</p>
<pre><code class="language-shell">yarn add react-native-keychain</code></pre>
<p>사용 방식은 다른 storage와 비슷하다.</p>
<pre><code class="language-typescript">import * as Keychain from &#39;react-native-keychain&#39;;

const ACCESS_TOKEN = &#39;ACCESS_TOKEN&#39;;
const REFRESH_TOKEN = &#39;REFRESH_TOKEN&#39;;
const LOGIN_ID = &#39;LOGIN_ID&#39;;

// get
async function getSecureValue(key: string): Promise&lt;string&gt; {
  const result = await Keychain.getInternetCredentials(key);
  if (result) {
    return result.password;
  }
  return &#39;&#39;;
}

// set
function setSecureValue(key: string, value: string) {
  Keychain.setInternetCredentials(key, key, value);
}

// remove
function removeSecureValue(key: string) {
  Keychain.resetInternetCredentials(key);
}
</code></pre>
<p>사용자 로그인을 위해 필요한 토큰을 저장하고 받아오는 과정을 살펴보자.</p>
<ul>
<li>토큰 저장 함수<pre><code class="language-typescript">export async function getAccessToken(): Promise&lt;string&gt; {
return await getSecureValue(ACCESS_TOKEN);
}
export function setAccessToken(token: string) {
setSecureValue(ACCESS_TOKEN, token);
}
export function removeAccessToken() {
removeSecureValue(ACCESS_TOKEN);
}</code></pre>
</li>
<li>함수 활용 방식<ul>
<li>get함수는 비동기 방식으로 작동하기 때문에 async await와 함께 사용한다.<pre><code class="language-typescript">const accessToken = await getAccessToken();
setAccessToken(res.data.result.accessToken);
removeAccessToken();</code></pre>
</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Python] 백준 2580 - 스도쿠]]></title>
            <link>https://velog.io/@chez_kwak/Python-%EB%B0%B1%EC%A4%80-2580-%EC%8A%A4%EB%8F%84%EC%BF%A0</link>
            <guid>https://velog.io/@chez_kwak/Python-%EB%B0%B1%EC%A4%80-2580-%EC%8A%A4%EB%8F%84%EC%BF%A0</guid>
            <pubDate>Fri, 22 Mar 2024 04:49:59 GMT</pubDate>
            <description><![CDATA[<h1 id="스도쿠">스도쿠</h1>
<h3 id="문제">문제</h3>
<p>스도쿠는 18세기 스위스 수학자가 만든 &#39;라틴 사각형&#39;이랑 퍼즐에서 유래한 것으로 현재 많은 인기를 누리고 있다. 이 게임은 아래 그림과 같이 가로, 세로 각각 9개씩 총 81개의 작은 칸으로 이루어진 정사각형 판 위에서 이뤄지는데, 게임 시작 전 일부 칸에는 1부터 9까지의 숫자 중 하나가 쓰여 있다.</p>
<p><img src="https://velog.velcdn.com/images/chez_kwak/post/c646e550-2434-4582-b35a-438c7ad098b7/image.png" alt=""></p>
<p>나머지 빈 칸을 채우는 방식은 다음과 같다.</p>
<p>각각의 가로줄과 세로줄에는 1부터 9까지의 숫자가 한 번씩만 나타나야 한다.
굵은 선으로 구분되어 있는 3x3 정사각형 안에도 1부터 9까지의 숫자가 한 번씩만 나타나야 한다.
위의 예의 경우, 첫째 줄에는 1을 제외한 나머지 2부터 9까지의 숫자들이 이미 나타나 있으므로 첫째 줄 빈칸에는 1이 들어가야 한다.</p>
<p><img src="https://velog.velcdn.com/images/chez_kwak/post/4ead7901-cf13-4859-9405-1d9f58151ca2/image.png" alt=""></p>
<p>또한 위쪽 가운데 위치한 3x3 정사각형의 경우에는 3을 제외한 나머지 숫자들이 이미 쓰여있으므로 가운데 빈 칸에는 3이 들어가야 한다.</p>
<p><img src="https://velog.velcdn.com/images/chez_kwak/post/adbc6767-e5d8-4634-b523-adf17d5b9f3f/image.png" alt=""></p>
<p>이와 같이 빈 칸을 차례로 채워 가면 다음과 같은 최종 결과를 얻을 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/chez_kwak/post/b92744ce-6e53-4a5d-bde1-a65ecaca4b67/image.png" alt=""></p>
<p>게임 시작 전 스도쿠 판에 쓰여 있는 숫자들의 정보가 주어질 때 모든 빈 칸이 채워진 최종 모습을 출력하는 프로그램을 작성하시오.</p>
<h3 id="입력">입력</h3>
<p>아홉 줄에 걸쳐 한 줄에 9개씩 게임 시작 전 스도쿠판 각 줄에 쓰여 있는 숫자가 한 칸씩 띄워서 차례로 주어진다. 스도쿠 판의 빈 칸의 경우에는 0이 주어진다. 스도쿠 판을 규칙대로 채울 수 없는 경우의 입력은 주어지지 않는다.</p>
<h3 id="출력">출력</h3>
<p>모든 빈 칸이 채워진 스도쿠 판의 최종 모습을 아홉 줄에 걸쳐 한 줄에 9개씩 한 칸씩 띄워서 출력한다.</p>
<p>스도쿠 판을 채우는 방법이 여럿인 경우는 그 중 하나만을 출력한다.</p>
<h3 id="제한">제한</h3>
<p>12095번 문제에 있는 소스로 풀 수 있는 입력만 주어진다.
PyPy3: 1172ms</p>
<h3 id="예제">예제</h3>
<p>예제 입력 1
0 3 5 4 6 9 2 7 8
7 8 2 1 0 5 6 0 9
0 6 0 2 7 8 1 3 5
3 2 1 0 4 6 8 9 7
8 0 4 9 1 3 5 0 6
5 9 6 8 2 0 4 1 3
9 1 7 6 5 2 0 8 0
6 0 3 7 0 1 9 5 2
2 5 8 3 9 4 7 6 0</p>
<p>예제 출력 1 
1 3 5 4 6 9 2 7 8
7 8 2 1 3 5 6 4 9
4 6 9 2 7 8 1 3 5
3 2 1 5 4 6 8 9 7
8 7 4 9 1 3 5 2 6
5 9 6 8 2 7 4 1 3
9 1 7 6 5 2 3 8 4
6 4 3 7 8 1 9 5 2
2 5 8 3 9 4 7 6 1</p>
<h3 id="풀이">풀이</h3>
<ul>
<li>처음 생각한 풀이: 골드4 치고 좀 간단하다고 생각했다. 각 row, col, 3*3 박스만 체크해주면 되겠네? 하고 코드를 짰다. 근데 브루트포스면 시간초과;;;</li>
</ul>
<pre><code class="language-python">import sys

sudoku = [list(map(int, sys.stdin.readline().split())) for _ in range(9)]

def check(box, row, col, num):
    for i in range(9):
        if box[row][i] == num:
            return False

    for i in range(9):
        if box[i][col] == num:
            return False

    # 3 * 3 
    srow, scol = 3 * (row // 3), 3 * (col // 3)
    for i in range(srow, srow + 3):
        for j in range(scol, scol + 3):
            if box[i][j] == num:
                return False

    return True

for i in range(9):
    for j in range(9):
        if sudoku[i][j] == 0:
            for num in range(1,10):
                if check(sudoku, i, j, num):
                    sudoku[i][j] = num

for row in sudoku:
    print(*row)</code></pre>
<ul>
<li>최종 풀이: 그럼 그렇지. 골드4. 백트래킹 문제였다. 가능한 모든 숫자를 체크하기 위해 재귀를 사용해야했다.<pre><code class="language-python">import sys
</code></pre>
</li>
</ul>
<p>sudoku = [list(map(int, sys.stdin.readline().split())) for _ in range(9)]</p>
<p>def check(box, row, col, num):
    for i in range(9):
        if box[row][i] == num:
            return False</p>
<pre><code>for i in range(9):
    if box[i][col] == num:
        return False

# 3 * 3 
srow, scol = 3 * (row // 3), 3 * (col // 3)
for i in range(srow, srow + 3):
    for j in range(scol, scol + 3):
        if box[i][j] == num:
            return False

return True</code></pre><p>def solve(box):
    for i in range(9):
        for j in range(9):
            if box[i][j] == 0:
                for num in range(1,10):
                    if check(box, i, j, num):
                        box[i][j] = num
                        if solve(box):
                            return True
                        box[i][j] = 0 # 백트래킹
                return False
    return True</p>
<p>solve(sudoku)</p>
<p>for row in sudoku:
    print(*row)
```</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Python] 백준 1213 - 팰린드롬 만들기]]></title>
            <link>https://velog.io/@chez_kwak/Python-%EB%B0%B1%EC%A4%80-1213-%ED%8C%B0%EB%A6%B0%EB%93%9C%EB%A1%AC-%EB%A7%8C%EB%93%A4%EA%B8%B0</link>
            <guid>https://velog.io/@chez_kwak/Python-%EB%B0%B1%EC%A4%80-1213-%ED%8C%B0%EB%A6%B0%EB%93%9C%EB%A1%AC-%EB%A7%8C%EB%93%A4%EA%B8%B0</guid>
            <pubDate>Wed, 20 Mar 2024 06:48:30 GMT</pubDate>
            <description><![CDATA[<h2 id="팰린드롬-만들기">팰린드롬 만들기</h2>
<h3 id="문제">문제</h3>
<p>임한수와 임문빈은 서로 사랑하는 사이이다.</p>
<p>임한수는 세상에서 팰린드롬인 문자열을 너무 좋아하기 때문에, 둘의 백일을 기념해서 임문빈은 팰린드롬을 선물해주려고 한다.</p>
<p>임문빈은 임한수의 영어 이름으로 팰린드롬을 만들려고 하는데, 임한수의 영어 이름의 알파벳 순서를 적절히 바꿔서 팰린드롬을 만들려고 한다.</p>
<p>임문빈을 도와 임한수의 영어 이름을 팰린드롬으로 바꾸는 프로그램을 작성하시오.</p>
<h3 id="입력">입력</h3>
<p>첫째 줄에 임한수의 영어 이름이 있다. 알파벳 대문자로만 된 최대 50글자이다.</p>
<h3 id="출력">출력</h3>
<p>첫째 줄에 문제의 정답을 출력한다. 만약 불가능할 때는 &quot;I&#39;m Sorry Hansoo&quot;를 출력한다. 정답이 여러 개일 경우에는 사전순으로 앞서는 것을 출력한다.</p>
<h3 id="예제">예제</h3>
<p>예제 입력 1 
AABB
예제 출력 1 
ABBA
예제 입력 2 
AAABB
예제 출력 2 
ABABA
예제 입력 3 
ABACABA
예제 출력 3 
AABCBAA
예제 입력 4 
ABCD
예제 출력 4 
I&#39;m Sorry Hansoo</p>
<h3 id="풀이">풀이</h3>
<ul>
<li>처음 생각한 풀이<pre><code class="language-python">from collections import Counter
</code></pre>
</li>
</ul>
<p>s = str(input())
c = sorted(Counter(s).items())</p>
<p>odd = 0
for k, v in c:
    if v % 2 != 0:
        odd += 1</p>
<p>answer = &#39;&#39;
if odd &gt; 1:
    print(&quot;I&#39;m sorry Hansoo&quot;)
else:
    for k, v in c:
        if v % 2 != 0: # 필요 없는 부분이더라
            break
        if v % 2 == 0:
            answer += k * (v//2)    # 반복 문자 저장
            del c[0]    # 이 부분이 문제. 잘못 지워진다.</p>
<pre><code>tmp = answer[::-1]
for k, v in c:
    if v % 2 != 0:
        answer += k

answer += tmp</code></pre><p>print(answer)</p>
<pre><code>- 최종 풀이
```python
from collections import Counter

s = str(input())
c = sorted(Counter(s).items())    # 정렬된 튜플 리스트로 변환.

odd = 0
for k, v in c:    # key, value 동시 조회 반복문
    if v % 2 != 0:    # 홀수 문자 개수 저장
        odd += 1

if odd &gt; 1:    # 홀수 문자가 여러 개면 팰린드롬 불가능
    print(&quot;I&#39;m Sorry Hansoo&quot;)
    exit()

answer = &#39;&#39;
m = &#39;&#39;    # 중앙에 올 홀수 문자
for k, v in c:
    if v % 2 != 0:
        m = k # 홀수 문자 따로 저장
    answer += k * (v//2)

answer = answer + m + answer[::-1]    # 반복 문자 + 홀수 문자 + 뒤집은 반복 문자
print(answer)</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[Python] 프로그래머스 - 완주하지 못한 선수]]></title>
            <link>https://velog.io/@chez_kwak/Python-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%99%84%EC%A3%BC%ED%95%98%EC%A7%80-%EB%AA%BB%ED%95%9C-%EC%84%A0%EC%88%98</link>
            <guid>https://velog.io/@chez_kwak/Python-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%99%84%EC%A3%BC%ED%95%98%EC%A7%80-%EB%AA%BB%ED%95%9C-%EC%84%A0%EC%88%98</guid>
            <pubDate>Fri, 15 Mar 2024 02:34:42 GMT</pubDate>
            <description><![CDATA[<h2 id="완주하지-못한-선수">완주하지 못한 선수</h2>
<h3 id="문제-설명">문제 설명</h3>
<p>수많은 마라톤 선수들이 마라톤에 참여하였습니다. 단 한 명의 선수를 제외하고는 모든 선수가 마라톤을 완주하였습니다.</p>
<p>마라톤에 참여한 선수들의 이름이 담긴 배열 participant와 완주한 선수들의 이름이 담긴 배열 completion이 주어질 때, 완주하지 못한 선수의 이름을 return 하도록 solution 함수를 작성해주세요.</p>
<h3 id="제한사항">제한사항</h3>
<p>마라톤 경기에 참여한 선수의 수는 1명 이상 100,000명 이하입니다.
completion의 길이는 participant의 길이보다 1 작습니다.
참가자의 이름은 1개 이상 20개 이하의 알파벳 소문자로 이루어져 있습니다.
참가자 중에는 동명이인이 있을 수 있습니다.</p>
<h3 id="입출력-예">입출력 예</h3>
<p>participant    completion    return
[&quot;leo&quot;, &quot;kiki&quot;, &quot;eden&quot;]
[&quot;eden&quot;, &quot;kiki&quot;]
&quot;leo&quot;
[&quot;marina&quot;, &quot;josipa&quot;, &quot;nikola&quot;, &quot;vinko&quot;, &quot;filipa&quot;]
[&quot;josipa&quot;, &quot;filipa&quot;, &quot;marina&quot;, &quot;nikola&quot;]
&quot;vinko&quot;
[&quot;mislav&quot;, &quot;stanko&quot;, &quot;mislav&quot;, &quot;ana&quot;]
[&quot;stanko&quot;, &quot;ana&quot;, &quot;mislav&quot;]
&quot;mislav&quot;</p>
<h3 id="입출력-예-설명">입출력 예 설명</h3>
<p>예제 #1
&quot;leo&quot;는 참여자 명단에는 있지만, 완주자 명단에는 없기 때문에 완주하지 못했습니다.</p>
<p>예제 #2
&quot;vinko&quot;는 참여자 명단에는 있지만, 완주자 명단에는 없기 때문에 완주하지 못했습니다.</p>
<p>예제 #3
&quot;mislav&quot;는 참여자 명단에는 두 명이 있지만, 완주자 명단에는 한 명밖에 없기 때문에 한명은 완주하지 못했습니다.</p>
<h3 id="풀이">풀이</h3>
<ul>
<li><p>처음 생각했던 풀이. 제일 간단하게 remove 사용해서 풀이. 하지만 효율성 문제가 발생한다. 입력값이 1~100,000 이기 때문에 입력값이 커지면 효율성이 떨어진다.</p>
<pre><code class="language-python">def solution(participant, completion):
  for c in completion:
      participant.remove(c)

  return participant[0]</code></pre>
</li>
<li><p>최종 풀이. 해시맵이 필요하다. dictionary로도 풀이할 수 있는데 counter가 편해서 사용했다.</p>
<pre><code class="language-python">from collections import Counter
</code></pre>
</li>
</ul>
<p>def solution(participant, completion):
    answer = &#39;&#39;
    p = Counter(participant)
    c = Counter(completion)</p>
<pre><code>p.subtract(c)
for k, v in p.items():    # items() 형태로 tuple list 만들기
    if v &gt; 0:
        answer = k
return answer</code></pre><p>```</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[iOS] http 통신 허용 - NSAllowsArbitraryLoads]]></title>
            <link>https://velog.io/@chez_kwak/iOS-http-%ED%86%B5%EC%8B%A0-%ED%97%88%EC%9A%A9-NSAllowsArbitraryLoads</link>
            <guid>https://velog.io/@chez_kwak/iOS-http-%ED%86%B5%EC%8B%A0-%ED%97%88%EC%9A%A9-NSAllowsArbitraryLoads</guid>
            <pubDate>Wed, 10 Jan 2024 00:05:16 GMT</pubDate>
            <description><![CDATA[<h1 id="nsallowsarbitraryloads">NSAllowsArbitraryLoads</h1>
<p>iOS는 http 통신이 기본적으로 불가능하다. https만 허용한다. 하지만 http가 꼭 필요한 경우가 있다.
Info.plist에서 NSAppTransportSecurity 라는 dictionary가 있는데, NSAllowsArbitraryLoads를 true로 설정해주게 되면 http 통신이 가능하다.</p>
<pre><code>&lt;key&gt;NSAppTransportSecurity&lt;/key&gt;
    &lt;dict&gt;
        &lt;key&gt;NSAllowsArbitraryLoads&lt;/key&gt;
        &lt;true/&gt;
        &lt;key&gt;NSExceptionDomains&lt;/key&gt;
        &lt;dict&gt;
            &lt;key&gt;{허용 원하는 URL}&lt;/key&gt;
            &lt;dict&gt;
                &lt;key&gt;NSExceptionAllowsInsecureHTTPLoads&lt;/key&gt;
                &lt;true/&gt;
                &lt;key&gt;NSIncludesSubdomains&lt;/key&gt;
                &lt;true/&gt;
            &lt;/dict&gt;
            &lt;key&gt;localhost&lt;/key&gt;
            &lt;dict&gt;
                &lt;key&gt;NSExceptionAllowsInsecureHTTPLoads&lt;/key&gt;
                &lt;true/&gt;
            &lt;/dict&gt;
        &lt;/dict&gt;
    &lt;/dict&gt;</code></pre><ul>
<li>NSAllowsArbitraryLoads: https 이외의 모든 통신을 허용한다.</li>
<li>NSExceptionDomains: 이 방법의 사용이 권장된다. 필요한 url을 적어주고 그 url만 통신을 허용해준다.</li>
</ul>
<p>나는 pod install만 하면, 기껏 해놓은 true가 false로 다시 overwrite되는 오류가 있었다. 온갖 설정을 다 해봐도 소용이 없었는데, 결국 답은 공식문서였다.
<a href="https://developer.apple.com/documentation/bundleresources/information_property_list/nsapptransportsecurity/nsallowsarbitraryloads">https://developer.apple.com/documentation/bundleresources/information_property_list/nsapptransportsecurity/nsallowsarbitraryloads</a>
<img src="https://velog.velcdn.com/images/chez_kwak/post/f99e01da-858f-4d49-961e-48de11781e7b/image.png" alt="">
Info.plist 안에 3가지 요소 중에 하나라도 있으면 NSAllowsArbitraryLoads의 키값은 무시된다. 즉 무조건 false로만 설정된다는 거다.
나는 NSAllowsLocalNetworking이 있었는데, 이걸 지워주니까 http가 드디어 허용됐다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React-Native] Mac 개발환경 설정 (M1 기준)]]></title>
            <link>https://velog.io/@chez_kwak/React-Native-Mac-%EA%B0%9C%EB%B0%9C%ED%99%98%EA%B2%BD-%EC%84%A4%EC%A0%95-M1-%EA%B8%B0%EC%A4%80</link>
            <guid>https://velog.io/@chez_kwak/React-Native-Mac-%EA%B0%9C%EB%B0%9C%ED%99%98%EA%B2%BD-%EC%84%A4%EC%A0%95-M1-%EA%B8%B0%EC%A4%80</guid>
            <pubDate>Fri, 24 Nov 2023 03:22:20 GMT</pubDate>
            <description><![CDATA[<p>React Native 프로젝트는 환경 설정이 매우 까다롭다. 오류도 정말 많이 발생하고 버전이 조금이라도 안 맞으면 빌드에 실패하기 때문에 꼼꼼히 설정해주어야 한다.
RN 프로젝트는 expo와 react native cli 두 가지로 실행할 수 있는데, 환경 설정에 있어서는 expo가 좀 더 간단하나 개발에 제약이 많기 때문에 조금 어렵더라도 처음부터 react native cli로 시작하는 걸 권장한다.</p>
<h2 id="homebrew-설치">Homebrew 설치</h2>
<p>mac에서 다양한 패키지들을 설치할 수 있게 해주는 패키지 매니저다. 다양한 상황에서 사용할 수 있으니 꼭 설치해놓는 걸 추천.</p>
<pre><code class="language-shell">/bin/bash -c &quot;$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)&quot;</code></pre>
<blockquote>
<p>Homebrew 링크: <a href="https://brew.sh/">https://brew.sh/</a></p>
</blockquote>
<p>Install이 완료되면 제대로 설치되었는지 확인하기 위해 다음 명령어를 사용한다.</p>
<pre><code>brew --version</code></pre><p><img src="https://velog.velcdn.com/images/chez_kwak/post/89658b83-8d77-45f8-ab4a-fd56f315555e/image.png" alt=""></p>
<h2 id="xcode-설치">Xcode 설치</h2>
<p>앱 스토어에서 설치! 용량이 매우 크니 설치 눌러두고 다른 작업 하고 있는 거 추천.
<img src="https://velog.velcdn.com/images/chez_kwak/post/6fde3c09-a72c-454c-8c1d-69a4e1955403/image.png" alt=""></p>
<h2 id="node-설치">node 설치</h2>
<p>React native는 Javascript 기반이기 때문에 javascript의 런타임 매</p>
<pre><code class="language-shell">brew install node</code></pre>
<blockquote>
<p>Node js 다운로드 링크: <a href="https://nodejs.org/en">https://nodejs.org/en</a>
링크를 확인해보면 LTS 버전과 Current 버전이 있는데 LTS 버전을 권장한다. 생각보다 node.js 버전 별로 패키지 dependency 오류가 많이 발생하기 때문에.. 추후에 package version 오류가 발생하면 node 버전을 낮춰줘야 하는 경우도 생긴다.</p>
</blockquote>
<p>node를 설치하면 패키지 매니저인 npm도 자동으로 설치된다.
<img src="https://velog.velcdn.com/images/chez_kwak/post/d49b3656-77f2-4603-a7bd-1e43198e84ef/image.png" alt=""></p>
<h2 id="watchman-설치">watchman 설치</h2>
<p>Watchman은 React-Native에서 코드의 추가, 변경 등의 수정 사항이 발생하면 다시 빌드하기 위해 사용한다.</p>
<pre><code class="language-shell">brew install watchman</code></pre>
<p><img src="https://velog.velcdn.com/images/chez_kwak/post/e187c0ca-4495-4179-90ac-a7f4efd97b5a/image.png" alt=""></p>
<h2 id="cocoapods-설치">cocoapods 설치</h2>
<p>cocoapods는 ios 개발을 위해 필요한 의존성 관리자이다.</p>
<pre><code class="language-shell">sudo gem install cocoapods</code></pre>
<p><img src="https://velog.velcdn.com/images/chez_kwak/post/a803c11b-c360-46a1-841f-91d6c9770910/image.png" alt=""></p>
<h2 id="react-native-설치">react native 설치</h2>
<p>이번에는 brew가 아니라 npm으로 설치해주어야 한다.</p>
<pre><code class="language-shell">npm install -g react-native-cli</code></pre>
<p><img src="https://velog.velcdn.com/images/chez_kwak/post/4c536b90-ebb8-4f79-a264-8e1bec27fb90/image.png" alt=""></p>
<p>여기까지 react native 기본 설정을 마쳤다. 이제부터는 iOS와 Android 개발을 위한 세팅을 진행해준다.</p>
<h2 id="ios-설정">iOS 설정</h2>
<ol>
<li>Xcode 열기
아무 프로젝트나 만들어서 일단 Xcode를 실행해준다.
<img src="https://velog.velcdn.com/images/chez_kwak/post/65b063cc-23be-49d3-9247-db220fb96130/image.png" alt=""></li>
<li>상단 바에서 Xcode를 눌러 Settings에 들어가준다. (버전에 따라 Preferences로 나와 있을 수도 있다.)
<img src="https://velog.velcdn.com/images/chez_kwak/post/ca836cca-410b-4892-bd7d-7487910ab682/image.png" alt=""></li>
<li><strong>Accounts</strong>: Simulator가 아닌 실제 디바이스를 연결해서 개발해야하는 경우가 있다. 이를 위해 iCloud 계정을 등록해준다.
<img src="https://velog.velcdn.com/images/chez_kwak/post/9877f09e-5cbe-4f5b-af07-6ba8ab854a58/image.png" alt=""></li>
<li><strong>Locations</strong>: Command Line Tools가 선택되어 있지 않은 경우, Xcode x.x(버전명)을 선택해준다.
<img src="https://velog.velcdn.com/images/chez_kwak/post/bbaefd3b-28c8-410d-bf59-e9af4f9703d6/image.png" alt=""></li>
<li><strong>Platforms</strong>: 최신 버전 iOS Simulator를 선택하여 설치해준다.
<img src="https://velog.velcdn.com/images/chez_kwak/post/b1f2649a-0e2e-45a8-b080-abae7682501e/image.png" alt=""></li>
</ol>
<h2 id="android-설정">Android 설정</h2>
<ol>
<li><p>java 설치</p>
<pre><code class="language-shell">brew tap adoptopenjdk/openjdk
brew install --cask adoptopenjdk14 // 숫자는 버전명이다. 원하는 버전을 설치해준다.</code></pre>
<p><img src="https://velog.velcdn.com/images/chez_kwak/post/88113d77-302b-43cc-8cc4-f9765e206db2/image.png" alt=""></p>
</li>
<li><p>Android Studio 설치</p>
<blockquote>
<p><a href="https://developer.android.com/studio?hl=ko">https://developer.android.com/studio?hl=ko</a>
위 링크를 통해 다운로드 받을 수 있다.</p>
</blockquote>
</li>
<li><p>Emulator 생성
설치를 마치면 다음과 같은 화면을 확인할 수 있다.
<img src="https://velog.velcdn.com/images/chez_kwak/post/0b29d650-9d11-4498-9331-0cab05a0842c/image.png" alt="">
Virtual Device Manager를 눌러 들어가서 Create Device로 에뮬레이터를 선택한다. 원하는 픽셀 크기와 타겟팅할 API를 선택해준다. 요즘 플레이스토어는 무조건 33 이상을 타겟팅하도록 하고 있으니 에뮬레이터도 맞춰서 설정해주면 좋다.
<img src="https://velog.velcdn.com/images/chez_kwak/post/e6436e39-337f-4e59-adab-9093f77aeb24/image.png" alt=""></p>
</li>
<li><p>SDK Manager 설정
<img src="https://velog.velcdn.com/images/chez_kwak/post/106945a8-cf9e-464c-8f41-b11139ddedf8/image.png" alt="">
<img src="https://velog.velcdn.com/images/chez_kwak/post/ab9b1548-d995-490f-8649-344ab530d73e/image.png" alt=""></p>
</li>
</ol>
<ul>
<li>Android SDK Location: 환경 설정 파일에 추가해야 하니 복사해두기.</li>
<li>SDK Tools: 다음과 같은 항목들을 선택하고 Apply를 눌러주면 다운로드가 진행된다.</li>
<li>SDK Platforms: 다음과 같은 항목들을 선택하고 Apply 누르기
<img src="https://velog.velcdn.com/images/chez_kwak/post/9c82e87c-5bbd-414b-bc89-a596c3d3754a/image.png" alt=""></li>
</ul>
<ol start="5">
<li>환경 변수 설정<pre><code class="language-shell">vi ~/.zshrc // 명령어로 파일 열기
</code></pre>
</li>
</ol>
<p>// .zshrc 파일 내에 다음 내용 추가
export ANDROID_HOME=/Users/(유저명)/Library/Android/sdk //위에서 복사해둔 Android SDK Location
export PATH=$PATH:$ANDROID_HOME/emulator
export PATH=$PATH:$ANDROID_HOME/tools
export PATH=$PATH:$ANDROID_HOME/tools/bin
export PATH=$PATH:$ANDROID_HOME/platform-tools</p>
<p>source ~/.zshrc // 변경 내용 바로 적용</p>
<pre><code>
## react native 실행
다음 명령어를 실행하면 내가 지정한 프로젝트명으로 폴더가 생성되면서 React Native 프로젝트가 시작된다.
```shell
npx react-native init 프로젝트명</code></pre><p>생성된 프로젝트를 실행하고 싶으면 다음 명령어를 입력한다.</p>
<pre><code class="language-shell">npm start // yarn을 사용하고 싶으면 yarn start</code></pre>
<p>안드로이드 에뮬레이터를 실행하고 싶으면 <code>a</code>, iOS 시뮬레이터를 실행하고 싶으면 <code>i</code>를 눌러주면 에뮬레이터가 실행되면서 프로젝트를 확인할 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React Native] 안드로이드에서 APK release 이후 네트워크 에러 발생]]></title>
            <link>https://velog.io/@chez_kwak/React-Native-%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C%EC%97%90%EC%84%9C-APK-release-%EC%9D%B4%ED%9B%84-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%EC%97%90%EB%9F%AC-%EB%B0%9C%EC%83%9D</link>
            <guid>https://velog.io/@chez_kwak/React-Native-%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C%EC%97%90%EC%84%9C-APK-release-%EC%9D%B4%ED%9B%84-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%EC%97%90%EB%9F%AC-%EB%B0%9C%EC%83%9D</guid>
            <pubDate>Sun, 05 Nov 2023 13:56:37 GMT</pubDate>
            <description><![CDATA[<p>RN으로 안드로이드 apk를 빌드했을 때, 네트워크 오류가 발생하는 경우가 있다.
나는 에뮬레이터에서는 정상 작동하는데 apk만 빌드하면 계속해서 백엔드 연결이 안 되는 오류가 발생했다.
나의 경우에는 백엔드 api url을 http로 사용하고 있었는데, 현재 안드로이드 버전에서는 https만 지원하고 http는 허용하지 않아서 생기는 문제였다. http를 허용해주기 위해, AndroidManifest.xml 파일에서 <code>android:usesCleartextTraffic</code> 이 한 줄만 추가해주고 다시 빌드하니 작동했다.</p>
<pre><code class="language-kotlin">&lt;manifest ...&gt;
    &lt;uses-permission android:name=&quot;android.permission.INTERNET&quot; /&gt;
    &lt;application
        ...
        android:usesCleartextTraffic=&quot;true&quot;  // &lt;-- added this 
        ...&gt;
        ...
    &lt;/application&gt;
&lt;/manifest&gt;</code></pre>
<p><a href="https://github.com/facebook/react-native/issues/24039#issuecomment-518687649">https://github.com/facebook/react-native/issues/24039#issuecomment-518687649</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Python] 파이썬 기본 문법 - 함수, 람다 표현식, 라이브러리]]></title>
            <link>https://velog.io/@chez_kwak/Python-%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EA%B8%B0%EB%B3%B8-%EB%AC%B8%EB%B2%95-%ED%95%A8%EC%88%98-%EB%9E%8C%EB%8B%A4-%ED%91%9C%ED%98%84%EC%8B%9D-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC</link>
            <guid>https://velog.io/@chez_kwak/Python-%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EA%B8%B0%EB%B3%B8-%EB%AC%B8%EB%B2%95-%ED%95%A8%EC%88%98-%EB%9E%8C%EB%8B%A4-%ED%91%9C%ED%98%84%EC%8B%9D-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC</guid>
            <pubDate>Tue, 18 Apr 2023 16:24:22 GMT</pubDate>
            <description><![CDATA[<h1 id="함수">함수</h1>
<ul>
<li>매개변수: 함수 내부에서 사용할 변수</li>
<li>반환 값: 함수에서 처리 된 결과 반환</li>
</ul>
<pre><code class="language-python">def add(a,b):
    print(&#39;결과: &#39;, a+b)
add(3,7)</code></pre>
<ul>
<li>파라미터 지정 가능: 매개변수 순서 달라도 ok<pre><code class="language-python">add(b=3, a=7)</code></pre>
</li>
<li>global: 전역 변수. 함수 바깥에 선언된 변수 바로 참조. 파이썬은 함수 안에 선언된 변수만 함수 내에서 인식 가능함.<pre><code class="language-python">a = 0
def func():
  global a
  a += 1
for i in range(10):
  func()
print(a)    # 10</code></pre>
</li>
<li>리턴 값 여러 개 가능<h1 id="람다-표현식">람다 표현식</h1>
</li>
<li>함수를 한 줄에 작성 가능<pre><code class="language-python">print((lambda a, b: a + b)(3,7))</code></pre>
<pre><code class="language-python">arr = [(&#39;김&#39;, 50), (&#39;이&#39;, 32), (&#39;박&#39;, 74)]
def my_key(x):
  return x[1]
print(sorted(array, key=my_key))
print(sorted(array, key=lambda x: x[1]))
# [(&#39;이&#39;, 32), (&#39;김&#39;, 50), (&#39;박&#39;, 74)]</code></pre>
<pre><code class="language-python">l1 = [1,2,3,4,5]
l2 = [6,7,8,9,10]
result = map(lambda a,b: a+b, l1, l2)
print(list(result))        # [7,9,11,13,15]</code></pre>
<h1 id="라이브러리">라이브러리</h1>
<h2 id="내장-함수">내장 함수</h2>
</li>
<li>sum(): 리스트, 튜플 원소들의 합</li>
<li>min(): 리스트에서 가장 작은 값</li>
<li>max(): 리스트에서 가장 큰 값</li>
<li>eval(): 문자열 형태 수식의 결과를 수로 반환</li>
<li>sorted(): 리스트와 같은 반복 가능한 객체를 오름차순 정렬<ul>
<li>sorted([], reverse=True): 내림차순 정렬<ul>
<li>sorted([], key=lambda x: x[1]): key로 정렬<h2 id="itertools">itertools</h2>
<code>순열, 조합</code></li>
</ul>
</li>
</ul>
</li>
<li>permutations(): 순열</li>
<li>combinations(): 조합<pre><code class="language-python">from itertools import permutations, combinations
data = [&#39;a&#39;, &#39;b&#39;, &#39;c&#39;]
result1 = list(permutations(data, 3))    # 모든 순열 구하기
result2 = list(combinations(data, 2))    # 2개 뽑는 모든 조합 구하기</code></pre>
</li>
<li>중복순열, 중복조합<pre><code class="language-python">from itertools import product, combinations_with_data
data = [&#39;a&#39;, &#39;b&#39;, &#39;c&#39;]
result1 = list(product(data, repeat=2))                    # 2개 뽑는 모든 순열 (중복 허용)
result2 = list(combinations_with_replacement(data, 2))    # 2개 뽑는 모든 조합 (중복 허용)</code></pre>
<h2 id="heapq">heapq</h2>
<code>우선순위 queue</code><h2 id="bisect">bisect</h2>
<code>이진 탐색</code><h2 id="collections">collections</h2>
<code>deque, counter</code></li>
<li>counter: 등장 횟수 세는 기능. iterable 객체에서 내부 원소 몇 번씩 등장했는지 count<pre><code class="language-python">from collections import Counter
counter = Counter([&#39;r&#39;, &#39;g&#39;, &#39;b&#39;, &#39;r&#39;, &#39;g&#39;, &#39;g&#39;])
print(counter[&#39;r&#39;])        # 2
print(dict(counter))    # {&#39;r&#39;: 2, &#39;g&#39;: 3, &#39;b&#39;: 1}</code></pre>
<h2 id="math">math</h2>
<code>팩토리얼, 제곱근, 최대 공약수, 삼각함수, pi 상수</code></li>
<li>gcd(): 최대 공약수<pre><code class="language-python">import math
def lcm(a,b):    # 최소 공배수 구하기: 최소 공배수 = 두 수의 곱 나누기 최대 공약수
  return a*b // math.gcd(a,b)</code></pre>
</li>
</ul>
<hr>
<blockquote>
<p>참고
<strong>이것이 취업을 위한 코딩 테스트다 with 파이썬</strong>
<a href="https://youtu.be/m-9pAwq1o3w">https://youtu.be/m-9pAwq1o3w</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Python] 파이썬 기본 문법 - 입출력, 조건문, 반복문]]></title>
            <link>https://velog.io/@chez_kwak/Python-%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EA%B8%B0%EB%B3%B8-%EB%AC%B8%EB%B2%95-%EC%9E%85%EC%B6%9C%EB%A0%A5-%EC%A1%B0%EA%B1%B4%EB%AC%B8-%EB%B0%98%EB%B3%B5%EB%AC%B8</link>
            <guid>https://velog.io/@chez_kwak/Python-%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EA%B8%B0%EB%B3%B8-%EB%AC%B8%EB%B2%95-%EC%9E%85%EC%B6%9C%EB%A0%A5-%EC%A1%B0%EA%B1%B4%EB%AC%B8-%EB%B0%98%EB%B3%B5%EB%AC%B8</guid>
            <pubDate>Tue, 18 Apr 2023 15:04:01 GMT</pubDate>
            <description><![CDATA[<h1 id="입출력">입출력</h1>
<h2 id="입력">입력</h2>
<ul>
<li>input(): 한 줄의 문자열 입력</li>
<li>map(): 리스트의 모든 원소에 각각 특정한 함수 적용<pre><code class="language-python">n = int(input())    # 데이터 크기 입력
data = list(map(int, input().split()))        # 공백 기준으로 정수형 데이터 리스트</code></pre>
<blockquote>
<ul>
<li>빠르게 입력: sys.stdin.readline()</li>
</ul>
</blockquote>
<ul>
<li>엔터가 줄 바꿈 기호로 입력되므로 rstrip() 메서드 함께 사용<pre><code class="language-python">import sys
data = sys.stdin.readline().rstrip()</code></pre>
</li>
</ul>
</li>
</ul>
<h2 id="출력">출력</h2>
<ul>
<li>print(): 각 변수를 ,를 이용하여 띄어쓰기로 구분<ul>
<li>기본적으로 출력 이후에 줄 바꿈 수행 -&gt; 줄 바꿈 원치 않을 경우, &#39;end&#39; 속성 이용<pre><code class="language-python">print(7, end=&quot; &quot;)
print(8, end=&quot; &quot;)
# 7 8</code></pre>
</li>
</ul>
</li>
<li>f-string: 문자열 앞에 접두사 f 붙여 사용<ul>
<li>중괄호 안에 변수명 기입하여 문자열과 정수 함께 넣을 수 있음<pre><code class="language-python">answer = 7
print(f&quot;정답: {answer}&quot;)    # 정답: 7</code></pre>
<h1 id="조건문">조건문</h1>
</li>
</ul>
</li>
<li>블록 indent로 조건문 설정</li>
<li>조건문 간소화<ul>
<li>조건문에서 실행될 코드가 한 줄인 경우, 줄 바꿈 없이 한 줄로 표기<ul>
<li>조건부 표현식으로 한 줄로 표기
<code>result = &#39;success&#39; if score &gt;= 80 else &#39;fail&#39;</code><blockquote>
<p><strong>부등식</strong>
x &gt; 0 and x &lt; 20 과 0 &lt; x &lt; 20 은 같은 결과</p>
</blockquote>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<h2 id="if-elif-else">if-elif-else</h2>
<pre><code class="language-python">score = 85
if score &gt;= 75:
    print(&#39;75 이상&#39;)
elif score &gt;= 50:
    print(&#39;50 이상 75 미만&#39;)
else:
    print(&#39;50 미만&#39;)
print(&#39;종료&#39;)
# 75 이상
# 종료</code></pre>
<h2 id="연산자">연산자</h2>
<h3 id="비교">비교</h3>
<table>
<thead>
<tr>
<th>==</th>
<th>!=</th>
<th>&lt;</th>
<th>&gt;</th>
<th>&lt;=</th>
<th>&gt;=</th>
</tr>
</thead>
<tbody><tr>
<td>같다</td>
<td>다르다</td>
<td>작다</td>
<td>크다</td>
<td>작거나 같다</td>
<td>크거나 같다</td>
</tr>
<tr>
<td>- 대입 연산자: =</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>- 같음 연산자: ==</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>### 논리</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>- and: 모두 참일 때 참</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>- or: 둘 중 하나만 참이어도 참</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>- not: 거짓일때 참</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>### 기타</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>- in: 리스트 안에 x 가 들어가 있을 때 참</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>- not in: 리스트 안에 x가 들어가 있지 않을 때 참</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>=&gt; 리스트, 튜플, 딕셔너리, 문자열 모두 사용 가능</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody></table>
<blockquote>
<ul>
<li><strong>pass</strong>: 아무것도 처리하고 싶지 않을 때 사용<ul>
<li>디버깅 과정에서 일단 조건문의 형태만 만들어 놓고 조건문 처리하는 부분은 비워놓고 싶은 경우</li>
</ul>
</li>
</ul>
</blockquote>
<pre><code>a = 5
if a &gt;= 0:
    pass    # 나중에 작성할 코드
else:
    print(&#39;음수&#39;)</code></pre><h1 id="반복문">반복문</h1>
<ul>
<li>코딩 테스트 실제 예시에서는 for문이 더 간결한 경우가 많음</li>
<li>continue: 남은 코드 실행 건너뛰고 다음 반복 진행</li>
<li>break: 반복문 즉시 탈출</li>
<li>중첩 반복문 가능<h2 id="while">while</h2>
<pre><code class="language-python">i = 1
result = 0
while i &lt;= 9:
  result += i
  i += 1
print(result)    # 45</code></pre>
</li>
<li>무한 루프: 반복문 작성한 뒤, 탈출할 수 있는지 확인 (코딩 테스트에서는 거의 구현할 일 없음)<h2 id="for">for</h2>
</li>
<li>for 변수 in 리스트: in 뒤에 오는 데이터(리스트, 튜플 등)에 포함되어 있는 원소를 첫 번째 인덱스부터 방문</li>
<li>for 변수 in range(시작 값, 끝 값+1): 연속적인 값 차례대로 순회<ul>
<li>인자를 하나만 넣으면 자동으로 시작 값은 0<pre><code class="language-python">result = 0
for i in range(1, 10):
result += i
print(result)    # 45</code></pre>
</li>
</ul>
</li>
</ul>
<hr>
<blockquote>
<p>참고
<strong>이것이 취업을 위한 코딩 테스트다 with 파이썬</strong>
<a href="https://youtu.be/m-9pAwq1o3w">https://youtu.be/m-9pAwq1o3w</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Python] 파이썬 기본 문법 - 자료형]]></title>
            <link>https://velog.io/@chez_kwak/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EA%B8%B0%EB%B3%B8-%EB%AC%B8%EB%B2%95-%EC%9E%90%EB%A3%8C%ED%98%95</link>
            <guid>https://velog.io/@chez_kwak/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EA%B8%B0%EB%B3%B8-%EB%AC%B8%EB%B2%95-%EC%9E%90%EB%A3%8C%ED%98%95</guid>
            <pubDate>Tue, 18 Apr 2023 10:28:18 GMT</pubDate>
            <description><![CDATA[<h1 id="자료형">자료형</h1>
<h2 id="수-자료형">수 자료형</h2>
<h3 id="정수형">정수형</h3>
<ul>
<li><p>양의 정수, 음의 정수, 0 <em>(형 변환 int)</em></p>
</li>
<li><p><em><em>코테 출제 대부분의 문제는 정수형을 주로 다룸</em>*</em></p>
<pre><code class="language-python">a = 1000    # 양의 정수
b = -7        # 음의 정수
c = 0        # 0</code></pre>
<h3 id="실수형">실수형</h3>
</li>
<li><p>소수점 아래의 데이터를 포함하는 수 자료형 : 변수에 소수점 붙이면 실수형으로 표현 가능 <em>(형 변환 float)</em></p>
<pre><code class="language-python">a = 157.93
b = -1837.2
c = 5.        # 소수부가 0일 때 0 생략: 5.0
d = -.7        # 정수부가 0일 때 0 생략: -0.7</code></pre>
</li>
<li><p>지수 표현 방식: e나 E 다음에 오는 수는 10의 지수부
<code>유효숫자e지수 = 유효숫자 * 10^지수</code></p>
<pre><code class="language-python">a = 1e9        # 1,000,000,000
b = 75.25e1    # 752.5
c = 3954e-3    # 3.954</code></pre>
<blockquote>
<p><strong>최단 경로 알고리즘 (그래프)</strong> : 도달할 수 없는 노드에 대하여 최단 거리를 <strong>INF</strong>(무한)으로 설정</p>
</blockquote>
</li>
<li><p>round() : 반올림 내장함수</p>
<pre><code class="language-python">round(123.456, 2)    # 123.46</code></pre>
</li>
</ul>
<blockquote>
<p>💡 <strong>연산</strong> : 사칙연산 + 나머지 연산자 많이 사용</p>
</blockquote>
<ul>
<li>// : 몫 연산자</li>
<li>/ : 나누기 연산자. 결과를 실수형으로 반환</li>
<li>% : 나머지 연산자</li>
<li>** : 거듭제곱 연산자</li>
</ul>
<h2 id="리스트">리스트</h2>
<ul>
<li>리스트: 여러 개의 데이터를 연속적으로 담아 처리. (배열, table)<h3 id="초기화">초기화</h3>
</li>
<li>대괄호 안에 원소 넣기. 쉼표로 원소 구분</li>
<li>list() 혹은 [] 이용하여 선언</li>
<li>인덱스 값으로 접근 (0부터)<pre><code class="language-python">a = [1,3,5,7,9]
print(a[1])        # 3
empty = list()      </code></pre>
<h3 id="인덱싱과-슬라이싱">인덱싱과 슬라이싱</h3>
</li>
<li>인덱싱: 인덱스 값을 입력하여 리스트의 특정한 원소에 접근.<pre><code>- 인덱스 값: 양, 음 정수 모두 사용 가능 (음의 정수: 원소 거꾸로 탐색)</code></pre><pre><code class="language-python">a = [1,2,3,4,5]
print(a[-1])    # 5</code></pre>
</li>
<li>슬라이싱: 연속적인 위치의 원소들 가져오기.<ul>
<li>리스트[시작 인덱스: 끝 인덱스] (<strong>끝 인덱스: 실제 인덱스보다 + 1</strong>)<pre><code class="language-python">a = [1, 2, 3, 4, 5]
print(a[0:2])    # 1,2</code></pre>
</li>
</ul>
</li>
</ul>
<h3 id="컴프리헨션">컴프리헨션</h3>
<ul>
<li>대괄호 안에 조건문과 반복문을 적용하여 리스트 초기화<pre><code class="language-python">a = [i for i in range(10)]
print(a)    # [1,2,3,4,5,6,7,8,9]
b = [j * j for j in range(1,10) if j % 2 == 1]
print(b)    # [1,9,25,49,81]
</code></pre>
</li>
</ul>
<h1 id="list-comprehension-사용하지-않을-경우">List Comprehension 사용하지 않을 경우</h1>
<p>b = []
for j in range(1,10):
    if j % 2 == 1:
        b.append(j*j)
print(b)</p>
<pre><code>&gt; **2차원 리스트 초기화할 때 효과적으로 사용**
- n x m 크기의 2차원 리스트를 한 번에 초기화
`a = [[0] * m for _ in range(n)]`

_ _ : 반복문에서 반복 변수값 무시하고 싶을 때 사용_

### 메서드
- append(): 원소 하나 삽입 `O(1)`
- sort(): 오름차순 정렬 `O(NlogN)`
sort(reverse = True): 내림차순 정렬
- reverse(): 리스트 원소 순서 모두 뒤집기 `O(N)`
- insert(): 특정 인덱스 위치에 원소 삽입 `O(N)`
- count(): 특정 값 갖는 원소 개수 세기 `O(N)`
- remove(): 특정 값 갖는 원소 제거. 여러 개면 하나만 제거 `O(N)`
```python
a.append(4)
a.append([5,6])
a.sort()    # 문자도 알파벳 순서 정렬 가능
a.reverse() # 정렬 X. 반환값 X. 그냥 뒤집어주는 메소드.
a.insert(0,4)   # 리스트의 0번째 위치에 4 삽입
a.remove(3) # 리스트에서 첫 번째로 나오는 3 제거
a.count(1)  # 1이 몇 개 있는지 리턴</code></pre><blockquote>
<p>💡 <strong>리스트에서 특정 값 가지는 원소 모두 제거</strong></p>
</blockquote>
<pre><code class="language-python">a = [1,2,3,3,3,4,5,5]
remove_set = {3,5}
result = [i for i in a if i not in remove_set]
print(result)    # [1,2,4]</code></pre>
<h2 id="문자열">문자열</h2>
<h3 id="초기화-1">초기화</h3>
<ul>
<li>&quot;&quot; 혹은 &#39;&#39; 이용 (\ 이스케이프 문자 사용해서 따옴표를 문자처럼 취급하여 표현)<h3 id="연산">연산</h3>
</li>
<li>+ 사용하여 concatenate: 양의 정수와 곱하면 여러 번 더해짐</li>
<li>indexing, slicing 가능 but <strong>특정 인덱스 값 변경 불가</strong><pre><code class="language-python">a = &#39;hello&#39;
b = &#39;world&#39;
print(a+&quot; &quot;+b)    # hello world</code></pre>
<h2 id="튜플">튜플</h2>
<h3 id="특징">특징</h3>
</li>
<li>한 번 선언된 값 변경 불가</li>
<li>() 이용</li>
<li>리스트에 비해 공간 효율적<pre><code class="language-python">a = (1,2,3,4,5)
print(a[3])        # 4
print(a[1:4])    # (2,3,4)</code></pre>
<blockquote>
<p><strong>튜플 장점</strong></p>
</blockquote>
</li>
<li>서로 다른 성질 데이터 묶어서 관리할 때 ex) 최단 경로 알고리즘 (비용, 노드 번호)</li>
<li>해싱 키 값으로 사용</li>
<li>메모리 효율적 사용</li>
</ul>
<h2 id="사전">사전</h2>
<h3 id="특징-1">특징</h3>
<ul>
<li>Key, Value 쌍을 데이터로 가지는 자료형: <strong>변경 불가능한 자료형</strong>을 키로 사용</li>
<li>Hash table 이용: 데이터 조회/수정 <code>O(1)</code><pre><code class="language-python">data = dict()
data[&#39;사과&#39;] = &#39;apple&#39;    # 사과: key, apple: value
data[&#39;바나나&#39;] = &#39;banana&#39;
data[&#39;오렌지&#39;] = &#39;orange&#39;
print(data)        # {&#39;사과&#39;:&#39;apple&#39;, &#39;바나나&#39;:&#39;banana&#39;, &#39;오렌지&#39;:&#39;orange&#39;}</code></pre>
<h3 id="함수">함수</h3>
</li>
<li>keys(): key 데이터만 담은 리스트</li>
<li>values(): value 데이터만 담은 리스트<pre><code class="language-python">key_list = data.keys()
value_list = data.values()
print(key_list)        # dict_keys([&#39;사과&#39;, &#39;바나나&#39;, &#39;오렌지&#39;])
print(value_list)    # dict_values([&#39;apple&#39;, &#39;banana&#39;, &#39;orange&#39;])</code></pre>
</li>
</ul>
<h2 id="집합">집합</h2>
<h3 id="특징-2">특징</h3>
<ul>
<li>중복 허용 X</li>
<li>순서 X</li>
<li>데이터 조회/수정 <code>O(1)</code><h3 id="초기화-2">초기화</h3>
</li>
<li>list 혹은 string 이용: set() 함수 이용</li>
<li>{} 안에 각 원소를 , 기준으로 구분하여 삽입<pre><code class="language-python">a = set([1,1,2,3,4,4,5])
b = {1,1,2,3,4,4,5}
print(a)    # {1,2,3,4,5}
print(b)    # {1,2,3,4,5}</code></pre>
<h3 id="연산-1">연산</h3>
</li>
<li>합집합: a | b</li>
<li>교집합: a &amp; b</li>
<li>차집합: a - b<h3 id="함수-1">함수</h3>
</li>
<li>add(): 새로운 원소 추가</li>
<li>update(): 새로운 원소 여러 개 추가</li>
<li>remove(): 특정 값 갖는 원소 삭제<pre><code class="language-python">data.add(4)
data.update([5,6])
data.remove(3)</code></pre>
<blockquote>
<ul>
<li>리스트, 튜플: 순서 O. 인덱싱을 통해 값 얻기</li>
</ul>
</blockquote>
</li>
<li>사전, 집합: 순서 X. 인덱싱 불가. 사전의 key, 집합의 element를 이용해 <code>O(1)</code>로 조회</li>
</ul>
<hr>
<blockquote>
<p>참고: 이것이 취업을 위한 코딩테스트다 with 파이썬
<a href="https://youtu.be/m-9pAwq1o3w">https://youtu.be/m-9pAwq1o3w</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] React 기본 문법]]></title>
            <link>https://velog.io/@chez_kwak/React-React-%EA%B8%B0%EB%B3%B8-%EB%AC%B8%EB%B2%95</link>
            <guid>https://velog.io/@chez_kwak/React-React-%EA%B8%B0%EB%B3%B8-%EB%AC%B8%EB%B2%95</guid>
            <pubDate>Mon, 06 Mar 2023 16:35:37 GMT</pubDate>
            <description><![CDATA[<h1 id="react">React</h1>
<h3 id="생성">생성</h3>
<pre><code>npx create-react app . // 현재 디렉토리에 프로젝트 생성</code></pre><p><code>npm start</code> 코드 시행</p>
<h3 id="수정">수정</h3>
<h3 id="배포">배포</h3>
<p><code>npm run build</code></p>
<p>serve: 웹서버. 사용 추천. 노드.
<code>npx serve -s build</code></p>
<p>=&gt; localhost 말고 네트워크로 배포.</p>
<h1 id="component">Component</h1>
<p>사용자 정의 태그 만들기: 함수 정의 (<strong>무조건 대문자</strong>)
=&gt; <strong>컴포넌트</strong></p>
<pre><code class="language-javascript">// components
function Header() {
  return &lt;header&gt;
    &lt;h1&gt;&lt;a href = &quot;/&quot;&gt;React&lt;/a&gt;&lt;/h1&gt;
  &lt;/header&gt;
}

function Nav() {
  return &lt;nav&gt;
    &lt;ol&gt;
      &lt;li&gt;&lt;a href = &quot;/read/1&quot;&gt;html&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href = &quot;/read/2&quot;&gt;css&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href = &quot;/read/3&quot;&gt;js&lt;/a&gt;&lt;/li&gt;
    &lt;/ol&gt;
&lt;/nav&gt;
}

function Article() {
  return &lt;article&gt;
    &lt;h2&gt;Welcome&lt;/h2&gt;
    Hello, WEB
  &lt;/article&gt;
}

// main function
function App() {
  return (
    &lt;div className=&quot;App&quot;&gt;
      &lt;Header /&gt;
      &lt;Nav /&gt;
      &lt;Article /&gt;
    &lt;/div&gt;
  );
}</code></pre>
<h1 id="props">Props</h1>
<p>Prop: 속성</p>
<pre><code class="language-javascript">function Header(props) {    // 변수명 임의로 props라 설정함
  console.log(&#39;props&#39;, props, props.title);
  return &lt;header&gt;
    &lt;h1&gt;&lt;a href = &quot;/&quot;&gt;{props.title}&lt;/a&gt;&lt;/h1&gt;
      // { } 안에 작성 시, 변수 취급
  &lt;/header&gt;
}

function App() {
  return (
    &lt;div className=&quot;App&quot;&gt;
      &lt;Header title = &#39;REACT&#39;/&gt;
      &lt;Nav /&gt;
      &lt;Article /&gt;
    &lt;/div&gt;
  );
}</code></pre>
<p>콘솔에 다음과 같이 출력됨</p>
<pre><code>&gt;&gt; props {title: &#39;REACT&#39;} REACT</code></pre><pre><code class="language-javascript">function Nav(props) {
  const lis = []
  // 반복문
  for(let i = 0; i &lt; props.topics.length; i++){    // 객체 배열 길이: length
    let t = props.topics[i];    // topics 배열을 변수 t에 저장
    lis.push(&lt;li key = {t.id}&gt;    // key라는 prop에는 unique key값 필요. id 값을 key 값으로 저장
      &lt;a href = {&quot;/read/&quot; + t.id}&gt;{t.title}&lt;/a&gt;
        // 중괄호 사용하여 id값을 주소에 포함
      // title을 내용으로 함
      &lt;/li&gt;)
  }
  return &lt;nav&gt;
    &lt;ol&gt;
      {lis}
    &lt;/ol&gt;
  &lt;/nav&gt;
}

function App() {
  const topics = [    // 객체 배열 생성
    {id : 1, title: &#39;html&#39;, body: &#39;html is...&#39;},
    {id : 2, title: &#39;css&#39;, body: &#39;css is...&#39;},
    {id : 3, title: &#39;javascript&#39;, body: &#39;javascript is...&#39;}
  ]
  return (
    &lt;div className=&quot;App&quot;&gt;
      &lt;Header title = &#39;WEB&#39;/&gt;
      &lt;Nav topics = {topics}/&gt;
      &lt;Article title = &#39;Welcome&#39; body = &#39;Hello, WEB&#39;/&gt;
    &lt;/div&gt;
  );
}</code></pre>
<h1 id="event">Event</h1>
<pre><code class="language-javascript">function Header(props) {
  console.log(&#39;props&#39;, props, props.title);
  return &lt;header&gt;
    &lt;h1&gt;&lt;a href = &quot;/&quot; onClick = {(event) =&gt; { // callback 함수. arrow function
      event.preventDefault(); // 기본 동작 방지 =&gt; 클릭해도 리로드 X
      props.onChangeMode();
    }}&gt;{props.title}&lt;/a&gt;&lt;/h1&gt;
  &lt;/header&gt;
}

function Nav(props) {
  const lis = []
  for(let i = 0; i &lt; props.topics.length; i++){
    let t = props.topics[i];
    lis.push(&lt;li key = {t.id}&gt;
      &lt;a id = {t.id} href = {&quot;/read/&quot; + t.id} onClick = {(event) =&gt; {
        event.preventDefault();
        props.onChangeMode(event.target.id);  
        // event 객체가 가지고 있는 event를 유발시킨 태그 : target
        }}&gt;
      {t.title}&lt;/a&gt;
    &lt;/li&gt;)
  }
  return &lt;nav&gt;
    &lt;ol&gt;
      {lis}
    &lt;/ol&gt;
  &lt;/nav&gt;
}

function App() {
  //
  return (
    &lt;div className=&quot;App&quot;&gt;
      &lt;Header title = &#39;WEB&#39; onChangeMode = {() =&gt; {
        alert(&#39;Header&#39;);
      }}/&gt;
      &lt;Nav topics = {topics} onChangeMode = {(id) =&gt; {
        alert(id);
      }}/&gt;
      &lt;Article title = &#39;Welcome&#39; body = &#39;Hello, WEB&#39;/&gt;
    &lt;/div&gt;
  );
}</code></pre>
<h1 id="state">State</h1>
<blockquote>
<p>prop: 컴포넌트를 사용하는 외부자를 위한 data
state: 컴포넌트를 만드는 내부자를 위한 data</p>
</blockquote>
<pre><code class="language-javascript">import { useState } from &#39;react&#39;;

function Nav(props) {
  const lis = []
  for(let i = 0; i &lt; props.topics.length; i++){
    let t = props.topics[i];
    lis.push(&lt;li key = {t.id}&gt;
      // t.id는 원래 숫자. 하지만 태그의 속성에 들어가는 순간 문자가 됨.
      &lt;a id = {t.id} href = {&quot;/read/&quot; + t.id} onClick = {(event) =&gt; {
        event.preventDefault();
        props.onChangeMode(Number(event.target.id));
        // Number로 변환 안 해주면 문자열 값.
        }}&gt;
      {t.title}&lt;/a&gt;
    &lt;/li&gt;)
  }
  return &lt;nav&gt;
    &lt;ol&gt;
      {lis}
    &lt;/ol&gt;
  &lt;/nav&gt;
}

function App() {
  /*
  const _mode = useState(&#39;WELCOME&#39;);    // 초기값 설정
  const mode = _mode[0];    // 상태의 값을 읽음
  const setMode = _mode[1];    // 상태의 값을 변경할 때 사용하는 함수
  console.log(&#39;_mode&#39;, _mode);
  */
  const [mode, setMode] = useState(&#39;WELCOME&#39;);    // 간단하게 표현
  const [id, setId] = useState(null);
  const topics = [
    {id : 1, title: &#39;html&#39;, body: &#39;html is...&#39;},
    {id : 2, title: &#39;css&#39;, body: &#39;css is...&#39;},
    {id : 3, title: &#39;javascript&#39;, body: &#39;javascript is...&#39;}
  ]
  let content = null;
  if (mode === &#39;WELCOME&#39;){
    content = &lt;Article title = &#39;Welcome&#39; body = &#39;Hello, WEB&#39;&gt;&lt;/Article&gt;
  } else if (mode === &#39;READ&#39;) {
    let title, body = null;
    for(let i = 0; i &lt; topics.length; i++){
      if(topics[i].id === id){
        title = topics[i].title;
        body = topics[i].body;
      }
    }
    content = &lt;Article title = {title} body = {body}&gt;&lt;/Article&gt;
  }
  return (
    &lt;div className=&quot;App&quot;&gt;
      &lt;Header title = &#39;WEB&#39; onChangeMode = {() =&gt; {
        setMode(&#39;WELCOME&#39;);
      }}/&gt;
      &lt;Nav topics = {topics} onChangeMode = {(id) =&gt; {
        setMode(&#39;READ&#39;);
      }}/&gt;
      {content}
    &lt;/div&gt;
  );
}</code></pre>
<h1 id="crud">CRUD</h1>
<h2 id="create">Create</h2>
<pre><code class="language-javascript">function Create(props) {
  return &lt;article&gt;
    &lt;h2&gt;Create&lt;/h2&gt;
    &lt;form onSubmit = {(event) =&gt; {
      event.preventDefault();
      const title = event.target.title.value;
      const body = event.target.body.value;
      props.onCreate(title, body);
    }}&gt;
      // 각각 다른 줄에 표현하기 위해 p 태그 사용
      &lt;p&gt;&lt;input type = &#39;text&#39; name = &#39;title&#39; placeholder = &#39;title&#39; /&gt;&lt;/p&gt;
      &lt;p&gt;&lt;textarea name = &#39;body&#39; placeholder = &#39;body&#39; /&gt;&lt;/p&gt;
      &lt;p&gt;&lt;input type = &#39;submit&#39; value = &#39;Create&#39; /&gt;&lt;/p&gt;
    &lt;/form&gt;
  &lt;/article&gt;
}

function App() {
  const [mode, setMode] = useState(&#39;WELCOME&#39;);
  const [id, setId] = useState(null);
  const [nextId, setNextId] = useState(4);
  const [topics, setTopics] = useState([
    {id : 1, title: &#39;html&#39;, body: &#39;html is...&#39;},
    {id : 2, title: &#39;css&#39;, body: &#39;css is...&#39;},
    {id : 3, title: &#39;javascript&#39;, body: &#39;javascript is...&#39;}
  ]);
  let content = null;
  if (mode === &#39;WELCOME&#39;){
    content = &lt;Article title = &#39;Welcome&#39; body = &#39;Hello, WEB&#39;&gt;&lt;/Article&gt;
  } else if (mode === &#39;READ&#39;) {
    let title, body = null;
    for(let i = 0; i &lt; topics.length; i++){
      if(topics[i].id === id){
        title = topics[i].title;
        body = topics[i].body;
      }
    }
    content = &lt;Article title = {title} body = {body}&gt;&lt;/Article&gt;
  } else if (mode === &#39;CREATE&#39;) {
    content = &lt;Create onCreate = {(_title, _body) =&gt; {
      const newTopic = {id: nextId, title: _title, body: _body}
      const newTopics = [...topics] // 복제본 생성
      newTopics.push(newTopic);
      setTopics(newTopics);
      setMode(&#39;READ&#39;);
      setId(nextId);
      setNextId(nextId + 1);
    }}/&gt;
  }
  return (
    &lt;div className=&quot;App&quot;&gt;
      &lt;Header title = &#39;WEB&#39; onChangeMode = {() =&gt; {
        setMode(&#39;WELCOME&#39;);
      }}/&gt;
      &lt;Nav topics = {topics} onChangeMode = {(_id) =&gt; {
        setMode(&#39;READ&#39;);
        setId(_id);
      }}/&gt;
      {content}
      &lt;a href = &#39;/create&#39; onClick = {(event) =&gt; {
        event.preventDefault();
        setMode(&#39;CREATE&#39;);
      }}&gt;Create&lt;/a&gt;
    &lt;/div&gt;
  );
}</code></pre>
<h2 id="update">Update</h2>
<pre><code class="language-javascript">function Update(props) {
  // useState 사용하여 업데이트
  const [title, setTitle] = useState(props.title);
  const [body, setBody] = useState(props.body);
  return &lt;article&gt;
    &lt;h2&gt;Update&lt;/h2&gt;
    &lt;form onSubmit = {(event) =&gt; {
      event.preventDefault();
      const title = event.target.title.value;
      const body = event.target.body.value;
      props.onUpdate(title, body);
    }}&gt;
      // onChange 속성 함수로 변경 내용 실시간 반영
      &lt;p&gt;&lt;input type = &#39;text&#39; name = &#39;title&#39; placeholder = &#39;title&#39; value = {title} onChange = {(event) =&gt; {
        setTitle(event.target.value);
      }}/&gt;&lt;/p&gt;
      &lt;p&gt;&lt;textarea name = &#39;body&#39; placeholder = &#39;body&#39; value = {body} onChange = {(event) =&gt; {
        setBody(event.target.value);
      }}/&gt;&lt;/p&gt;
      &lt;p&gt;&lt;input type = &#39;submit&#39; value = &#39;Update&#39; /&gt;&lt;/p&gt;
    &lt;/form&gt;
  &lt;/article&gt;
}

function App() {
  //
  let content = null;
  let contextControl = null;    // READ 모드일 때만 확인 가능한 context
  if (mode === &#39;WELCOME&#39;){
    content = &lt;Article title = &#39;Welcome&#39; body = &#39;Hello, WEB&#39;&gt;&lt;/Article&gt;
  } else if (mode === &#39;READ&#39;) {
    let title, body = null;
    for(let i = 0; i &lt; topics.length; i++){
      if(topics[i].id === id){
        title = topics[i].title;
        body = topics[i].body;
      }
    }
    content = &lt;Article title = {title} body = {body}&gt;&lt;/Article&gt;
    contextControl = &lt;li&gt;&lt;a href = {&#39;/update/&#39; + id} onClick = {(event) =&gt; {
      event.preventDefault();
      setMode(&#39;UPDATE&#39;);
    }}&gt;Update&lt;/a&gt;&lt;/li&gt;
  } else if (mode === &#39;CREATE&#39;) {
    //
  } else if (mode === &#39;UPDATE&#39;) {
    let title, body = null;
    for(let i = 0; i &lt; topics.length; i++){
      if(topics[i].id === id){
        title = topics[i].title;
        body = topics[i].body;
      }
    }
    content = &lt;Update title = {title} body = {body} onUpdate = {(title, body) =&gt; {
      const newTopics = [...topics]
      const updatedTopic = {id: id, title: title, body: body}
      for(let i = 0; i &lt; newTopics.length; i++){
        if(newTopics[i].id === id){
          newTopics[i] = updatedTopic;
          break;
        }
      }
      setTopics(newTopics);
      setMode(&#39;READ&#39;);
    }}/&gt;
  }
  return (
    //
      &lt;ul&gt;
        &lt;li&gt;&lt;a href = &#39;/create&#39; onClick = {(event) =&gt; {
          event.preventDefault();
          setMode(&#39;CREATE&#39;);
        }}&gt;Create&lt;/a&gt;&lt;/li&gt;
        {contextControl}
      &lt;/ul&gt;
    &lt;/div&gt;
  );
}</code></pre>
<h2 id="delete">Delete</h2>
<pre><code class="language-javascript">else if (mode === &#39;READ&#39;) {
    let title, body = null;
    for(let i = 0; i &lt; topics.length; i++){
      if(topics[i].id === id){
        title = topics[i].title;
        body = topics[i].body;
      }
    }
    content = &lt;Article title = {title} body = {body}&gt;&lt;/Article&gt;
    contextControl = &lt;&gt;
      &lt;li&gt;&lt;a href = {&#39;/update/&#39; + id} onClick = {(event) =&gt; {
        event.preventDefault();
        setMode(&#39;UPDATE&#39;);
      }}&gt;Update&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;input type = &#39;button&#39; value = &#39;Delete&#39; onClick = {() =&gt; {
        const newTopics = []
        for(let i = 0; i &lt; topics.length; i++){
          // 현재 id에 해당하지 않는 topics의 id들만 newTopics 배열에 push
          if(topics[i].id !== id){
            newTopics.push(topics[i]);
          }
        }
        setTopics(newTopics);
        setMode(&#39;WELCOME&#39;);
      }} /&gt;&lt;/li&gt;
    &lt;/&gt;
  } </code></pre>
<hr>
<blockquote>
<p>생활코딩 React 강의 2022 개정판
<a href="https://youtu.be/AoMv0SIjZL8">https://youtu.be/AoMv0SIjZL8</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React Native] React Navigation 사용하기]]></title>
            <link>https://velog.io/@chez_kwak/React-Native-React-Navigation-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@chez_kwak/React-Native-React-Navigation-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0</guid>
            <pubDate>Fri, 29 Jul 2022 06:44:40 GMT</pubDate>
            <description><![CDATA[<h2 id="react-navigation">React-Navigation</h2>
<h3 id="navigate-vs-replace">navigate VS replace</h3>
<ul>
<li>navigate: stack 중에 screen이 있으면 그걸 찾아서 간다.</li>
<li>replace: 새롭게 replace한다.</li>
</ul>
<p>나는 거의 navigate로 사용했는데 그러다보니까 예를 들어 노트를 삭제했는데 삭제 후 다시 리스트로 돌아가도록 navigate 메소드를 사용하면, 삭제된 노트도 리스트에서 계속 확인이 됐다.
그래서 replace로 바꾸어주었더니, 바로바로 동기화 완료.</p>
<h3 id="passing-params">Passing Params</h3>
<ul>
<li>넘겨줄 때
: 가장 중요한 건 제일 바깥쪽 export할 function의 인자로, { navigation, route } 를 넣어주는 것이다. 이게 없으면! 안 돌아간다.<pre><code class="language-javascript">navigation.navigate(&#39;Note&#39;, {
  noteId: response.data.result[&#39;note_id&#39;],
  categoryName: category,
  userId: userId,
  fromUpload: true
})</code></pre>
</li>
<li>받아올 때
: 여기도 마찬가지로 navigation, route 설정해주기.<pre><code class="language-javascript">useEffect(() =&gt; {
  setUserId(route.params.userId);
  setCategory(route.params.categoryName);
  setNoteId(route.params.noteId);
  setFromUpload(route.params.fromUpload);
}, [noteId]);</code></pre>
</li>
</ul>
<hr>
<p>참고 공식 문서 -&gt; <a href="https://reactnavigation.org/docs/getting-started/">React Navigation</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React Native] 로그인 네비게이션 로직 분리 + 로그아웃]]></title>
            <link>https://velog.io/@chez_kwak/React-Native-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EB%84%A4%EB%B9%84%EA%B2%8C%EC%9D%B4%EC%85%98-%EB%A1%9C%EC%A7%81-%EB%B6%84%EB%A6%AC-%EB%A1%9C%EA%B7%B8%EC%95%84%EC%9B%83</link>
            <guid>https://velog.io/@chez_kwak/React-Native-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EB%84%A4%EB%B9%84%EA%B2%8C%EC%9D%B4%EC%85%98-%EB%A1%9C%EC%A7%81-%EB%B6%84%EB%A6%AC-%EB%A1%9C%EA%B7%B8%EC%95%84%EC%9B%83</guid>
            <pubDate>Fri, 29 Jul 2022 06:15:12 GMT</pubDate>
            <description><![CDATA[<h2 id="asyncstorage-사용">AsyncStorage 사용</h2>
<ul>
<li>로그인 화면에서 다음과 같이 AsyncStorage를 이용해 user_id를 저장해주었다.<ul>
<li>user_id는 key값. value값을 저장할 때는 JSON.stringify를 써줘야한다. key, value 모두 string값이어야 하기 때문이다.<pre><code class="language-javascript">const saveId = async id =&gt; {
  try {
      await AsyncStorage.setItem(&#39;user_id&#39;, JSON.stringify(id));
  } catch (e) {
      console.error(e);
  }
}</code></pre>
</li>
</ul>
</li>
</ul>
<h2 id="로그인-여부-받아오기">로그인 여부 받아오기</h2>
<ul>
<li>AsyncStorage 안에 user_id가 저장되어 있는지 아닌지로 로그인 여부를 판단했다. <pre><code class="language-javascript">const [isLogin, setIsLogin] = useState(false);
const getLogin = async () =&gt; {
  if(await AsyncStorage.getItem(&#39;user_id&#39;)!== null){
      setIsLogin(true);
  }
}
useEffect(() =&gt; {
  getLogin();
});</code></pre>
</li>
<li>그 뒤, isLogin 값에 따라 navigation stack 분리<pre><code class="language-javascript">{
  isLogin ? (
      &lt;&gt;
      &lt;Stack.Screen name = &#39;TabNavigator&#39; component = {TabNavigator} /&gt; 
      &lt;/&gt;   
  ) : (
      &lt;&gt;
      &lt;Stack.Screen name = &#39;SignInStack&#39; component = {SignInStack} /&gt;
      &lt;Stack.Screen name = &#39;TabNavigator&#39; component = {TabNavigator} /&gt;
      &lt;/&gt;
  )
}</code></pre>
</li>
</ul>
<p>로그인 여부에 따라 navigation 나눈 자세한 코드는 다음 링크 참고 -&gt; <a href="https://velog.io/@chez_kwak/React-Native-Nesting-navigator-with-stack-and-tab">Navigator 구성</a></p>
<h2 id="로그아웃">로그아웃</h2>
<p>마지막으로 로그아웃! 내가 이놈의 로그아웃 때문에 얼마나 고생했는지 모른다. 내가 navigation stack을 요상하게 쌓아놓는 바람에 navigation 메소드로 넘어가는 걸 포기하고 앱 리로딩이 되도록 만들었다.. 아직도 해결 방법을 못 찾아 그냥 앱 restart하기로 했다.</p>
<ul>
<li>로그아웃 시에는 AsyncStorage에 저장해두었던 값을 지우도록 AsyncStorage.clear() 사용해주기.<pre><code class="language-javascript">const logout = async () =&gt; {
  try {
      AsyncStorage.clear();
      restart(); // 이 부분에 로그아웃 네비게이션
  } catch (error) {
      console.log(error);
  }
};</code></pre>
restart() 대신 navigation method나 자기가 원하는 화면으로 넘어가도록 잘 설정해주면 된다.
혹시 앱을 리로드하고 싶은 사람들을 위해 참고하시라고 코드 올려놓는다.<pre><code class="language-javascript">import * as Update from &#39;expo-updates&#39;;
</code></pre>
</li>
</ul>
<p>export default () =&gt; Update.reloadAsync();
```</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React Native] Nesting navigator with stack and tab]]></title>
            <link>https://velog.io/@chez_kwak/React-Native-Nesting-navigator-with-stack-and-tab</link>
            <guid>https://velog.io/@chez_kwak/React-Native-Nesting-navigator-with-stack-and-tab</guid>
            <pubDate>Fri, 29 Jul 2022 06:04:43 GMT</pubDate>
            <description><![CDATA[<h2 id="react-navigation">React Navigation</h2>
<p>React Native로 앱을 개발하면서 가장 어려움이 많았던 부분은 간단해 보이던 navigator였다.
우선 나는 stack navigator와 tab navigator를 사용할 예정이었기 때문에 모듈을 다운로드했다.</p>
<pre><code class="language-shell">npm add @react-navigation/native
expo install react-native-gesture-handler react-native-reanimated react-native-screens react-native-safe-area-context @react-native-community/masked-view
npm add @react-navigation/stack
npm add @react-navigation/bottom-tabs</code></pre>
<p>내가 구성한 navigation을 살펴보면</p>
<pre><code>StackNavigator
    ㄴSignInStack
    ㄴCameraStack
    ㄴAlbumStack
    ㄴMypageStack

TabNavigator
    ㄴCameraStack
    ㄴAlbumStack
    ㄴMypageStack

MainNavigator
    ㄴSignInStack
    ㄴTabNavigator</code></pre><p>로그인을 하고 나면 tab navigator 화면으로 넘어가야 하기 때문에, main navigator를 두 가지 스택으로 분리하였다.
각 Tab 별로 stack을 쌓아 tab 속 screen을 관리하였다.</p>
<h3 id="stack-navigator">Stack Navigator</h3>
<pre><code class="language-javascript">import { createNativeStackNavigator } from &#39;@react-navigation/native-stack&#39;;

const Stack = createNativeStackNavigator();

export function SignInStack() {
    return (
        &lt;Stack.Navigator
            screenOptions = {({ route }) =&gt; ({ headerShown: false })}
        &gt;
            &lt;Stack.Screen name = {SignInName} component = {SignInScreen} /&gt;
            &lt;Stack.Screen name = {SignUpName} component = {SignUpScreen} /&gt;
        &lt;/Stack.Navigator&gt;
    )
}</code></pre>
<p>위와 같은 방식으로 다른 Stack들도 구성해주었다.</p>
<ul>
<li>screenoptions: <code>route</code>를 넣어준 이유는, 메소드를 사용해 screen별로 이동하고 route.params로 parameter를 넘겨주기 위해서다.
그리고 나는 header를 따로 만들었기 때문에 navigation 기본 헤더는 가려주었다.</li>
</ul>
<h3 id="tab-navigator">Tab Navigator</h3>
<pre><code class="language-javascript">import { NavigationContainer } from &#39;@react-navigation/native&#39;;
import { createBottomTabNavigator } from &#39;@react-navigation/bottom-tabs&#39;;
import { CameraStack, AlbumStack, MypageStack } from &#39;./StackNavigator&#39;;

const Tab = createBottomTabNavigator();

&lt;NavigationContainer
    independent = {true}
&gt;
    &lt;Tab.Navigator
        screenOptions = {({ route }) =&gt; ({ headerShown: false })}
        initialRouteName = &#39;AlbumStack&#39;
    &gt;
        &lt;Tab.Screen name = &#39;CameraStack&#39; component = {CameraStack} 
            options = {{
                tabBarShowLabel: false,
                tabBarIcon: () =&gt; (
                    &lt;Image source = {images.camera} /&gt;
                ),
                unmountOnBlur: true,
            }} /&gt;
        // 나머지 tab screen도 위와 같이 구성
        &lt;/Tab.Navigator&gt;
&lt;/NavigationContainer&gt;</code></pre>
<ul>
<li>전체를 navigation container로 감싸주어야 작동한다. nested navigator 구성이기 때문에 independent = {true} 설정도 필요</li>
<li>TabNavigator 전체에도 route가 필요했다. 그리고 마찬가디로 header는 가려줌.</li>
<li>Tab bar label도 필요 없어서 가려줌.</li>
<li>tabBarIcon도 expo vector icon말고 따로 활용하려고 image source 넣어줌</li>
<li>unmountOnBlur: 각 tab 이동하고 나면 tab stack history는 없애려고 true로 설정해줬다.</li>
</ul>
<h3 id="main-navigator">Main Navigator</h3>
<p>로그인 로직을 분리하여 navigator를 구성하기 위해 파일을 따로 빼서 main navigator를 만들어 stack을 쌓았다.</p>
<pre><code class="language-javascript">&lt;NavigationContainer
    independent = {true}
&gt;
    &lt;Stack.Navigator
        screenOptions = {({ route }) =&gt; ({ headerShown: false })}
        initialRouteName = {SignInStack}
    &gt;
    {
        isLogin ? (
            &lt;&gt;
            &lt;Stack.Screen name = &#39;TabNavigator&#39; component = {TabNavigator} /&gt; 
            &lt;/&gt;   
        ) : (
            &lt;&gt;
            &lt;Stack.Screen name = &#39;SignInStack&#39; component = {SignInStack} /&gt;
            &lt;Stack.Screen name = &#39;TabNavigator&#39; component = {TabNavigator} /&gt;
            &lt;/&gt;
        )
    }
    &lt;/Stack.Navigator&gt;
&lt;/NavigationContainer&gt;</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React-Native] Flatlist Navigation]]></title>
            <link>https://velog.io/@chez_kwak/React-Native-Flatlist-Navigation</link>
            <guid>https://velog.io/@chez_kwak/React-Native-Flatlist-Navigation</guid>
            <pubDate>Fri, 29 Jul 2022 03:03:53 GMT</pubDate>
            <description><![CDATA[<h2 id="flatlist">Flatlist</h2>
<p>Flatlist 컴포넌트는 말하자면 스크롤 가능한 리스트라고 볼 수 있다.
나는 메모리스트를 보여주는 데에 사용했다. (grid로도 사용할 수 있다)</p>
<blockquote>
<ul>
<li>ScrollView
스크롤은 ScrollView로도 가능한데, 왜 사용하지 않았는가? 라고 묻는다면, map함수를 사용하기 귀찮았기 때문이다.
나는 메모리스트를 구현해야하는데 ScrollView를 사용한다면 map함수로 각 메모를 돌려줘야하는데, 이 부분이 귀찮아 그냥 map 기능까지 비슷하게 제공하는 flatlist를 사용했다.</li>
</ul>
</blockquote>
<h3 id="props">Props</h3>
<p>Flatlist를 사용할 때 가장 중요한 두 가지 요소는 <code>data</code>와 <code>renderItem</code>이다.</p>
<ul>
<li><p><code>data</code>: 말 그대로 flatlist에 넣을 데이터를 의미한다.
나는 객체 배열을 사용해서 data에 넣었다. 아래는 내가 넣은 data이다. API에서 데이터 받아오는 부분이 조금 복잡해져서 코드가 이렇게 나왔다.
id, title, date를 가지는 객체의 배열이라고 보면 된다.</p>
<pre><code class="language-javascript">const setMemos = (i) =&gt; {
    memos.push({
      id: _noteId[i],
      title: _title[i],
      date: _date[i]
    });
 }

 setNotes(memos);    // notes를 data에 넣음.</code></pre>
</li>
<li><p><code>renderItem</code>: <code>data</code>를 불러오는 callback함수라고 보면 된다.
{ item }은 객체로, render할 data의 item을 의미한다. data가 객체 배열이었으니, item은 그 하나하나의 객체라고 보면 된다.</p>
</li>
</ul>
<pre><code class="language-javascript">  const renderMemo = ({ item }) =&gt; {
    return(
      &lt;TouchableOpacity style = {boxStyles.memo}
        onPress = {() =&gt; navigation.navigate(&#39;Note&#39;, {
          noteId: item.id,    // data의 id
          category: category,
          userId: userId
          })}&gt;
        &lt;View style ={textStyles.InBox}&gt;
          &lt;View style = {boxStyles.important} /&gt;
          &lt;Text style = {{
            marginLeft: 10,
            fontWeight: &#39;bold&#39;,
          }}&gt;
            {item.title}    // data의 title
          &lt;/Text&gt;
        &lt;/View&gt;

        &lt;View&gt;
          &lt;Text 
            style = {{ marginLeft: 35 }}
          &gt;
            {item.date}        // data의 date
          &lt;/Text&gt;
        &lt;/View&gt;
      &lt;/TouchableOpacity&gt;
    );
  }</code></pre>
<ul>
<li><code>keyExtractor</code>: map 함수의 key값처럼 앞의 item에 key를 주는 거라고 볼 수 있다.</li>
</ul>
<h3 id="usage">Usage</h3>
<p>이제 flatlist를 생성해주면 완성.</p>
<pre><code class="language-javascript">&lt;FlatList
    data={notes}
    renderItem = {renderMemo}
    keyExtractor={(item) =&gt; item.id}
/&gt;</code></pre>
<hr>
<p>FlatList 생성 화면은 다음과 같다.
<img src="https://velog.velcdn.com/images/chez_kwak/post/a715a294-3a51-43f9-b6d6-1aa3cc360964/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React Native] Axios로 Django API 연결하기]]></title>
            <link>https://velog.io/@chez_kwak/Axios-React-Native-Axios%EB%A1%9C-API-%EC%97%B0%EA%B2%B0%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@chez_kwak/Axios-React-Native-Axios%EB%A1%9C-API-%EC%97%B0%EA%B2%B0%ED%95%98%EA%B8%B0</guid>
            <pubDate>Fri, 29 Jul 2022 02:26:09 GMT</pubDate>
            <description><![CDATA[<h2 id="axios">Axios</h2>
<p>web -&gt; localhost</p>
<p><strong>하지만 앱을 개발할 때는 ios simulator, android emulator를 돌리기 때문에, web의 localhost로 할 때는 연결이 되지 않는다.</strong>
따라서, ios와 android 에뮬레이터의 IP 주소를 따로 설정해주어야 한다.
ios -&gt; 127.0.0.1
andriod -&gt; 10.0.2.2</p>
<p>(만약 안 된다면 settings.py에서 ALLOWED_HOST[*]로 바꿔주면 된다)</p>
<p>나는 ios simulator로 개발했기 때문에 ios 기준으로 얘기하겠다.
일단 API 연결 전에, 백엔드에서 Response Body를 지정해주었다.</p>
<pre><code class="language-json">{
    &quot;success&quot; : true,
    &quot;result&quot; : [~],
    &quot;status&quot; : 200
}</code></pre>
<p>axios를 매번 import하는 것보다는 api 파일을 따로 만들었다.</p>
<pre><code class="language-javascript">import axios from &#39;axios&#39;;

const API = axios.create({
    baseURL: &#39;http://127.0.0.1:8000/api&#39;,
    headers: {
        &#39;Content-Type&#39; : &#39;application/json&#39;,
    },
});

export default API;</code></pre>
<h3 id="post">Post</h3>
<p>Create</p>
<ul>
<li><p>bodyData는 하나의 객체로 전송했다.</p>
</li>
<li><p>지정해준 response.data.success가 true로 나오면 navigation method가 작동되도록 설정했다.</p>
<pre><code class="language-javascript">const saveNote = async () =&gt; {
      const data = {
          user_id: userId,
          title: title,
          date: new Date(),
          contents: contents,
          category_id: categoryId,
      }

      try {
          const response = await API.post(
              `/notes`,
              data
          )
          .then(function (response) {
              if (response.data[&#39;success&#39;] == true) {
                  navigation.navigate(&#39;Note&#39;, {
                      noteId: response.data.result[&#39;note_id&#39;],
                      categoryName: category,
                      userId: userId,
                      fromUpload: true
                  })
              }
          })
          .catch(function (error) {
              console.log(error.response);
          });
      } catch (error) {
          console.log(error);
      }
  }</code></pre>
<h3 id="get">Get</h3>
<p>Read</p>
</li>
<li><p>get에는 bodyData를 전송할 필요가 없다. API를 받아오는 목적이기 때문이다.</p>
</li>
<li><p>get api를 성공했다면, 각각 필요한 데이터를 useState 값으로 넣어주었다.</p>
<pre><code class="language-javascript">const getNotes = async () =&gt; {
      try {
          await API.get(
              `/notes/${noteId}`
          )
          .then(function (response) {
              if (response.data[&#39;success&#39;] == true) {
                  setTitle(response.data.result[&#39;title&#39;]);
                  setContents(response.data.result[&#39;contents&#39;]);
                  setSummary(response.data.result[&#39;summary&#39;]);
                  for(let i = 0; i &lt; response.data.result.keywords.length; i++){
                      _keyword.push(response.data.result.keywords[i][&#39;keyword&#39;]);
                  }
                  setKeywords(keywords.concat(_keyword));
              }
          })
          .catch(function (error) {
              console.log(error.response);
          })
      } catch (error) {
          console.log(error);
      }
  }</code></pre>
</li>
</ul>
<h3 id="put">Put</h3>
<p>Update</p>
<ul>
<li><p>Put은 Get + Post라고 볼 수 있다.</p>
</li>
<li><p>bodyData는 post와 같은 형식으로 지정해주었다.</p>
<pre><code class="language-javascript">const modifyNote = async () =&gt; {
      const data = {
          user_id: userId,
          title: title,
          contents: contents,
          date: new Date(),
          category_id: categoryId + 1,
      }

      try {
          const response = await API.put(
              `/notes/${noteId}`,
              data
          )
              .then(function (response) {
                  if (response.data[&#39;success&#39;] == true) {
                      navigation.replace(&#39;Note&#39;, {
                          noteId: response.data.result[&#39;note_id&#39;],
                          categoryName: category,
                          userId: userId,
                          fromUpload: fromUpload
                      });
                  }
              })
              .catch(function (error) {
                  console.log(error.response);
              });
      } catch (error) {
          console.log(error);
      }
  }</code></pre>
<h3 id="delete">Delete</h3>
<p>Delete</p>
</li>
<li><p>삭제 시에는 bodyData를 지정할 필요가 없었다.</p>
</li>
<li><p>그리고 response data를 주지 않는다. 백엔드 쪽에서도 204 No content를 status로 지정해주었다.</p>
</li>
</ul>
<pre><code class="language-javascript">const deleteNote = async () =&gt; {
        try {
            await API.delete(
                `/notes/${noteId}`
            )
            .then(response =&gt; {
                if(response.status === 204){
                    console.log(&#39;delete&#39;);
                    fromUpload ? (
                        navigation.replace(&#39;Camera&#39;)
                    ) : (
                        navigation.replace(&#39;List&#39;, {
                            categoryName: categoryName,
                            userId: userId
                        })
                    )
                }
            })
            .catch(function (error) {
                console.log(error);
            });
        } catch (error) {
            console.error(error);
        }
    }</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React Native] Picker 사용]]></title>
            <link>https://velog.io/@chez_kwak/React-Native-Picker-%EC%82%AC%EC%9A%A9</link>
            <guid>https://velog.io/@chez_kwak/React-Native-Picker-%EC%82%AC%EC%9A%A9</guid>
            <pubDate>Thu, 28 Jul 2022 12:31:01 GMT</pubDate>
            <description><![CDATA[<h2 id="react-native-picker">react-native-picker</h2>
<pre><code class="language-shell">npm install @react-native-picker/picker</code></pre>
<p>위와 같은 명령어로 install
<a href="https://github.com/react-native-picker/picker">https://github.com/react-native-picker/picker</a></p>
<p><del>멍청한 짓 하지 말자. 꼭 node_modules 깔려있는 디렉토리 확인하고 거기에 설치. cd frontend 안 하고 전체에 설치하려는 멍청한 짓으로 2시간 가량 오류 잡다가 날림^^</del></p>
<p>picker를 사용하려면 코드는 다음과 같이 작성</p>
<pre><code class="language-javascript">import { Picker } from &#39;@react-native-picker/picker&#39;;


const [category, setCategory] = useState(&#39;diary&#39;);

return (
    &lt;Picker
        selectedValue = {category}
        onValueChange = {(itemValue, itemIndex) =&gt; 
        setCategory(itemValue)
        }
        style = {{
            width: 200,
            height: 50,
        }}&gt;
        &lt;Picker.item label = &#39;Diary&#39; value = &#39;diary&#39; /&gt;
        &lt;Picker.item label = &#39;Todo&#39; value = &#39;todo&#39; /&gt;
        &lt;Picker.item label = &#39;Study&#39; value = &#39;study&#39; /&gt;
    &lt;/Picker&gt;
);
</code></pre>
<p>그러나 이 picker는 커스텀하기도 힘들고 딱 밑으로 떨어지는 dropdown을 원했는데 약간 scroll 형식이라 옆에 글씨 놓고 디자인 맞추고 싶었던 나에겐 부적절. 그래서 찾은 게 아래의 picker.</p>
<h2 id="react-native-dropdown-picker">react-native-dropdown-picker</h2>
<pre><code class="language-shell">npm install react-native-dropdown-picker</code></pre>
<p>이거는 앞에 picker보다 개인적으로 디자인은 별로지만 커스텀이 쉽고 전반적으로 내가 원하던 디자인으로 페이지 구성할 수 있어서 선택.</p>
<p>CustomPicker라는 컴포넌트를 구성해, screen에서 불러와 설정할 수 있도록 했다.</p>
<pre><code class="language-javascript">import DropDownPicker from &#39;react-native-dropdown-picker&#39;;

const CustomPicker = ({ open, setOpen, value, setValue, items, setItems, onChangeValue, placeholder }) =&gt; {
    return (
        &lt;DropDownPicker
            open = {open}
            value = {value}
            items = {items}
            setOpen = {setOpen}
            setValue = {setValue}
            setItems = {setItems}
            onChangeValue = {onChangeValue}
            containerStyle = {{
                width: 200,
            }}
            placeholder = {placeholder}
            dropDownDirection = &quot;BOTTOM&quot;
            style = {{
                marginBottom: open ? 100 : 10
            }}
            listItemContainerStyle = {{
                height: 30,
            }}
        /&gt;
    );
}

export default CustomPicker;</code></pre>
<pre><code class="language-javascript">&lt;CustomPicker
    open = {open}
    value = {category}
    items = {items}
    setOpen = {setOpen}    // true, false value
    setValue = {setCategory}
    setItems = {setItems}
    onChangeValue = {() =&gt; getIndex(category)}
    placeholder = &quot;Select a category&quot;
/&gt;</code></pre>
<p>setOpen을 사용한 이유는 open, close 상태에서 밑에 버튼의 위치를 다르게 주고 싶었기 때문이다.</p>
<p>근데 이거 defaultvalue 설정이 잘 안 된다.. 흠..</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[MySQL] Mac에서 MySQL 실행하기 (MySQL Community 서버 설치)]]></title>
            <link>https://velog.io/@chez_kwak/MySQL-Mac%EC%97%90%EC%84%9C-MySQL-%EC%8B%A4%ED%96%89%ED%95%98%EA%B8%B0-MySQL-Community-%EC%84%9C%EB%B2%84-%EC%84%A4%EC%B9%98</link>
            <guid>https://velog.io/@chez_kwak/MySQL-Mac%EC%97%90%EC%84%9C-MySQL-%EC%8B%A4%ED%96%89%ED%95%98%EA%B8%B0-MySQL-Community-%EC%84%9C%EB%B2%84-%EC%84%A4%EC%B9%98</guid>
            <pubDate>Fri, 22 Jul 2022 02:13:41 GMT</pubDate>
            <description><![CDATA[<p>Homebrew로 설치하면 자꾸 pid 오류가 나서 MySQL 공식 홈페이지에서 파일을 받아 설치하였다.
이런 경우에 mysql.server start 명령어가 적용이 안 되기 때문에 다음과 같은 방법으로 실행해야 한다.</p>
<pre><code class="language-shell">cd usr/local/mysql/bin
./mysql -uroot -p</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React-Native] useState 사용 없이 반복문으로 배열 생성하기]]></title>
            <link>https://velog.io/@chez_kwak/useState-%EC%82%AC%EC%9A%A9-%EC%97%86%EC%9D%B4-%EB%B0%98%EB%B3%B5%EB%AC%B8%EC%9C%BC%EB%A1%9C-%EB%B0%B0%EC%97%B4-%EC%83%9D%EC%84%B1%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@chez_kwak/useState-%EC%82%AC%EC%9A%A9-%EC%97%86%EC%9D%B4-%EB%B0%98%EB%B3%B5%EB%AC%B8%EC%9C%BC%EB%A1%9C-%EB%B0%B0%EC%97%B4-%EC%83%9D%EC%84%B1%ED%95%98%EA%B8%B0</guid>
            <pubDate>Mon, 18 Jul 2022 07:46:47 GMT</pubDate>
            <description><![CDATA[<p>useState을 사용해서 배열값을 저장하려다가, 반복문에서는 적용이 되지 않길래 공식문서를 찾아봤다.
알고보니 react hook은 반복문 안에서 적용이 안 된다고 한다... 여태 모르고 삽질하고 있었던지라 한 번 정리해두고자 한다.</p>
<h2 id="최상위에서만-hook-호출">최상위에서만 hook 호출</h2>
<p><strong>반복문, 조건문, 중첩 함수 내에서 hook 호출 불가</strong>
컴포넌트 렌더링 시, 여러 번 hook이 호출되더라도 올바른 상태로 유지될 수 있도록 한다.</p>
<p>이거 때문에 진짜 삽질을 오지게 하고, 굉장히 비효율적인 코드를 만들었다.</p>
<h2 id="usestate-사용하지-않고-반복문으로-배열값-받아오기">useState 사용하지 않고 반복문으로 배열값 받아오기</h2>
<p>일단 이 코드는 카테고리 별로 노트 리스트를 받아오기 위함인데, 이때 flatlist로 노트를 띄워주기 위해 여러 과정을 거쳤다.</p>
<p>우선 아래와 같이 필요한 배열과 변수들을 선언해주었다.</p>
<pre><code class="language-javascript">  const _title = [];
  const _date = [];
  const _noteId = [];
  const [userId, setUserId] = useState(&#39;&#39;);
  const [categoryName, setCategoryName] = useState(&#39;&#39;);
  const [category, setCategory] = useState(&#39;&#39;);
  const [notes, setNotes] = useState(&#39;&#39;);
  const memos = [];</code></pre>
<p>useState를 axios 코드 내의 반복문에 적용할 수 없기에, flatlist의 객체 배열을 만들어주기 위해 각각 원소 배열을 따로 변수 배열에 저장해 받아왔다.
react에서는 javascript의 push 대신 concat이나 map 또는 spread 연산자를 사용하기를 권장하던데.. 나는 concat이나 map을 쓰면 자꾸 오류가 나고, 그냥 push가 편해서 이걸 사용했다.</p>
<pre><code class="language-javascript">  const setMemos = (i) =&gt; {
    memos.push({
      id: _noteId[i], 
      title: _title[i], 
      date: _date[i]
    });
  }

  const getNotes = async () =&gt; {
    try {
      await axios.get(
        `/notes/${userId}/all?category=${category}`
      )
      .then(function (response) {
        if(response.data[&#39;success&#39;] == true) {
          // 반복문을 사용해서 각 메모 별로 title, date, note id를 저장해주었다.
          for(let i = 0; i &lt; response.data.result.length; i++){
            _title.push(response.data.result[i][&#39;title&#39;]);
            _date.push(response.data.result[i][&#39;date&#39;]);
            _noteId.push(response.data.result[i][&#39;note_id&#39;]);
            // setMemos 함수에 객체 배열로 각각의 원소를 저장해주었다.
            setMemos(i);
          }
              // 저장한 memos를 notes에 배열로 넣어주었다.
            setNotes(memos);
        }
      })
      .catch(function (error) {
        console.log(error.response);
      })
    } catch (error) {
      console.log(error);
    }
  };

// 앞서 작성한 Axios와 useEffect를 사용하기 위한 글 참고
  useEffect(()=&gt; {
    setCategory(route.params.category);
    setUserId(route.params.userId);
    getNotes();
  }, [userId, category]);</code></pre>
<hr>
<ul>
<li>또 다른 예시!</li>
</ul>
<p>여기서 keywords는 data 안에 배열로 저장되기 때문에, 이 원소들을 다른 배열에 저장해 받아오는 게 필요했다. 주로 배열을 저장하는 데 사용하던 useState hook은 반복문 안에 사용이 불가능하기 때문에, keyword 배열을 따로 생성해서 push로 데이터를 받아왔다.
그 후, useState 배열에 concat을 활용해 넣어주었다.</p>
<pre><code class="language-javascript">for(let i = 0; i &lt; response.data.result.keywords.length; i++){
      _keyword.push(response.data.result.keywords[i][&#39;keyword&#39;]);
}
setKeywords(keywords.concat(_keyword));</code></pre>
<p>이거는 hashtag를 보여주어야 했기 때문에, 반복문을 돌려 hashtag를 보여주었다. </p>
<pre><code class="language-javascript">var hashtag = [];
    for(let i = 0; i &lt; 5; i++){
        hashtag.push(
            &lt;Text style = {textStyles.hashtag}&gt;#{keywords[i]}&lt;/Text&gt;
        )
    }</code></pre>
<p>(추가) 아 왜 map을 까먹고있었니^^</p>
<hr>
<p>참고) <a href="https://ko.reactjs.org/docs/hooks-rules.html">Hook의 규칙</a></p>
]]></description>
        </item>
    </channel>
</rss>