<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>seul-bean.log</title>
        <link>https://velog.io/</link>
        <description>안녕하세요 성장하는 새싹 프론트엔드 개발자 입니다🌱</description>
        <lastBuildDate>Tue, 17 Oct 2023 14:44:35 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>seul-bean.log</title>
            <url>https://velog.velcdn.com/images/seul-bean/profile/259fe091-ca51-424b-bf1a-aca4da376a9c/social_profile.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. seul-bean.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/seul-bean" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[44일차 리액트 심화주차 (throttling & debouncing)]]></title>
            <link>https://velog.io/@seul-bean/43%EC%9D%BC%EC%B0%A8-15yi0r5x</link>
            <guid>https://velog.io/@seul-bean/43%EC%9D%BC%EC%B0%A8-15yi0r5x</guid>
            <pubDate>Tue, 17 Oct 2023 14:44:35 GMT</pubDate>
            <description><![CDATA[<h1 id="🍎-throttling--debouncing-이란">🍎 Throttling &amp; Debouncing 이란?</h1>
<p>짧은 시간 간격으로 연속해서 이벤트가 발생했을 때 과도한 이벤트 핸들러 호출을 방지하는 기법 (ex. 인스타그램 좋아요 버튼)</p>
<br />

<h2 id="🌳-throttling-이란">🌳 Throttling 이란?</h2>
<p>짧은 시간 간격으로 연속해서 발생한 이벤트들을 일정시간 단위(delay)로 그룹화하여 처음 또는 마지막 이벤트 핸들러만 호출되도록 하는 것</p>
<br />

<h2 id="🌳-debouncing-이란">🌳 Debouncing 이란?</h2>
<p>짧은 시간 간격으로 연속해서 이벤트가 발생하면 이벤트 핸들러를 호출하지 않다가 마지막 이벤트로부터 일정 시간(delay)이 경과한 후에 한 번만 호출하도록 하는 것
주로 사용되는 예: 입력값 실시간 검색, 화면 resize 이벤트</p>
<br />

<blockquote>
<p><strong>메모리 누수(Memory Leack)란?</strong>
필요하지 않은 메모리를 계속 점유하고 있는 현상</p>
</blockquote>
<pre><code class="language-js">import { useEffect, useState } from &quot;react&quot;;
import { useNavigate } from &quot;react-router-dom&quot;;

export default function Home() {
    const navigate = useNavigate();
    let timerId = null;

      const throttle = (delay) =&gt; {
        if (timerId) {
            // timerId가 있으면 바로 함수 종료
              return;
        }
          console.log(`API요청 실행! ${delay}ms 동안 추가요청 안받음`);
          timerId = setTimeout(() =&gt; {
            console.log(`${delay}ms 지남 추가요청 받음`);
              timerId = null;
        }, delay);
    };

      const debounce = (delay) =&gt; {
        if(timerId) {
            // 할당되어 있는 timerId에 해당하는 타이머 제거
              clearTimeout(timerId);
        }
          timerId = setTimeout(()=&gt;{
            // timerId에
        })
    }
}</code></pre>
<br />

<h2 id="🌳-lodash-적용해보기">🌳 lodash 적용해보기</h2>
<pre><code class="language-jsx">import { useState, useCallback } from &quot;react&quot;;
import _ from &quot;lodash&quot;;

function App() {
    const [searchText, setSearchText] = useState(&quot;&quot;);
      const [inputText, setInputText] = useState(&quot;&quot;);

      const handleSearchcText = useCallback(
        _.debounce((text) =&gt; setSearchText(text), 2000),
          []
    );

      const handleChange = (e) =&gt;{
        setInputText(e.target.value);
          handleSearchText(e.target.value);
    };

      return (
        &lt;div style={{paddingLeft: 20, paddingRight: 20,}}&gt;
            &lt;h1&gt;디바운싱 예제&lt;/h1&gt;
            &lt;br /&gt;
            &lt;input
              placeholder=&quot;입력값을 넣고 디바운싱 테스트를 해보세요.&quot;
              style={{ width: &quot;300px&quot; }}
              onChange={handleChange}
              type=&quot;text&quot;
            /&gt;
            &lt;p&gt;Search Text: {searchText}&lt;p&gt;
            &lt;p&gt;Input Text: {inputText}&lt;/p&gt;
        &lt;/div&gt;
    );
}
export default App;</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[43일차 리액트 심화주차 (React Query)]]></title>
            <link>https://velog.io/@seul-bean/43%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@seul-bean/43%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Sun, 15 Oct 2023 14:34:15 GMT</pubDate>
            <description><![CDATA[<h1 id="🍎-react-query">🍎 React Query</h1>
<blockquote>
<p>리액트 쿼리(React Query)는 리액트 애플리케이션 데이터 관리를 위한 상태 관리 라이브러리입니다. 리애트 쿼리는 API 호출, 상태 캐싱, 데이터 업데이트 및 동기화, 오류처리 등을 처리하는 간편하고 직관적인 방식을 제공합니다.</p>
</blockquote>
<h2 id="🌳-주요-키워드">🌳 주요 키워드</h2>
<h3 id="🌱-query">🌱 Query</h3>
<p>어떤 데이터에 대한 요청을 의미.</p>
<h3 id="🌱-mutation">🌱 Mutation</h3>
<p>어떤 데이터를 변경 (추가, 수정, 삭제)</p>
<h3 id="🌱-query-invalidation">🌱 Query Invalidation</h3>
<p>Query를 invalidation. 즉, 무효화 시킨다는 의미.</p>
<blockquote>
<p>무효화 시킨다는 것은?
기존에 가져온 Query는 서버 데이터이기 때문에, 언제든지 변경이 있을 수 있음.
그렇기 때문에 <strong>&#39;최신 상태가 아닐 수&#39;</strong>있다.
→ 기존의 쿼리를 무효화 시킨 후 최신화 시켜야 함.</p>
</blockquote>
<br/>
<br/>

<p><strong>react-query 설치</strong>
<code>yarn add react-query</code></p>
<br/>

<p>*<em>QueryClientProvider *</em>: 데이터를 읽어오는 기능(QueryClient)을 애플리케이션 전체에 주입하도록 하는 API</p>
<pre><code class="language-jsx">// App.jsx

import React from &quot;react&quot;;
import Router from &quot;./shared/Router&quot;;
import { QueryClient, QueryClientProvider } from &quot;react-query&quot;;

const queryClient = new QueryClient();

const App = () =&gt; {
    return (
        &lt;QueryClientProvider client={queryClient}&gt;
            &lt;Router /&gt;;
        &lt;/QueryClientProvider&gt;
    );
};

export default App;</code></pre>
<br />

<h2 id="🌳-조회-기능">🌳 조회 기능</h2>
<pre><code class="language-js">// src&gt;api&gt;todos.js

import axios from &quot;axios&quot;;

// 모든 todos를 가져오는 api
const getTodos = async () =&gt; {
    const response = await axios.get(&quot;http://localhost:3000/todos&quot;);
      return response;
};

export { getTodos };</code></pre>
<pre><code class="language-jsx">// Todolist.jsx

import React from &quot;react&quot;;

import { getTodos } from &quot;../../../api/todos&quot;;
import { useQuery } from &quot;react-query&quot;;

function TodoList({ isActive }){
      // useQuery(Querykey, 비동기 함수)
    const { isLoading, isError, data } = useQuery(&quot;todos&quot;, getTodos);

    if (isLoading) {
        return &lt;p&gt;로딩중입니다&lt;/p&gt;;
    }

      if (isError) {
        return &lt;p&gt;오류가 발생하였습니다&lt;/p&gt;;
    }

      return (
        .
          .
          .
    )
}
</code></pre>
<p><strong>useQuery의 인자에 대해</strong></p>
<p>첫 번째 인자 - Query Keys</p>
<ul>
<li>refetching 하는 데에 쓰인다. (invalidate)</li>
<li>캐싱(caching) 처리를 하는 데에 쓰인다.</li>
<li><strong>애플리케이션 전체 맥락에서 이 쿼리를 공유하는 방법으로 쓰인다.</strong>
(어느 컴포넌트 곳곳에 뿌려져 있어도 같은 key면 같은 쿼리 및 데이터를 보장한다.)</li>
<li>배열의 형태일 수도 있고, nested 객체일 수도 있다.</li>
<li>모든 Query keys는 Unique 해야 한다.</li>
</ul>
<p>두 번째 인자 - 쿼리 함수</p>
<ul>
<li>쿼리 함수는 promise 객체를 return 한다.</li>
<li>promise 객체는 반드시 data를 resolve하거나 에러를 내야 한다.
resove는 정상적으로 통신이 되었음을 의미.</li>
</ul>
<p>useQuery의 결과물 - 객체</p>
<ul>
<li>시작하면, isLoading이 <code>true</code>가 된다.</li>
<li>조회 결과 오류가 나면 isError가 <code>true</code>가 된다. 
isLoading은 <code>false</code>가 된다.</li>
<li>조회 결과 정상이 되면 isSuccess가 <code>true</code>가 된다.
isLoading은 <code>false</code>가 된다.</li>
</ul>
<br />

<h2 id="🌳-추가-기능">🌳 추가 기능</h2>
<pre><code class="language-js">// src &gt; api &gt; todos.js

import axios from &quot;axios&quot;

// .env를 활용하는게 더 바람직 함
const SERVER_URI = &quot;http://localhost:4000&quot;;

const getTodos = async () =&gt; {
    const response = await axios.get(`${SERVER_URI}/todos`);
      return response.data
};

const addTodo = async (newTodo) =&gt; {
    await axios.post(`${SERVER_URI}/todos`, newTodo);
}

export {getTodos, addTodo};</code></pre>
<pre><code class="language-jsx">// Input.jsx

import { addTodo } from &quot;../../../api/todos&quot;;
import { QueryClient, useMutation } from &quot;react-query&quot;;

function Input(){
    const queryClient = new QueryClient();

      const mutation = useMutation(addTodo, {
        onSuccess: () =&gt; {
            // Invalidate and refresh
              // todos라는 이름으로 만들었던 query를 invalidate 할 수 있음
              queryClient.invalidateQueries(&quot;todos&quot;);
        },
    });
}</code></pre>
<blockquote>
<p><strong>invalidate의 과정</strong>
Input.jsx에서 값 입력으로 인해 서버 데이터가 변경됨
→ onSuccess가 일어나면 기존의 Query인 &quot;todos&quot;는 무효화
→ 새로운 데이터를 가져와서 &quot;todos&quot;를 최신화시킴
→ TodoList.jsx를 갱신함
따라서 계속해서 리액트 앱은 최신 상태의 서버 데이터를 유지할 수 있게 된다.</p>
</blockquote>
<blockquote>
<p><strong>무효화라는 뜻이 이해되지 않아서 chatGPT에게 물어본 결과</strong>
<em>캐시된 데이터를 무효화(invalidate)시키면, 다음에 해당 데이터를 요청할 때 라이브러리는 새로운 데이터를 가져오게 됩니다. 이것은 캐시된 데이터를 사용하지 않고 서버로부터 새로운 데이터를 다시 요청하는 효과를 가지게 됩니다. 캐시된 데이터를 가져오지 않고 새로운 데이터를 강제로 다시 가져올 수 있습니다.</em></p>
</blockquote>
<br/>

<p><strong>mutations</strong>
query와는 다르게 mutation은 <strong>CUD</strong>에서 사용된다.</p>
<pre><code class="language-js">function App() {
    const mutation = useMutation(newTodo =&gt; {
        return axios.post(&#39;/todos&#39;, newTodo)
    })
    return (
        &lt;div&gt;
              {mutation.isLoading ? (
                &#39;Adding todo...&#39; 
            ) : (
                &lt;&gt;
                     {mutation.isError?(
                        &lt;div&gt;An error occurred: {mutation.error.message}&lt;/div&gt;
                    ) : null}
                    {mutation.isSuccess ? &lt;div&gt;Todo added!&lt;/div&gt; : null}
                    &lt;button onClick={()=&gt;{
                        mutation.mutate({ id: new Date(), title: &#39;Do Laundry&#39;})
                    }}&gt;
                        create Todo
                    &lt;/button&gt;
                &lt;/&gt;
            )}
          &lt;/div&gt;
    )
}</code></pre>
<p>mutation.mutate(인자)</p>
<ul>
<li>인자는 반드시 한 개의 변수 또는 객체여야 해요.</li>
<li>mutation.mutate(인자1, 인자2) → 오류</li>
</ul>
<p>결과를 객체(object) 형태로 갖고 있다.
그 결과물 객체는 항상 아래 상태 중 하나에 속한다.</p>
<ul>
<li>isIdle</li>
<li>isLoading</li>
<li>isError</li>
<li>isSuccess</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[42일차 리액트 심화주차 (Thunk)]]></title>
            <link>https://velog.io/@seul-bean/42%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@seul-bean/42%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Tue, 10 Oct 2023 14:59:16 GMT</pubDate>
            <description><![CDATA[<h2 id="redux-미들웨어">Redux 미들웨어</h2>
<p>리덕스에서 dispatch를 하면 action 이 리듀서로 전달이 되고, 리듀서는 새로운 state를 반환한다. → 미들웨어를 사용하면 이 과정 사이에 우리가 하고 싶은 작업들을 넣어서 할 수 있다.</p>
<p>리덕스 미들웨어를 사용하는 이유 : 서버와의 통신</p>
<br />
<br />

<h1 id="🍎-thunk">🍎 thunk</h1>
<p>dispatch를 할 때 객체가 아닌 함수를 dispatch 할 수 있게 해준다.</p>
<blockquote>
<p>dispatch (함수) → 함수실행 → 함수 안에서 dispatch (객체)</p>
</blockquote>
<br />

<h3 id="🌱-thunk-사용하기">🌱 thunk 사용하기</h3>
<p><code>createAsyncThunk</code> 라는 API를 사용해서 thunk 함수를 생성할 수 있다.
이 API는 함수인데, 첫 번째 인자에는 Action Value, 두 번째 인자에는 함수가 들어간다.</p>
<p>두 번째 들어가는 함수에서도 인자를 꺼낼 수 있는데, 첫 번째 인자는 이 thunk 함수가 외부에서 사용되었을 때 넣은 값을 여기에서 조회할 수 있고, 두 번째 인자에서는 thunk가 제공하는 여러가지 API 기능들이 담긴 객체를 꺼낼 수 있다.</p>
<pre><code class="language-js">// thunk 함수는 createAsyncThunk 라는 툴킷 API를 사용해서 생성함.

export const __addNumber = createAsyncThunk(
    &quot;ADD_NUMBER_WAIT&quot;,    
    (arg, thunkAPI)=&gt;{},
)</code></pre>
<br />
<br />

<pre><code class="language-js">// src/redux/modules/counterSlice.js

import { createSlice, createAsyncThunk } from &quot;@reduxjs/toolkit&quot;;

export const __addNumber = createAsyncThunk(
    // 첫 번째 인자 : action value
      &quot;addNumber&quot;,
      // 두 번째 인자 : 콜백함수
      (payload, thunkAPI) =&gt; {
        setTimeout(() =&gt; {
            thunkAPI.dispatch(addNumber(payload));
        }, 3000);
    }
);

const initialState = {
    number: 0,
};

const counterSlice = createSlice({
    name: &quot;counter&quot;,
    initialState,
      reducers: {
        addNumber: (state, action) =&gt; {
            state.number = state.number + action.payload;
        },

          minusNumber: (state, action) =&gt; {
            state.number = state.number - action.payload;
        },
    },
});

export const { addNumber, minusNumber } = counterSlice.actions;
export default counterSlice.reducer;</code></pre>
<br />
<br />

<pre><code class="language-jsx">// src/App.jsx

import React from &quot;react&quot;;
import { useState } from &quot;react&quot;;
import { useDispatch, useSelector } from &quot;react-redux&quot;;
import { minusNumber, __addNumber } from &quot;./redux/modules/counterSlce&quot;;

const App = () =&gt; {
    const dipatch = useDispatch();
      const [number, setNumber] = useState(0);
      const globalNumber = useSelector((state) =&gt; state.counter.number);

    const onChangeHandler = (event) =&gt; {
    const { value } = event.target;
    setNumber(+value);
   };

  // thunk 함수를 디스패치한다. payload는 thunk함수에 넣어주면,
  // 리덕스 모듈에서 payload로 받을 수 있다.
  const onClickMinusNumberHandler = () =&gt; {
      dispatch(__addNumber(number));
  };

  const onClickMinusNumberHandler = () =&gt; {
      dispatch(minusNumber(number));
  };

  return (
      &lt;div&gt;
      &lt;div&gt;{globalNumber}&lt;/div&gt;
      &lt;input type=&quot;number&quot; onChange={onChangeHandler} /&gt;
      &lt;button onClick={onClickAddNumberHandler}&gt;더하기&lt;/button&gt;
      &lt;button onClick={onClickMinusNuberHandler}&gt;빼기&lt;/button&gt;
    &lt;/div&gt;
  );
};

export default App;</code></pre>
<br />
<br />

<h2 id="🌳-정리">🌳 정리</h2>
<ul>
<li>리덕스 미들웨어를 사용하면, 액션이 리듀서로 전달되기전에 중간에 어떤 작업을 더 할 수 있다.</li>
<li>Thunk를 사용하면, <strong>객체가 아닌 함수를 dispatch 할 수 있게 해준다.</strong></li>
<li><code>createAsyncThunk()</code>의 첫번째 자리에는 action value, 두번째에는 함수가 들어간다.</li>
<li>두 번째로 들어가는 함수에서 2개의 인자를 꺼내 사용할 수 있는데, 첫 번째 인자는 컴포넌트에서 보내준 payload이고, 두 번째 인자는 thunk에서 제공하는 여러가지 기능이다.</li>
</ul>
<blockquote>
<p>dispatch: thunk 함수안에서 dispatch를 할 때 사용
getState: thunk 함수안에서 현재 리덕스 모듈의 state 값을 사용하고 싶을 때 사용</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[41일차 리액트 심화주차 (비동기 통신, axios interceptor의 개념과 필요성)]]></title>
            <link>https://velog.io/@seul-bean/41%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@seul-bean/41%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Fri, 06 Oct 2023 14:50:09 GMT</pubDate>
            <description><![CDATA[<h1 id="🍎-비동기-통신">🍎 비동기 통신</h1>
<h2 id="🌳-axios">🌳 Axios</h2>
<p><em>&#39; HTTP 클라이언트 라이브러리 &#39;</em>
node.js와 브라우저를 위한 Promise 기반 http 클라이언트
→ http를 이용해서 서버와 통신하기 위해 사용하는 패키지</p>
<h3 id="🌱-axios-설치">🌱 Axios 설치</h3>
<p><code>yarn add axios</code></p>
<h3 id="🌱-get">🌱 GET</h3>
<p><strong>Axios get</strong>
get은 서버의 데이터를 <strong>조회할 때 사용</strong></p>
<pre><code class="language-jsx">// url에는 서버의 url이 들어가고, config에는 기타 여러가지 설정을 추가할 수 있다.
axios.get(url[, config])    // GET</code></pre>
<blockquote>
<p>Axios config 공식문서
<a href="https://axios-http.com/kr/docs/req_config">https://axios-http.com/kr/docs/req_config</a></p>
</blockquote>
<p><strong>우리가 사용하는 json-server API 명세서 확인하기</strong>
전체 정보나 상세 정보는 아래와 같이 path variable로 url을 작성</p>
<p>Plural routes</p>
<pre><code>GET        /posts
GET        /posts/1</code></pre><br />
<br />

<p>filter와 같은 기능을 위해서 GET 요청을 하고자할 때는 query로 보내라고 명시하고 있다.</p>
<p>Filter
use . to access deep properies</p>
<pre><code>GET /posts?title=json-server&amp;author=typicode
GET /posts?id=1&amp;id=2
GET /comments?author.name=typicode</code></pre><br />
<br />

<p>json-server에 있는 todos를 axios를 이용해서 fetching하고 useState를 통해서 관리하는 로직</p>
<pre><code class="language-jsx">// src/App.js
import React, { useEffect, useState } from &quot;react&quot;;
import axios from &quot;axios&quot;;

const App = () =&gt; {
    const [todos, setTodos] = useState(null);

    // axios를 통해서 get 요청을 하는 함수를 생성한다.
    // 비동기처리를 해야하므로 async/await 구문을 통해서 처리한다.
    const fetchTodos = async () =&gt; {
        const { data } = await axios.get(&quot;http://localhost:3001/todos&quot;);
          setTodos(data);    // 서버로부터 fetching한 데이터를 useState의 state로 set 한다
    };

  // 생성한 함수를 컴포넌트가 mount 됐을 때 실행하기 위해 useEffect를 사용한다.
  useEffect(() =&gt; {
    // effect 구문에 생성한 함수를 넣어 실행한다.
    fetchTodos();
  }, []);
}</code></pre>
<br />
<br />

<h3 id="🌱-post">🌱 POST</h3>
<p><strong>Axios POST</strong></p>
<pre><code>axios.post(url[, data[, config]])    // post</code></pre><p>post는 보통 <strong>서버에 데이터를 추가할 때 사용</strong>
보통은 클라이언트의 데이터를 <code>body</code> 형태로 서버에 보내고자 할 때 사용.</p>
<pre><code class="language-jsx">const onSubmitHandler = async(todo) =&gt; {
    // 1. 이때 todos는 [{투두하나}]임
    await axios.post(&quot;http://localhost:3001/todos&quot;, todo);
    // 이때 서버에 있는 todos도 [{투두하나}]임

      // 근데 여기서 서버 요청이 끝나고 서버는 [{투두가}, {두개임}]

      setTodos([...todos, todo])    // 2. 만약 이게 없다면, go to useEffect
      // 4. 새로고침해서 진짜 현재 서버 데이터를 받아오기전에 상태를 똑같이 동기시켜줌
      // 5. 유저한테 서버에서 새로 받아온것처럼
}

useEffect(() =&gt; {
    fetchTodos();    // 3. 새로고침해서 여기를 다시 실행해줘야 서버값이 새로 들어옴 [{투두가}, {두개임}]
}, []);</code></pre>
<br />
<br />

<h3 id="🌱-delete">🌱 DELETE</h3>
<p><strong>Axios delete</strong></p>
<pre><code class="language-jsx">axios.delete(url[, config])    // Delete</code></pre>
<p>DELETE는 저장되어 있는 데이터를 삭제하고자 요청을 보낼 때 사용.</p>
<pre><code class="language-jsx">const onClickDeleteButtonHandler = (todoId) =&gt; {
    axios.delete(`http://localhost:3001/todos/${todoId}`)
}
</code></pre>
<br />
<br />

<h3 id="🌱-patch">🌱 PATCH</h3>
<p><strong>Axios patch</strong></p>
<pre><code class="language-jsx">axios.patch(url[, data[, config]])    // PATCH</code></pre>
<p>patch는 보통 어떤 데이터를 수정하고자 서버에 요청을 보낼 때 사용하는 메서드이다.
http 환경에서 서로가 한 약속이자 문맥이기 때문에, 수정을 하고자 반드시 patch, put을 써야만 하는 것은 아니지만 이러한 약속들을 대부분의 개발자들이 지키고 있다.</p>
<pre><code class="language-jsx">const [editTodo, setEditTodo] = useState({
    title: &quot;&quot;,
});

const onClickEditButtonHandler = (todoId, edit) =&gt; {
    axios.patch(`http://localhost:3001/todos/${todoId}`, edit)
}</code></pre>
<br />
<br />
<br />

<h2 id="🌳-fetch">🌳 Fetch</h2>
<p>Fetch는 ES6부터 도입된 Javascript 내장 라이브러리.
Promise 기반 비동기 통신 라이브러리.</p>
<p><strong>fetch 단점</strong></p>
<ul>
<li>미지원 브라우저 존재</li>
<li>개발자에게 불친절한 response</li>
<li>axios에 비해 부족한 기능</li>
</ul>
<br />
<br />

<h3 id="🌱-fetch와-axios의-차이점">🌱 fetch와 axios의 차이점</h3>
<p><strong>데이터 읽어오기</strong></p>
<p>fetch</p>
<pre><code class="language-jsx">const url = &quot;http://jsonplaceholder.typicode.com/todos&quot;;
fetch(url)
.then((response) =&gt; response.json())    // 한 번 더 json화
.then(console.log);</code></pre>
<p>fetch().then을 한 상태여도 여전히 JSON 포맷의 응답이 아니기 때문에 response.json()을 한 번 더 해주는 과정이 필요하다.
따라서, fetch로 데이터를 요청하는 경우 두 개의 .then()이 필요하다.</p>
<p>axios</p>
<pre><code class="language-jsx">const url = &quot;http://jsonplaceholder.typicode.com/todos&quot;;
axios.get(url).then((response) =&gt; console.log(response.data));</code></pre>
<p>axios는 응답(response)을 기본적으로 JSON 포맷으로 제공한다.</p>
<br />

<p><strong>에러 처리</strong>
fetch</p>
<pre><code class="language-jsx">const url = &quot;https://jsonplaceholder.typicode.com/todos&quot;;

fetch(url)
    .then((response)=&gt;{
        if(!response.ok) {
            throw new Error(
                `This is an HTTP error: The status is ${response.status}`
            );
        }
          return response.json();
    })
    .then(console.log)
    .catch((err) =&gt; {
        console.log(err.message);
    });</code></pre>
<p>axios</p>
<pre><code class="language-jsx">const url = &quot;https://jsonplaceholder.typicode.com/todos&quot;;

axios
    .get(url)
    .then((response) =&gt; console.log(response.data))
    .catch((err) =&gt; {
        console.log(err.message);
    })</code></pre>
<p>axios.get() 요청이 반환하는 Promise 객체가 갖고 있는 상태코드가 2xx의 범위를 넘어가면 거부(reject)를 한다.
따라서, 곧바로 catch() 부분을 통해 error handling이 가능하다.</p>
<pre><code class="language-jsx">const url = &quot;https://jsonplaceholder.typiicode.com/todos&quot;;

// axios 요청 로직
axios
    .get(url)
    .then((response) =&gt; console.log(response.data))
    .catch((err) =&gt; {

      // 오류 객체 내의 response가 존재한다 = 서버가 오류 응답을 주었다
      if (err.response){
            const { status, config } = err.response;

            // 없는 페이지
            if (status === 404) {
                console.log(`${config.url} not found`);
            }
            // 서버 오류
            if (status === 500) {
                console.log(&quot;Server error&quot;);
            }

            // 요청이 이루어졌으나 서버에서 응답이 없었을 경우
      } else if (err.request) {
          console.log(&quot;Error&quot;, err.message);
        // 그 외 다른 에러
      } else {
          console.log(&quot;Error&quot;, err.message);
      }
    });</code></pre>
<p>fetch의 경우, catch()가 발생하는 경우는 오직 네트워크 장애 케이스이다. 
따라서 개발자가 일일히 then() 안에 모든 케이스에 대한 HTTP 에러 처리를 해야한다.</p>
<br />
<br />

<hr>
<br />
<br />

<h1 id="🍎-axios-interceptor의-개념과-필요성">🍎 axios interceptor의 개념과 필요성</h1>
<p>axios interceptor는 다음 두 상황에서 흐름을 가로채서 어떠한 코드 상의 관여를 할 수 있게 한다.</p>
<ol>
<li>요청(request)이 처리되기 전(= http request가 서버에 전달되기 전)</li>
<li>응답(response)의 then(=성공) 또는 catch(=실패)가 처리되기 전
<img src="https://velog.velcdn.com/images/seul-bean/post/2cfa4308-1b66-4116-8e72-5905a0a5e559/image.png" alt=""></li>
</ol>
<p>아래와 같은 요청 및 응답시에 필요한 작업들을 한꺼번에 처리.</p>
<ul>
<li>요청 헤더 추가</li>
<li>인증 관리</li>
<li>로그 관련 로직 삽입</li>
<li>에러 핸들링</li>
</ul>
<br />

<h2 id="🌳-instance-만들기-baseurl-설정하기">🌳 instance 만들기, baseURL 설정하기</h2>
<pre><code class="language-js">const data = axios.get(&quot;http://localhost:4000/&quot;)</code></pre>
<p>인스턴스(instance) :  custom 설정이 되어 있지 않은 완전히 plain axios, 순수 axios</p>
<pre><code class="language-js">// src &gt; axios &gt; api.js

import axios from &quot;axios&quot;;

// axios.create의 입력값으로 들어가는 객체는 configuration 객체이다.

const instance = axios.create({
    baseURL : &quot;http://localhost:4000&quot;,
});

export default instance;</code></pre>
<p>참고주소 <a href="https://axios-http.com/docs/req_config">https://axios-http.com/docs/req_config</a></p>
<blockquote>
<p>axios.create는 Axios 라이브러리에서 사용되는 메서드 중 하나이다. 
이 메서드를 사용하면 Axios의 인스턴스를 생성할 수 있으며, 이를 통해 HTTP 요청을 보내고 응답을 받을 수 있다.</p>
</blockquote>
<pre><code class="language-jsx">// App.jsx

import {useEffect} from &quot;react&quot;;
import api from &quot;./axios/api&quot;;

function App() {
    useEffect(()=&gt;{
        api
            .get(&quot;/cafe&quot;)
              .then((res) =&gt; {
                console.log(&quot;결과 =&gt; &quot;, res.data)
            })
              .catch(() =&gt; {
                console.log(&quot;오류가 발생하였습니다!&quot;)
            });
    }, []);

      return &lt;div&gt;axios 예제&lt;/div&gt;;
}

export default App;
</code></pre>
<p>서버의 정보가 
<a href="http://localhost:4000">http://localhost:4000</a> → <a href="http://localhost:5000">http://localhost:5000</a>
변경이 되어도, api.js 파일만 수정해주면 된다.</p>
<br />

<h2 id="🌳-request-response">🌳 request, response</h2>
<pre><code class="language-js">// src &gt; axios &gt; api.js

import axios from &quot;axios&quot;;

const instance = axios. create({
    baseURL: &quot;http://localhost:4000&quot;,
});

instance.interceptors.request.use(
    function (config) {
        // 요청을 보내기 전 수행
          console.log(&quot;인터셉트 요청 성공!&quot;);
          return config;
    }
      function (error) {
        // 오류 요청을 보내기 전 수행
          console.log(&quot;인터셉트 요청 오류!&quot;);
          return Promise.reject(error);
    }
);

instance.interceptors.response.use(
    function (response) {
        console.log(&quot;인터셉트 응답 받았어요!&quot;);
          // 정상 응답
          return response;
    },

      function (error) {
        console.log(&quot;인터셉트 응답을 받지 못하였어요!&quot;);
          return Promise.reject(error);
    }
);
</code></pre>
<p>요청과 응답 중간에 <strong>가로채서</strong> 어떠한 작업을 수행해 주는 것을 볼 수 있다.</p>
<br />

<h2 id="🌳-더-적용할-수-있는-부분">🌳 더 적용할 수 있는 부분</h2>
<ul>
<li>요청 시, content-type 적용</li>
<li>token 등 인증 관련 로직 적용</li>
<li>서버 응답 코드에 대한 오류 처리(controller)</li>
<li>통신시작 및 종료에 대한 전역 상태를 관리하여 spinner, progress bar 등 구현 가능</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[40일차 리액트 심화주차 (json-server, HTTP)]]></title>
            <link>https://velog.io/@seul-bean/40%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@seul-bean/40%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Wed, 04 Oct 2023 14:59:12 GMT</pubDate>
            <description><![CDATA[<h1 id="🍎-json-server란">🍎 json-server란?</h1>
<p><strong>아주 간단한 DB와 API 서버를 생성해주는 패키지.</strong>
사용하는 이유: Backend에서 실제 DB와 API Server가 구축될 때까지 Frontend 개발에 임시적으로 사용할 mock data를 생성하기 위함.</p>
<h3 id="🌱-설치">🌱 설치</h3>
<p>yarn 또는 npm을 이용해서 설치
<code>yarn add json-server</code></p>
<p>json-server가 간단한 패키지이긴 하나, 말그대로 서버이기 때문에 리액트와는 별개로 따로 실행을 해줘야 한다.
<code>yarn json-server --watch db.json --port 4000</code></p>
<p>명령어를 입력하면, db.json이 자동으로 생성된다.</p>
<blockquote>
<p><strong>package.json에서 script는 어떤 역할을 할까?</strong>
script에서 개발자가 원하는 명령어를 설정할 수 있다.
script에 <code>&quot;start&quot;:&quot;react-scripts start&quot;</code>로 등록이 되어있기 때문에 우리가 <code>yarn start</code>를 입력하는 것만으로도 <code>&quot;react-scripts start&quot;</code>이 실행되는 것</p>
</blockquote>
<br />
<br />

<h1 id="🍎-http">🍎 HTTP</h1>
<p>웹 통신은 서버와 클라이언트간의 대화이다.
<img src="https://velog.velcdn.com/images/seul-bean/post/ef141408-033d-444a-889f-c5ced11aee4a/image.png" alt=""></p>
<p><strong>웹 통신은 약속(=프로토콜)이다</strong></p>
<h3 id="🌱-프로토콜">🌱 프로토콜</h3>
<p>웹에서 서버 - 클라이언트간 주고 받은 상호간의 약속(프로토콜)을 HTTP 프로토콜이라고 한다.</p>
<br />

<h3 id="🌱-요청request과-응답response">🌱 요청(Request)과 응답(Response)</h3>
<p>서버와 클라이언트가 서로 데이터를 주고 받기(대화하기) 위해서는 항상 &#39;요청 (request)&#39;을 해야하고 그에 따른 &#39;응답(response)&#39;을 준다.</p>
<br />

<h3 id="🌱-url에-대해서">🌱 URL에 대해서</h3>
<ul>
<li>protocol</li>
<li>domain(sub domain, domain name)</li>
<li>resource path(path/page)</li>
<li>query variable, path variable
<img src="https://velog.velcdn.com/images/seul-bean/post/075ba874-2708-4cb8-9ad4-1bd94561425e/image.png" alt=""></li>
</ul>
<br />

<h3 id="🌱-메서드">🌱 메서드</h3>
<p>Get - 조회
POST - 생성
PUT, PATCH - 수정(변경)
DELETE - 삭제</p>
<br />

<h3 id="🌱-상태코드">🌱 상태코드</h3>
<p>클라이언트가 서버에 어떤 요청(request)를 하고 나면, 서버는 그에 맞는 응답(response)을 제공한다. 그 때, 각 응답은 상태코드를 갖는다.</p>
<ul>
<li><strong>1xx(정보)</strong> : 요청을 받았으며 프로세스를 계속 진행한다.</li>
<li><strong>2xx(성공)</strong> : 요청을 성공적으로 받았으며 인식했고 수용한다.</li>
<li><strong>3xx(리다이렉션)</strong> : 요청 완료를 위해 추가 작업 조치가 필요하다.</li>
<li><strong>4xx(클라이언트 오류)</strong> : 요청의 문법이 잘못되었거나  요청을 처리할 수 없다.</li>
<li><strong>5xx(서버 오류)</strong> : 서버가 명백히 유효한 요청에 대한 충족을 실패했다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[39일차 Flux 패턴]]></title>
            <link>https://velog.io/@seul-bean/39%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@seul-bean/39%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Mon, 02 Oct 2023 14:51:57 GMT</pubDate>
            <description><![CDATA[<h1 id="🍎-flux-패턴">🍎 Flux 패턴</h1>
<p>Flux 패턴은 소프트웨어 애플리케이션의 상태 관리와 데이터 흐름을 다루는 디자인 패턴 중 하나이다.</p>
<h2 id="🌳-등장하게-된-이유">🌳 등장하게 된 이유</h2>
<p>기존 보편적으로 사용하던 MVC 패턴(Model, View, Controller)이 View가 다양한 상호작용을 위해 여러 개의 Modal을 동시에 업데이트하고 Model 역시 여러 개의 View에 데이터를 전달하는 상황 발생.
→ 많은 의존성을 가지면 Model의 개수가 많아질수록 각 Model에서 발생한 이벤트가 애플리케이션 전체로 퍼져나갈 때 이를 예측하기 힘들어짐. 복잡한 데이터 흐름</p>
<blockquote>
<p><strong>MVC 패턴</strong>
Model에 데이터를 저장하고, Controller를 이용하여 Model의 데이터를 관리.
Model의 데이터가 변경되면 View로 전달되어 사용자에게 보여짐.
사용자가 View를 통해 데이터를 입력하면 View 역시 Model을 업데이트할 수 있다(양방향)</p>
</blockquote>
<br />

<h2 id="🌳-flux-패턴에-대하여">🌳 Flux 패턴에 대하여</h2>
<ol>
<li>사용자 입력을 기반으로 <strong>Action</strong> 생성</li>
<li>Action을 <strong>Dispatcher</strong>에 전달</li>
<li><strong>Store</strong>의 데이터를 변경</li>
<li>View 반영</li>
</ol>
<h3 id="🌱-flux-패턴-요소">🌱 Flux 패턴 요소</h3>
<p>액션 (Action): 사용자 상호작용 또는 시스템 이벤트와 같은 외부 요인으로 인해 애플리케이션 상태, 데이터를 변경하기 위해 Dispatcher에게 전달되는 객체 또는 이벤트.</p>
<p>디스패처 (Dispatcher): 액션을 받아 상태 변경을 관리하고, 이벤트를 등록한 스토어에 전파하는 중앙 허브 역할을 하는 컴포넌트.</p>
<p>스토어 (Store): 애플리케이션의 상태와 비즈니스 로직을 포함하는 곳으로, 상태를 변경하고 앱의 뷰를 업데이트하기 위한 데이터 소스.</p>
<p>뷰 (View): 사용자 인터페이스를 표시하고 사용자 입력을 처리하는 부분.</p>
<br/>

<p>참고 Blog
<a href="https://bestalign.github.io/translation/cartoon-guide-to-flux/">https://bestalign.github.io/translation/cartoon-guide-to-flux/</a>
<a href="https://taegon.kim/archives/5288">https://taegon.kim/archives/5288</a>
<a href="https://velog.io/@andy0011/Flux-%ED%8C%A8%ED%84%B4%EC%9D%B4%EB%9E%80">https://velog.io/@andy0011/Flux-%ED%8C%A8%ED%84%B4%EC%9D%B4%EB%9E%80</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[38일차 리액트 심화주차 (Redux Toolkit (RTK))]]></title>
            <link>https://velog.io/@seul-bean/38%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@seul-bean/38%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Sun, 01 Oct 2023 14:59:05 GMT</pubDate>
            <description><![CDATA[<h1 id="🍎-리덕스툴킷rtk이란">🍎 리덕스툴킷(RTK)이란?</h1>
<p><em>코드는 더 적게, 리덕스를 더 편하게 쓰기 위한 기능들을 흡수해서 만든 것.</em>
리덕스를 사용하기 위해 작성했던 ducks 패턴의 요소들이 전체적인 코드의 양을 늘림 
→ 리덕스 툴킷을 통해 어느정도 자동화.</p>
<br/>

<h2 id="🌳-설치">🌳 설치</h2>
<p>CRA를 통해 새로운 프로젝트를 생성.
패키지 설치.
<code>yarn add react-redux @reduxjs/toolkit</code></p>
<br/>

<p><strong>Redux와 RTK의 차이점</strong>
Action Value와 Action Creator를 직접 생성해주지 않고,
<code>Slice</code>라는 API를 통해 Action Value, Action Creator, Reducer가 하나로 합쳐졌다는 점.</p>
<pre><code class="language-js">// createSlice API 뼈대

const counterSlice = createSlice({    // createSlice API를 통해 슬라이스 생성
    name: &#39;&#39;,    // 모듈 이름
      initialState : {}, // 모듈의 초기상태 값
      reducers : {},    // 모듈의 Reducer 로직, 여러개 들어갈 수 있기 때문에 객체
})</code></pre>
<br />

<p>counter 만드는 예제</p>
<pre><code class="language-js">// src/redux/modules/counterSlice.js
import { createSlice } from &quot;@reduxjs/toolkit&quot;;

const initialState = {
    number: 0,
}

const counterSlice = createSlice({
    name: &quot;counter&quot;,
    initialState,
      reducers: {
          // 리듀서 안에서 만든 함수 자체가 리듀서의 로직이자, 액션크리에이터가 된다.
          // Action Value까지 함수의 이름을 따서 자동으로 생성.
        addNumber: (state, action) =&gt; {
            state.number = state.number + action.payload;
        },
          minusNumber: (state, action) =&gt;{
            state.number = state.number - action.payload;
        },
    },
});

// 액션크리에이터는 컴포넌트에서 사용하기 위해 export
export const { addNumber, minusNumber } = counterSlice.actions;    // reducer 객체를 의미
// reducer는 configStore에 등록하기 위해 export default
export default counterSlice.reducer;</code></pre>
<blockquote>
<p>actions 속성은 Redux Toolkit에서 생성한 슬라이스(slice) 객체에 포함된 액션 생성자 함수들을 담고 있는 객체.
Redux Toolkit의 createSlice 함수를 사용하여 슬라이스를 생성하면, 해당 슬라이스의 액션 생성자 함수들이 actions 속성에 자동으로 포함된다.</p>
</blockquote>
<br />

<p>configStore</p>
<pre><code class="language-js">// src/redux/modules/config/configStore.js
import {configureStore} from &quot;@reduxjs/toolkit&quot;;

// slice.reducer
import counter from &quot;../modules/counterSlice&quot;;
import todos from &quot;../mmodules/todosSlice&quot;;

// 모듈이 여러개인 경우
// 추가할때마다 reducer 안에 각 모듈의 slice.reducer를 추가해줘야 한다.
const store = configureStore({
    reducer: { counter: counter, todos: todos },
})

export default store;</code></pre>
<pre><code class="language-js">// index.js
import React from &quot;react&quot;;
import ReactDOM from &quot;react-dom/client&quot;;
import App from &quot;./App&quot;;
import { Provider } from &quot;react-redux&quot;;
import store from &quot;./redux/config/configStore&quot;;

const root = ReactDOM.createRoot(document.getElementById(&quot;root&quot;));
root.render(
    &lt;Provider store={store}&gt;
          &lt;App /&gt;
      &lt;/Provider&gt;
);</code></pre>
<br />

<p>툴킷을 사용해서 만든 모듈을 조회하는 방식은 일반리덕스를 사용했을 때와 동일하다.</p>
<pre><code class="language-js">import React from &quot;react&quot;;
import { useSelector } from &quot;react-redux&quot;;

const App = () =&gt; {
    // Store에 있는 todos 모듈 state 조회하기
      const todos = useSelector((state) =&gt; state.todos);

      return &lt;div&gt;APP&lt;/div&gt;;
};

export default App;</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[37일차 리액트 숙련주차 (JSON)]]></title>
            <link>https://velog.io/@seul-bean/37%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@seul-bean/37%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Sat, 30 Sep 2023 14:22:01 GMT</pubDate>
            <description><![CDATA[<h1 id="🍎-json이란">🍎 JSON이란?</h1>
<p><em>JavaScript Object Notation</em>
자바스크립트 객체 문법에 토대를 둔, 문자 기반의 데이터 교환 형식</p>
<p>일반적인 JSON 구조는 자바스크립트 객체 리터럴 작성법을 따른다.
자바스크립트의 원시 자료형인 <strong>문자열, 숫자, 불리언</strong>을 가질 수 있고 중첩된 계층 구조 또한 가질 수 있다.
작은 따옴표(&#39;&#39;)가 아닌 큰 따옴표(&quot;&quot;)만 허용된다.</p>
<h2 id="🌳-메서드">🌳 메서드</h2>
<p>Json → 문자열 형태 → 서버-클라이언트 간 데이터 전송 시 사용</p>
<p>두 경우를 위해 파싱(parsing) 과정이 필요</p>
<ol>
<li>JS 객체를 JSON 형태로 전송</li>
<li>JSON 형태를 JS 객체 형태로 사용
<code>JS object → Json, Json → JS object</code></li>
</ol>
<br />

<p><code>stringify()</code>
자바스크립트 객체 → JSON 문자열 변환.
네트워크를 통해 객체를 JSON 문자열로 변환할 때 주로 사용.</p>
<pre><code class="language-js">console.log(JSON.stringify({x: 5, y: 6}));
// {&quot;x&quot;:5,&quot;y&quot;:6}

// 문자열, 숫자, 불리언
console.log(JSON.stringify([new Number(3), new String(&#39;false&#39;), new Boolean(false)]));
// [3,&quot;false&quot;,false]

// 숫자, undefined, 함수, 심볼
console.log(JSON.stringify({ x: [10, undefined, function(){}, Symbol(&#39;&#39;)]}));
// {&quot;x&quot;:[10,null,null,null]}

// Date
console.log(JSON.stringify(new Date(2006, 0, 2, 15, 4, 5)));
// &quot;2006-01-02T15:04:05.000Z&quot;</code></pre>
<p><code>parse()</code>
JSON 문자열 → 자바스크립트 객체 변환.
네트워크 통신의 결과를 통해 받아온 JSON 문자열을 프로그램 내부에서 사용하기 위해 JS 객체로 변환할 때 사용. (서버 → client)</p>
<pre><code class="language-js">const json = `{&quot;result&quot;:true, &quot;count&quot;:42}`;
const obj = JSON.parse(json);

console.log(obj.count);
// 42

console.log(obj.result);
// true</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[36일차 리액트 숙련주차 (REST)]]></title>
            <link>https://velog.io/@seul-bean/35%EC%9D%BC%EC%B0%A8-feu3pbej</link>
            <guid>https://velog.io/@seul-bean/35%EC%9D%BC%EC%B0%A8-feu3pbej</guid>
            <pubDate>Mon, 25 Sep 2023 14:58:59 GMT</pubDate>
            <description><![CDATA[<h1 id="🍎-restpath-variable-vs-query-parameter">🍎 REST(Path Variable vs Query Parameter)</h1>
<p>REpresentational State Transfer의 약자로서, 어떤 자원에 대해 CRUD를 진행할 수 있게 HTTP <strong>Method</strong>(GET, POST, PUT, DELETE)를 사용하여 요청을 보내는 것.
이 때, 요청을 위한 자원은 특정한 형태로 표현된다.
URI를 통해 정보의 자원을(only 자원만을) 표현하고, 자원의 행위는 HTTP Method로 명시한다.</p>
<ul>
<li>자원(Resource) : URI</li>
<li>행위(Verb) : HTTP Method</li>
</ul>
<p>표현(Representations)</p>
<p><code>Get/users/3/profile</code>
Get 행위
users/3/profile 자원</p>
<br />

<h3 id="🌱-규칙">🌱 규칙</h3>
<ul>
<li>URI는 명사를 사용하고 소문자로 작성되어야 한다.</li>
<li>명사는 복수형을 사용한다.</li>
<li>URI의 마지막에는 /를 포함하지 않는다.</li>
<li>URI에는 언더바가 아닌 하이픈을 사용한다.</li>
<li>URI에는 파일의 확장자를 표시하지 않는다.</li>
</ul>
<p><strong>RestFul하다는 것</strong> : REST API의 까다로운 조건을 만족시킨 통신 설계 상태.
<strong>RestFul 하지 못한 상황</strong></p>
<ul>
<li>CRUD의 기능을 모두 POST method로만 이용하는 경우</li>
<li>URI에 행위(method)에 대한 부분이 드러가는 경우</li>
</ul>
<br />
<br />

<h2 id="🌳-path-variable-vs-query-parameter">🌳 Path Variable vs Query Parameter</h2>
<h3 id="🌱-path-variable">🌱 Path Variable</h3>
<ul>
<li>경로 자체에 변수를 사용한 방법</li>
<li>전체 데이터 또는 특정 하나의 데이터를 다룰 때 처럼, 리소스를 식별하기 위 사용된다.<pre><code>/user/3 - ID</code></pre></li>
</ul>
<h3 id="🌱-query-parameter">🌱 Query Parameter</h3>
<p>데이터를 정렬하거나 필터링하는 경우 더 적합하다. → order</p>
<pre><code>/user?user_id=3</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[35일차 리액트 숙련주차 (동기/비동기 방식)]]></title>
            <link>https://velog.io/@seul-bean/35%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@seul-bean/35%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Fri, 22 Sep 2023 11:51:46 GMT</pubDate>
            <description><![CDATA[<h1 id="🍎-비동기-프로그래밍">🍎 비동기 프로그래밍</h1>
<p><strong>동기(synchronous)적 방식이란?</strong>
현재 실행중인 코드가 끝나야 다음 코드를 실행하는 방식</p>
<p><strong>비동기(asynchronous)적 방식이란?</strong>
실행중인 코드의 완료 여부와 무관하게 즉시 다음 코드로 넘어가는 방식</p>
<ol>
<li>setTimeout, add EventListner 등</li>
<li>별도의 <strong>요청, 실행, 대기, 보류</strong> 등과 관련된 코드는 모두 비동기적 코드</li>
</ol>
<p><strong>3. 대표적으로 서버 통신과 관련된 로직들 포함</strong>
<img src='https://velog.velcdn.com/images/seul-bean/post/bd9ac152-0405-4807-8293-54109349d467/image.png' /></p>
<br />

<h3 id="🌱-콜백지옥">🌱 콜백지옥</h3>
<p>비동기적 프로그래밍을 하다 보면, 콜백지옥과 마주할 수 있다.</p>
<ol>
<li>콜백 함수를 익명 함수로 전달하는 과정이 반복되어 코드의 들여쓰기 수준이 헬 수준인 경우</li>
<li>주로 이벤트 처리 및 서버 통신과 같은 비동기적 작업을 수행할 때 발생</li>
<li>가독성이 떨어지고, 수정이 어려움</li>
</ol>
<p>이를 해결하기 위해 ES6에서 Promise 객체가 소개되었다.</p>
<br />
<br />

<h2 id="🌳-promise-객체">🌳 Promise 객체</h2>
<p>비동기 작업이 맞이할 미래의 완료 또는 실패와 그 결과 값을 나타낸다.</p>
<br />

<h3 id="🌱-promise-객체에-담기는-주요한-상태정보">🌱 Promise 객체에 담기는 주요한 상태정보</h3>
<ol>
<li><strong>대기</strong> : pending. 아직 성공(resolve) 또는 실패(rejected)되지 않은 상태.</li>
<li><strong>이행</strong> : fulfilled. 데이터 전달아 성공적으로 이행된 상태.</li>
<li><strong>거부</strong> : rejected, 어떠한 이유로 데이터 전달이 실패 된 상태.</li>
</ol>
<br />

<h3 id="🌱-promise-객체-핸들링-방법">🌱 Promise 객체 핸들링 방법</h3>
<p><strong>then ~ catch</strong> (ES6)</p>
<pre><code class="language-jsx">// http://api.naver.com/weather/today 로 요청을 한다고 가정.

axios.get(&#39;http://api.naver.com/weather/today&#39;)        // Promise 객체
.then(response =&gt; {
    console.log(&#39;정상처리 되었습니다 : &#39; + response);
})
.catch(error =&gt; {
    console.log(&#39;오류가 발생하였습니다 : &#39; + error);
})
.finally(()=&gt;{
    console.log(&#39;항상 실행되는 부분입니다!&#39;)
})</code></pre>
<p><strong>async / await</strong> (ES7)</p>
<pre><code class="language-jsx">const getWeather = async () =&gt; {
    try {
        const response = await axios. get(&#39;http://api.naver.com/weather/today&#39;);    
        // await를 입력해주면 이 문장이 끝날때까지 밑으로 넘어가지 않음
        console. log(&#39;정상처리 되었습니다 : &#39; + response);
    } catch (error) {
        console.log(&#39;오류가 발생하였습니다 : &#39; + error);
    }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[34일차 React-query]]></title>
            <link>https://velog.io/@seul-bean/34%EC%9D%BC%EC%B0%A8-React-query</link>
            <guid>https://velog.io/@seul-bean/34%EC%9D%BC%EC%B0%A8-React-query</guid>
            <pubDate>Thu, 21 Sep 2023 14:58:12 GMT</pubDate>
            <description><![CDATA[<h1 id="infinite-queries">Infinite Queries</h1>
<p>Data Fetching이 일어날 때 마다 기존 리스트 데이터에 Fetched Data를 추가하고자 할 때 유용하게 사용할 수 있는 hook.
더보기 UI 또는 무한스크롤 UI에 사용하기에 적합.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[33일차 Next.js]]></title>
            <link>https://velog.io/@seul-bean/33%EC%9D%BC%EC%B0%A8-Next.js</link>
            <guid>https://velog.io/@seul-bean/33%EC%9D%BC%EC%B0%A8-Next.js</guid>
            <pubDate>Mon, 21 Aug 2023 16:28:36 GMT</pubDate>
            <description><![CDATA[<h1 id="🍎-nextjs">🍎 Next.js</h1>
<ol>
<li>SEO(Search Engine Optimization)을 위한 SSR(Server-Side Rendering)을 지원</li>
<li>파일 기반 라우팅(File-based routing)을 통해 Routing을 쉽게 구현할 수 있다.</li>
<li>복잡한 Server 구축 없이도 API를 배포할 수 있다.</li>
<li>초기 로딩 속도 개선을 위한 자동 Code Splitting(코드 분할) 등 최적화를 자동으로 지원한다.</li>
<li>개발 환경 설정이 쉽고 간단하다.</li>
</ol>
<ul>
<li>Linting, Compling, Bundling, Deploying을 위한 설정이 자동화 되어있다.</li>
<li>Router, tailwind, typeScript, lint 등 주요 기능들을 configuration 없이 사용 가능하다.</li>
</ul>
<br>

<h2 id="🌳-mpa부터-ssr까지">🌳 MPA부터 SSR까지</h2>
<p>MPA (Multi-Page-Application)</p>
<pre><code class="language-tsx">/about → about.html
/profile → profile.html</code></pre>
<p><strong>원시적인 서버 사이드 렌더링 방식.</strong>
페이지 이동시나 렌더링 시 깜빡거려 유저 사용성 저하하는 경우가 있다.
이를 보완하기 위해서 CSR 방식의 React를 이용해서 SPA를 만들기 시작</p>
<br>

<h2 id="🌳-spa-single-page-application-csr-client-side-rendering">🌳 SPA (Single-Page-Application), CSR (Client-Side-Rendering)</h2>
<p>React의 SPA 개념을 이용하게 되면서 더 이상 새로고침이나 깜빡거림 없이 유저 사용성이 개선되었으나, 단점도 있었다.
→ 자바스크립트 번들 사이즈가 커짐에 따라 초기 로딩 속도가 증가하는 것.
→ 이를 보완하기 위해서 Code Splitting 개념이 나왔다.</p>
<p><strong>Code Spliting (Lazy-Loading)이란?</strong>
현재 꼭 필요한 곳에서만 자바스크립트 파일을 로딩하는 방식.
하나로 번들된 코드를 여러 코드나 컴포넌트로 분리해서, 지금 당장 필요한 코드가 아니라면 나중에 필요할 때 불러와서 사용할 수 있다.</p>
<p><strong>문제점. SEO</strong>
검색 엔진에서 웹 사이트의 정보를 가져오기 위해서 사용하는 크롤링 봇은 방문하는 웹 사이트 HTML 정보를 읽고 데이터를 축적하는데, CSR 방식의 웹사이트의 경우 방문하는 시점에는 웹사이트의 정보가 없음.
방문 이후 Javascript를 통해서 현재 페이지에 내용이 나타나는 CSR 형식
→ 서버에서 렌더링해서 클라이언트에 곧바로 보내주는 SSR가 대두됌.</p>
<br>

<h2 id="🌳-rendering이란">🌳 Rendering이란?</h2>
<p>Javascript를 이용해서 HTML을 만드는 행위</p>
<p><strong>Pre-rendering이란?</strong>
Client에 HTML이 이미 로드가 된 이후가 아닌, 이전에 Javascript를 이용해 HTML을 만드는 것을 말함.</p>
<p>Next.js는 기본적으로 모든 코드는 Pre-rendering 된다.
언제 HTML을 만드느냐에 따라서,</p>
<ul>
<li>Build 할 때 rendering 된다면? Static-Site generation (SSG) <span style="color:purple">정적 사이트 생성자</span></li>
<li>runtime에 rendering 된다면? Server-Side Rendering (SSR)</li>
</ul>
<blockquote>
<p><strong>runtime(실행 시간)이란?</strong>
애플리케이션이 빌드 및 배포된 후 사용자의 요청에 대한 응답으로 애플리케이션이 실행되는 기간.</p>
</blockquote>
<blockquote>
<ul>
<li>Pages Router : 자동으로 정적으로 렌더링 된다.</li>
</ul>
</blockquote>
<ul>
<li>App Router : 기본적으로 서버 컴포넌트로 취급된다.</li>
</ul>
<br>

<h2 id="🌳-csr-vs-ssr-vs-ssg-vs-isr">🌳 CSR vs SSR vs SSG vs ISR</h2>
<p><strong>Client-Side Rendering</strong>
<img src="https://velog.velcdn.com/images/seul-bean/post/cac2bd6d-19cd-41c1-8fab-8068b22e97eb/image.png" alt=""></p>
<p>브라우저에서 HTML file을 로드하면, Javascript를 이용하여 rendering 하는 방식</p>
<br>

<p><strong>Server-Side Rendering</strong>
<img src="https://velog.velcdn.com/images/seul-bean/post/c4ddc89e-6eb5-4a40-89ce-a8d809f365e4/image.png" alt=""></p>
<p>브라우저에서 해당하는 페이지를 접속하면 ,그 순간 서버에서 html을 렌더링해서 전달해주는 방식
페이지를 요청할 때마다 렌더링하기 때문에 오래 걸림.</p>
<br>

<p><strong>Static-Site Generation</strong>
<img src="https://velog.velcdn.com/images/seul-bean/post/8d351581-9190-4f42-81bf-df14be25911a/image.png" alt=""></p>
<p>SSR의 경우 페이지를 요청할 때마다 서버에서 렌더링.
정적인 페이지를 제공하려고 할 때는 그럴 필요없이 빌드할 때 렌더링하고 페이지를 요청할 때 이미 렌저링 된 페이지를 반환함.</p>
<br>

<p><strong>Incremental Static Regeneration</strong>
<img src="https://velog.velcdn.com/images/seul-bean/post/47bdeed5-dcee-4329-98a4-bcd6c9b87911/image.png" alt=""></p>
<p>SSG의 단점은, 컨텐츠가 업데이트 되면 제대로 된 정보를 보여줄 수 없다는 것.
이를 보완하기 위해서 일정 주기마다 페이지를 빌드시켜주는 ISR이라는 방식이 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/seul-bean/post/f56602bc-40a5-4fa6-befa-30b13b65385d/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[32일차 쉽게 다시 보는 리덕스]]></title>
            <link>https://velog.io/@seul-bean/32%EC%9D%BC%EC%B0%A8-%EC%89%BD%EA%B2%8C-%EB%8B%A4%EC%8B%9C-%EB%B3%B4%EB%8A%94-%EB%A6%AC%EB%8D%95%EC%8A%A4</link>
            <guid>https://velog.io/@seul-bean/32%EC%9D%BC%EC%B0%A8-%EC%89%BD%EA%B2%8C-%EB%8B%A4%EC%8B%9C-%EB%B3%B4%EB%8A%94-%EB%A6%AC%EB%8D%95%EC%8A%A4</guid>
            <pubDate>Tue, 15 Aug 2023 14:56:26 GMT</pubDate>
            <description><![CDATA[<h2 id="🍎-리덕스의-구성요소">🍎 리덕스의 구성요소</h2>
<h3 id="🌳-store">🌳 Store</h3>
<p>모든 전역 State들을 관리하는 단 하나의 <strong>상태 저장소</strong>(→단 하나의 객체)</p>
<pre><code class="language-jsx">Store: {todos, auth}</code></pre>
<p>store 내부의 리듀서들로부터 각각 최신 상태를 갖는다.</p>
<h3 id="🌳-reducer">🌳 Reducer</h3>
<p>state 변경 함수</p>
<ul>
<li>매개변수로 기존상태와 액션객체를 받음</li>
<li>상태 변경 후 최신 상태를 Store에 제공 (리턴)</li>
</ul>
<h3 id="🌳-action">🌳 Action</h3>
<p>{type, payload} 형태의 객체</p>
<ul>
<li>리듀서 함수에게 전달되는 인자</li>
<li>리듀서에게 요구할 상태변경 작업에 대한 정의를 나타내는 객체 (상태변경 요청서)</li>
<li>type은 필수 속성. payload는 선택 속성</li>
</ul>
<h3 id="🌳-dispatch">🌳 Dispatch</h3>
<p>액션 객체를 인자로 받아 리듀서를 호출 시키는 함수</p>
<ul>
<li>dispatch(액션객체)가 실행되면 리듀서 함수의 매개변수로 action 객체를 전달하며 호출</li>
</ul>
<br>

<h2 id="🍎-리덕스를-왜-써야-하나요">🍎 리덕스를 왜 써야 하나요?</h2>
<ul>
<li>props drilling으로 인한 불편함을 해소</li>
<li>상태관리에 대한 유지보수성이 좋아짐. (코드베이스 규모가 커질수록 Good)</li>
<li>디버깅이 쉬어짐. (redux dev tools) - 단순 전역 상태관리를 넘어 추가적인 옵션 기능 제공</li>
</ul>
<br>

<h2 id="🍎-전역-상태관리는-context-api로도-되는데-왜-리덕스를-써야-하나요">🍎 전역 상태관리는 context API로도 되는데, 왜 리덕스를 써야 하나요?</h2>
<p><img src="https://velog.velcdn.com/images/seul-bean/post/36e225a0-deb1-45c2-8ae5-0ed6f6e7da5d/image.png" alt=""></p>
<p>관리해야할 State 수가 적은 편이면 context API만으로도 충분
확장성, 유지보수성까지 고려해야 한다면 리덕스와 같은 전역 상태 라이브러리를 적용하는 것이 현명한 선택</p>
<br>

<h2 id="🍎-리덕스는-어떻게-동작하나요">🍎 리덕스는 어떻게 동작하나요?</h2>
<p><img src="https://velog.velcdn.com/images/seul-bean/post/b1ae0f89-8ab8-4719-9331-1acf96beccdd/image.png" alt=""></p>
<ol>
<li><strong>초기 상태 받기</strong>: 페이지 랜딩 시 useSelector를 통해 store에서 initialState를 받아 UI를 렌더링한다.</li>
<li><strong>상태 변경 요청</strong>: 사용자 이벤트 발생 시 상태변경을 위해 dispatch(action)로 Store 내 각 리듀서들에게 action 전달하며 실행시킨다.
(todos 리듀서 호출만을 의도했어도 auth 리듀서도 함께 호출된다. → action.type이 중복되면 안되는 이유!)</li>
<li><strong>상태 변경 처리</strong>: 기존 State는 store부터, action 객체는 dispatch를 통해 매개변수로 받아서 리듀서 함수를 실행하여 action.type에 따라 상태 변경 처리 후 store에 변경된 최신 상태를 제공한다.</li>
<li><strong>신규 상태 받기</strong>: useSelector를 통해 store의 특정 상태를 구독중인 현재 페이지 컴포넌트(view)는 상태 변경 알림을 받고 리렌더링한다.</li>
</ol>
<br>

<p>상태 가져오기 (컴포넌트 자체 → form store)
<img src="https://velog.velcdn.com/images/seul-bean/post/ce1d37a3-4b4f-4f4c-ac38-2406cd6288c3/image.jpg" alt=""></p>
<p>상태 변경 요청하기(컴포넌트 자체 → to reducer)</p>
<pre><code class="language-jsx">const dispatch = useDispatch();
const deleteTodo=(id)=&gt;{
    // 단순히 리듀서에게 상태 변경 요청만하는 패턴. 상태변경 로직은 리듀서 안에서 기술
    dispatch({type: &quot;todos/DELETE_TODO&quot;, payload:id}) // → 리듀서 실행
    //dispatch(deleteTodo(id)) // 액션생성자 함수 적용 (휴먼에러 방지)
}</code></pre>
<br>

<h2 id="🍎-서로-다른-리듀서-모듈끼리-액션-타입이-중복되도-되나요">🍎 서로 다른 리듀서 모듈끼리 액션 타입이 중복되도 되나요?</h2>
<p>dispatch({type:&quot;ADD_TODO&quot;})라고 하면 액션 객체는 store로 전달되서 모든 리듀서들에게 전달된다. 만약 action type이 todos 리듀서와 auth 리듀서 안에 각각 들어있다면 두 리듀서 함수가 모두 실행되어 예상치 못한 버그를 가질 수 있다!</p>
<pre><code class="language-jsx">// 리듀서명 / 액션명의 조함으로 혹여나 중복이 발생하지 않도록 한다.
// modules/todos.js
const ADD_TODO=&quot;todos/ADD_TODO&quot;;
// modules/auth.js
const ADD_TODO=&quot;auth/ADD_TODO&quot;;</code></pre>
<br>

<h2 id="🍎-store-자체를-구독하는-건-지양해야-함">🍎 Store 자체를 구독하는 건 지양해야 함.</h2>
<pre><code>// ❌ 불필요하게 리렌더링이 발생할 수 있음.
const store = useSelector(state =&gt; state);
const todos = store.todos;

// ⭕ Good!!
const todos = useSelector(state =&gt; state.todos);</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[12주차 주특기 플러스 - 일조 팀프로젝트 회고록]]></title>
            <link>https://velog.io/@seul-bean/%EC%A3%BC%ED%8A%B9%EA%B8%B0-%ED%94%8C%EB%9F%AC%EC%8A%A4-%EC%A3%BC%EC%B0%A8-%EC%9D%BC%EC%A1%B0-%ED%8C%80%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9A%8C%EA%B3%A0%EB%A1%9D</link>
            <guid>https://velog.io/@seul-bean/%EC%A3%BC%ED%8A%B9%EA%B8%B0-%ED%94%8C%EB%9F%AC%EC%8A%A4-%EC%A3%BC%EC%B0%A8-%EC%9D%BC%EC%A1%B0-%ED%8C%80%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9A%8C%EA%B3%A0%EB%A1%9D</guid>
            <pubDate>Mon, 14 Aug 2023 07:41:01 GMT</pubDate>
            <description><![CDATA[<h1 id="프로젝트-명-genesis">프로젝트 명: Genesis</h1>
<p>별자리를 역동적인 UI와 함께 재미있게 소개해주는 서비스입니다.
매달 우주에서 일어나고 있는 이벤트가 캘린더에 알기 쉽게 표시되어 있습니다.
슈팅게임과, 별자리 맞추기 게임을 통해 별자리에 대한 흥미도를 높여줍니다.</p>
<p><img src="https://velog.velcdn.com/images/seul-bean/post/487e20ff-0c4e-4be6-835f-72f45852f900/image.gif" alt=""></p>
<h2 id="keep"><strong>Keep</strong></h2>
<p>이번 프로젝트에서 진행한 과정 중 다음 프로젝트에서도 <strong>유지했으면 하는 부분</strong>.</p>
<ol>
<li><p>홍민 - 팀원들과의 소통하는 부분이다.
우리는 팀원과의 원활한 소통을위해 처음에 아이스브레이킹을통해 서로에대해 알아갔다.
그렇게 친해짐과동시에 팀원에대한 서로의 배려까지 더해지니 더할 나위없이 어색함이 없었다.
그런점이 팀원의 소통에대해 + 요소라고 생각이되며 이런점은 다음팀 에서도 적용하면 좋을거 같다.</p>
</li>
<li><p>승범 - 와이어 프레임 및 계획 세우는 법이다</p>
<p> 우리 팀은 작업을 할 때 자기가 맡은 부분을 잘 설계하여 프로젝트를 하는 도중 기능을 줄이는 일은 거의 없었고 오히려 추가하여 자기가 맡은 방안에서도 넓혀가는 방안을 선택하여 너무 좋았다. </p>
</li>
<li><p>유진 - 팀원 다 같이 깃에 올리는 점이 충돌이 적어서 정말 좋았습니다. 그리고 프로젝트 영역이 잘 나눠진 것 같아서 진행이 잘 되었습니다.</p>
</li>
<li><p>슬기 - Git flow를 최대한 지키려고 하는 부분이 좋았습니다.
각자의 역할에 충실하며 프로젝트에 필요한 작업을 잘 수행한 점이 좋았습니다.
어떤 아이디어를 제시해도 존중해주는 모습이 정말 좋았습니다.</p>
</li>
</ol>
<hr>
<h2 id="problem"><strong>Problem</strong></h2>
<p>이번 프로젝트에서 발생한 <strong>문제점</strong></p>
<ol>
<li><p>홍민 - 더 좋은 라이브러리의 등장
작업을하고 마무리단계에서 기존 작업하던 라이브러리보다 훨씬 좋은 성능의 라이브러리를 발견하게되었따. .. 정말 충격이였다. 그간 작업한게 여기선 딸깍거리면 끝난다니..
사전조사의 중요성을 다시한번 깨닫게 되었다.</p>
</li>
<li><p>승범 - 작은 동작들의 미스</p>
<p> 작업을 하는데 어떤 부분들은 통합을 했어야 하는데 그런 부분들은 통합이 안되어서 작업이 조금 지연이 되었었다.</p>
</li>
<li><p>유진 - map함수가 너무많이 중첩되어서 기능적으로 효율있는 코드가 아닌 것 같습니다.</p>
</li>
<li><p>슬기 - 최적화의 부재가 살짝 아쉽습니다. Props를 살짝 비효율적으로 내려준거 같고 이미지 로딩 부분 처리를 잘 하지 못한 점이 너무 아쉽습니다.</p>
</li>
</ol>
<hr>
<h2 id="try"><strong>Try</strong></h2>
<p>다음 프로젝트를 위해 해야 할 <strong>노력</strong></p>
<ol>
<li><p>홍민 - Next.js 의 부재는 생각보다 컸다.
채용공고를 보면 nextJs의 수요가 적지않게 많다. 이것을 해보지 못했단건 내 경험의 부족과 노력의 부족으로 생각이된다. 
앞으로 전진적으로 더욱 더 배워야 겠다.</p>
</li>
<li><p>승범 - 경험의 부족 및 다양한 과정을 찾아보는 것</p>
<p> 작업을 하는데 나는 시간이 오래 걸린 부분들이 영어로 걸려서 자막을 필요로 해서 영상을 보았더니 내가 작업한 시간이 반 이상으로 단축 되는 과정을 보아서 정보를 다양하게 알아보는 노력을 하는게 중요하다는 것을 느꼈다.</p>
</li>
<li><p>유진 - 효율적인 코드를 더 공부할 것이고, css작업할 때 너무많은 잔 가지가 있는 느낌을 받았어서 css도 공부할 것입니다. </p>
</li>
<li><p>슬기 - 이번 프로젝트에서 써보지 못한 기술들에 대해 알아보고, 이번 프로젝트에서 써봤던 기술들을 복습 해야할 것 같습니다.
또한, 아쉬웠던 부분에 대해 어떻게 보완할지 생각해보아야할거 같습니다.</p>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[프로그래머스 <명예의 전당 (1)
>]]></title>
            <link>https://velog.io/@seul-bean/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EB%AA%85%EC%98%88%EC%9D%98-%EC%A0%84%EB%8B%B9-1</link>
            <guid>https://velog.io/@seul-bean/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EB%AA%85%EC%98%88%EC%9D%98-%EC%A0%84%EB%8B%B9-1</guid>
            <pubDate>Thu, 03 Aug 2023 16:38:00 GMT</pubDate>
            <description><![CDATA[<h2 id="🍎-명예의-전당-1">🍎 명예의 전당 (1)</h2>
<p><a href="https://school.programmers.co.kr/learn/courses/30/lessons/138477">https://school.programmers.co.kr/learn/courses/30/lessons/138477</a></p>
<p><strong>문제 설명</strong>
&quot;명예의 전당&quot;이라는 TV 프로그램에서는 매일 1명의 가수가 노래를 부르고, 시청자들의 문자 투표수로 가수에게 점수를 부여합니다. 매일 출연한 가수의 점수가 지금까지 출연 가수들의 점수 중 상위 k번째 이내이면 해당 가수의 점수를 명예의 전당이라는 목록에 올려 기념합니다. 즉 프로그램 시작 이후 초기에 k일까지는 모든 출연 가수의 점수가 명예의 전당에 오르게 됩니다. k일 다음부터는 출연 가수의 점수가 기존의 명예의 전당 목록의 k번째 순위의 가수 점수보다 더 높으면, 출연 가수의 점수가 명예의 전당에 오르게 되고 기존의 k번째 순위의 점수는 명예의 전당에서 내려오게 됩니다.</p>
<p>이 프로그램에서는 매일 &quot;명예의 전당&quot;의 최하위 점수를 발표합니다. 예를 들어, k = 3이고, 7일 동안 진행된 가수의 점수가 [10, 100, 20, 150, 1, 100, 200]이라면, 명예의 전당에서 발표된 점수는 아래의 그림과 같이 [10, 10, 10, 20, 20, 100, 100]입니다.</p>
<p>명예의 전당 목록의 점수의 개수 k, 1일부터 마지막 날까지 출연한 가수들의 점수인 score가 주어졌을 때, 매일 발표된 명예의 전당의 최하위 점수를 return하는 solution 함수를 완성해주세요.</p>
<p><strong>제한사항</strong>
3 ≤ k ≤ 100
7 ≤ score의 길이 ≤ 1,000
0 ≤ score[i] ≤ 2,000</p>
<br>

<hr>
<br>

<h2 id="🍎-내가-생각한-solution">🍎 내가 생각한 solution</h2>
<p>문제가 길어서 이해하는데도 꽤 오랜 시간이 걸렸다.
if문을 통해 k를 기준으로 k일동안 점수따로 그 이후에 점수를 따로 구해주어 모두 answer 배열에 넣어주었다.</p>
<pre><code class="language-javascript">function solution(k, score) {
    var answer = [];
    let arr=[]

    score.forEach((num,i)=&gt;{
        if(i&lt;k){
            arr.push(num)
            arr.sort((a,b)=&gt;a-b)
            answer.push(arr[0])
        }else{
            arr.push(num)
            arr.sort((a,b)=&gt;b-a)
            arr=arr.slice(0,k)
            answer.push(arr[k-1])
        }

    })
    return answer
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[31일차 리액트 숙련주차(Router Dom) / (모던 자바스크립트: 명시적 타입 변환)]]></title>
            <link>https://velog.io/@seul-bean/31%EC%9D%BC%EC%B0%A8-%EB%AA%A8%EB%8D%98-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EB%AA%85%EC%8B%9C%EC%A0%81-%ED%83%80%EC%9E%85-%EB%B3%80%ED%99%98</link>
            <guid>https://velog.io/@seul-bean/31%EC%9D%BC%EC%B0%A8-%EB%AA%A8%EB%8D%98-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EB%AA%85%EC%8B%9C%EC%A0%81-%ED%83%80%EC%9E%85-%EB%B3%80%ED%99%98</guid>
            <pubDate>Wed, 02 Aug 2023 16:25:30 GMT</pubDate>
            <description><![CDATA[<h1 id="🍎-react-router-dom">🍎 React Router Dom</h1>
<p>페이지를 구현할 수 있게 해주는 패키지</p>
<br>

<ul>
<li>react-router-dom을 이용하면, SPA 기반 인 리액트 프로젝트 안에서 여러개의 페이지를 구현할 수 있다.</li>
<li>Router.js에 Router 설정에 관련된 코드를 작성하고, 최상위 컴포넌트인 App.js에서 import해서 사용한다.</li>
<li>react-router-dom는 여러가지 훅을 제공한다.</li>
</ul>
<br>

<p>vscode 터미널에서 아래 코드를 입력해 패키지를 설치할 수 있다.</p>
<pre><code>yarn add react-router-dom</code></pre><br>

<h2 id="🌳-사용방법-순서">🌳 사용방법 순서</h2>
<ul>
<li>페이지 컴포넌트 생성(Home.jsx, Detail.jsx.....)</li>
<li>⭐ Router.js 생성 및 route 설정 코드 작성</li>
<li><em>브라우저에 우리가 URL을 입력하고 이동했을 때 우리가 원하는 페이지 컴포넌트로 이동하게끔 만드는 부분*</em></li>
</ul>
<pre><code class="language-jsx">import React from &quot;react&quot;;
import { BrowserRouter, Route, Routes } from &quot;react-router-dom&quot;;

// BrowserRouter를 Router로 감싸는 이유는,
// SPA의 장점인 브라우저가 깜빡이지 않고 다른 페이지로 이동할 수 있게 만들어줍니다
const Router = () =&gt; {
    return (
        &lt;BrowserRouter&gt;
              &lt;Routes&gt;
                  // path는 사용하고싶은 &quot;주소&quot;
                  // element는 해당 주소로 이동했을 때 보여주고자 하는 컴포넌트
                  &lt;Route path=&quot;/&quot; element={&lt;Home /&gt;} /&gt;
                &lt;Route path=&quot;detail&quot; element={&lt;Detail /&gt;} /&gt;
              &lt;/Routes&gt;
          &lt;/BrowserRouter&gt;
    );
};

export default Router;</code></pre>
<ul>
<li>App.js에 Router.js import 해주기<pre><code class="language-jsx">import React from &quot;react&quot;;
import Router from &quot;./shared/Router&quot;;
</code></pre>
</li>
</ul>
<p>function App() {
    return <Router />;
}
export default App;</p>
<pre><code>Router.js를 **App 컴포넌트에 넣어주는 이유는 우리가 만든 프로젝트에서 가장 최상위에 존재하는 컴포넌트가 App.js이기 때문**

&lt;br&gt;

## 🌳 react-router-dom Hooks
### 🪴 useNavigate
navigate를 생성하고, navigate(&#39;보내고자 하는 url&#39;)을 통해 페이지를 이동 시킬 수 있다.
```jsx
const Home = () =&gt; {
    const navigate = useNvigate();

    return (
        &lt;button
            onClick={()=&gt;{
                navigate(&quot;/works&quot;);
            }}
        &gt;
           work로 이동
        &lt;/button&gt;
    );
};

export default Home;</code></pre><br>

<h3 id="🪴-uselocation">🪴 useLocation</h3>
<pre><code class="language-jsx">import {useLocation} from &quot;react-router-dom&quot;;

const Works = () =&gt; {
    const location = useLocation();
    console.log(&quot;location :&gt;&gt; &quot;, location);
    return    &lt;div&gt;&lt;/div&gt;
}</code></pre>
<br>

<h3 id="🪴-link">🪴 Link</h3>
<p>html 태그중에 a 태그의 기능을 대체하는 API. 
<strong>만약 JSX에서 a태그를 사용해야 한다면, 반드시 Link를 사용해서 구현해야 한다.</strong>
(a태그를 사용하면 페이지를 이동하면서 브라우저가 새로고침(refresh)되기 때문)
브라우저가 새로고침 되면 모든 컴포넌트가 다시 렌더링되야 하고, 또한 리덕스나 useState를 통해 메모리상에 구축해놓은 모든 상태값이 초기화된다. → 성능에 악영향을 줄 수 있고, 불필요한 움직임.</p>
<pre><code class="language-jsx">import {Link, useLocation} from &#39;react-router-dom&#39;;

const Works = () =&gt; {
    return(
        &lt;div&gt;
            &lt;Link to=&quot;/contact&quot;&gt;contact 페이지로 이동하기&lt;/Link&gt;
        &lt;/div&gt;
    )
}</code></pre>
<br>

<h2 id="🌳-dynamic-route">🌳 Dynamic Route</h2>
<p>동적 라우팅이라고도 말하는데 path에 유동적인 값을 넣어서 특정 페이지로 이동하게끔 구현하는 방법</p>
<pre><code class="language-jsx">const Router = () =&gt; {
    return (
        &lt;BrowserRouter&gt;
              &lt;Routes&gt;
                  // path는 사용하고싶은 &quot;주소&quot;
                  // element는 해당 주소로 이동했을 때 보여주고자 하는 컴포넌트
                  &lt;Route path=&quot;/&quot; element={&lt;Home /&gt;} /&gt;
                &lt;Route path=&quot;detail/:id&quot; element={&lt;Detail /&gt;} /&gt;
              &lt;/Routes&gt;
          &lt;/BrowserRouter&gt;
    );
};

export default Router;</code></pre>
<p>:id라는 것이 바로 동적인 값을 받겠다라는 의미.
:id는 useParams 훅에서 조회할 수 있는 값</p>
<p>useParams: path의 있는 id값을 조회할 수 있게 해주는 훅</p>
<br>
<br>
<br>

<h2 id="🌱-모던-자바스크립트-deep-dive">🌱 모던 자바스크립트 Deep Dive</h2>
<p><code>매일 책 15분동안 읽고 새로 깨달은 부분 정리</code></p>
<h3 id="93-명시적-타입-변환"><strong>9.3 명시적 타입 변환</strong></h3>
<p>개발자의 의도에 따라 명시적으로 타입을 변경하는 방법
-표준 빌트인 생성자 함수(String, Number, Boolean)를 new 연산자 없이 호출하는 방법</p>
<pre><code class="language-javascript">// 숫자 타입 =&gt; 문자열 타입
String(1);    // &quot;1&quot;

// 불리언 타입 =&gt; 문자열 타입
String(true);    // &quot;true&quot;</code></pre>
<p>-빌트인 메서드를 사용하는 방법</p>
<pre><code class="language-javascript">// 숫자 타입 =&gt; 문자열 타입
(Infinity).toString();    //&quot;Infinity&quot;

// 불리언 타입 =&gt; 문자열 타입
(true).toString();    //&quot;true&quot;</code></pre>
<p>-암묵적 타입 변환을 이용하는 방법</p>
<pre><code class="language-javascript">// 숫자 타입 =&gt; 문자열 타입
NaN+&#39;&#39;;    //&quot;NaN&quot;

// 불리언 타입 =&gt; 문자열 타입
false + &#39;&#39;;    //&quot;false&quot;</code></pre>
<blockquote>
<p><strong>표준 빌트인 생성자 함수와 빌트인 메서드</strong>
자바스크립트에서 기본 제공하는 함수
표준 빌트인 생성자 함수 : 객체를 생성하기 위한 함수이며 new 연산자와 함께 호출한다.
표준 빌트인 메서드 : 자바스크립트에서 기본 제공하는 빌트인 객체의 메서드</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[프로그래머스 <정수 내림차순으로 배치하기>]]></title>
            <link>https://velog.io/@seul-bean/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%A0%95%EC%88%98-%EB%82%B4%EB%A6%BC%EC%B0%A8%EC%88%9C%EC%9C%BC%EB%A1%9C-%EB%B0%B0%EC%B9%98%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@seul-bean/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%A0%95%EC%88%98-%EB%82%B4%EB%A6%BC%EC%B0%A8%EC%88%9C%EC%9C%BC%EB%A1%9C-%EB%B0%B0%EC%B9%98%ED%95%98%EA%B8%B0</guid>
            <pubDate>Tue, 01 Aug 2023 17:22:42 GMT</pubDate>
            <description><![CDATA[<h2 id="🍎-정수-내림차순으로-배치하기">🍎 정수 내림차순으로 배치하기</h2>
<p><a href="https://school.programmers.co.kr/learn/courses/30/lessons/12933">https://school.programmers.co.kr/learn/courses/30/lessons/12933</a></p>
<p><strong>문제 설명</strong>
함수 solution은 정수 n을 매개변수로 입력받습니다. 
n의 각 자릿수를 큰것부터 작은 순으로 정렬한 새로운 정수를 리턴해주세요. 
예를들어 n이 118372면 873211을 리턴하면 됩니다.</p>
<p><strong>제한 조건</strong>
n은 1이상 8000000000 이하인 자연수입니다.</p>
<br>

<hr>
<br>

<h2 id="🍎-내가-생각한-solution">🍎 내가 생각한 solution</h2>
<p>처음에 문제를 잘못 이해하고 배열을 냅다 반대로 돌려버렸는데 잘못됨을 느끼고 아래처럼 풀게 되었다.
일단 내림차순 정렬을 위해 n을 문자로 만들어서 split으로 &quot;&quot;기준으로 쪼개주고, sort b-a해서 내림차순으로 정렬시켜줬다.
그 후 forEach를 돌려서 배열에서 꺼내주고 마지막 return 해줄때 숫자형으로 형변환 시켜주었다.</p>
<pre><code class="language-javascript">function solution(n) {
    var answer = 0;
    const arr=String(n).split(&quot;&quot;).sort((a,b)=&gt;b-a)
    arr.forEach((num)=&gt;{
        answer+=num
    })
    return Number(answer);
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[30일차 리액트에서 불변성 왜 중요한가?]]></title>
            <link>https://velog.io/@seul-bean/%EB%A6%AC%EC%95%A1%ED%8A%B8%EC%97%90%EC%84%9C-%EB%B6%88%EB%B3%80%EC%84%B1-%EC%99%9C-%EC%A4%91%EC%9A%94%ED%95%9C%EA%B0%80</link>
            <guid>https://velog.io/@seul-bean/%EB%A6%AC%EC%95%A1%ED%8A%B8%EC%97%90%EC%84%9C-%EB%B6%88%EB%B3%80%EC%84%B1-%EC%99%9C-%EC%A4%91%EC%9A%94%ED%95%9C%EA%B0%80</guid>
            <pubDate>Mon, 31 Jul 2023 16:39:14 GMT</pubDate>
            <description><![CDATA[<h1 id="🍎-리액트에서-불변성-왜-중요한가">🍎 리액트에서 불변성 왜 중요한가?</h1>
<h2 id="🌳-불변성-정의">🌳 불변성 정의</h2>
<p>한 번 생성된 원본 데이터는 변경시키지 않고, 데이터 변경 필요시 새로운 원본을 만드는 디자인 패턴</p>
<p><strong>불변성 X → mutable</strong>
원본 데이터가 변할 수 있다는 의미 <span style="color:green">(push 메서드)</span></p>
<p><strong>불변성 O → immutable</strong>
원본 데이터가 변할 수 없다는 의미 <span style="color:green">(map 메서드)</span></p>
<br>

<h2 id="🌳-불변성의-중요성--문제점">🌳 불변성의 중요성 / 문제점</h2>
<p><strong>문제점 1.</strong>
<span style="color:gray"><em>원본과 수정된 값의 주소값이 같으면 불변성이 유지 X → 렌더링 되지 X</em></span>
리액트는 state 변경 전 후의 값을 <span style="color:red">얕은 비교</span>하여 <span style="color:red">다른 경우에만</span> 리렌더링
얕은 비교 → 참조 값의 경우 주소끼리 비교. 원시값은 데이터값 그 자체끼리 비교.</p>
<p><strong>문제점 2.</strong>
Side Effect 부작용을 일으킬 수 있다.</p>
<p>객체의  내부에 데이터에 직접 변경을 가하는 방식으로 개발할 경우.
명령형 / 절차적 프로그래밍하게 되어 규모있는 프로젝트를 만들게 되면 유지보수가 어려워진 스파게티 코드를 보게될 확률이 높다.</p>
<br>

<p>불변성을 지키는 수단
<strong>-spread Operator</strong></p>
<pre><code class="language-javascript">setObj({...obj, age:obj.age+1})</code></pre>
<p>depth가 깊은 객체라면 다소 가독성이 떨어지고 복잡해 보임.</p>
<p><strong>-불변성 지원 라이브러리(immer.js)</strong>
depth가 깊은 중첩 객체를 상태로 가질 경우, 불변성 여부를 점검하기 어려워지기 때문에, mutable한 문법으로도 불변성을 지킬 수 있는 immer 라이브러리를 사용을 권장.</p>
<pre><code class="language-javascript">setObj(produce(draftObj=&gt;{draftObj.contact.email=newEmail;}))</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[11주차 Week I Learned]]></title>
            <link>https://velog.io/@seul-bean/qtlvd79k</link>
            <guid>https://velog.io/@seul-bean/qtlvd79k</guid>
            <pubDate>Sun, 30 Jul 2023 15:04:49 GMT</pubDate>
            <description><![CDATA[<p><em>이번주는 주특기 플러스 기간으로 타입스크립트에 대해 배우는 주였다.</em>
타입스크립트를 배워서 이전에 제출했던 TodoList 과제를 리팩토링하는 과제가 있었다.</p>
<h2 id="🌱-일주일-총-요약">🌱 일주일 총 요약</h2>
<p>팀프로젝트 과제 (아웃소싱 프로젝트(지도, 유튜브, 설문))</p>
<h2 id="🌱-일주일동안-새로-알게-된-사항">🌱 일주일동안 새로 알게 된 사항</h2>
<p>타입스크립트(JavaScript의 약점, 튜플, enum, any &amp; unknown &amp; union, 인터페이스, 객체 지향 설계 원칙 - S.O.L.I.D 등)</p>
<h2 id="🌱-일주일동안-느낀-점">🌱 일주일동안 느낀 점</h2>
<p>타입스크립트란 정말 하나하나 타입들을 지정해주는거로구나..라는걸 알게되었고 과제를 진행하면서 props를 내려줄때마다 빨간줄이 뜨는것을 보고 아주아주 한참 멀었구나를 느끼게 되었다.</p>
<h2 id="🌱-다음주-목표">🌱 다음주 목표</h2>
<p>다음주도 타입스크립트를 배움에 있어 적극적인 자세로 임하기
aws도 열심히 강의 듣기
하루하루 목표를 잘 세워서 알차게 하루 보내기
알고리즘 문제 한문제씩이라도 꼭 풀기
하루에 메서드 1개씩 알아가기
아침 7시에 일어나기
새벽 2시에는 자기</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[프로그래머스 <n보다 커질 때까지 더하기
>]]></title>
            <link>https://velog.io/@seul-bean/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-n%EB%B3%B4%EB%8B%A4-%EC%BB%A4%EC%A7%88-%EB%95%8C%EA%B9%8C%EC%A7%80-%EB%8D%94%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@seul-bean/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-n%EB%B3%B4%EB%8B%A4-%EC%BB%A4%EC%A7%88-%EB%95%8C%EA%B9%8C%EC%A7%80-%EB%8D%94%ED%95%98%EA%B8%B0</guid>
            <pubDate>Thu, 27 Jul 2023 19:00:42 GMT</pubDate>
            <description><![CDATA[<h2 id="🍎-n보다-커질-때까지-더하기">🍎 n보다 커질 때까지 더하기</h2>
<p><a href="https://school.programmers.co.kr/learn/courses/30/lessons/181884">https://school.programmers.co.kr/learn/courses/30/lessons/181884</a></p>
<p><strong>문제 설명</strong>
정수 배열 numbers와 정수 n이 매개변수로 주어집니다. numbers의 원소를 앞에서부터 하나씩 더하다가 그 합이 n보다 커지는 순간 이때까지 더했던 원소들의 합을 return 하는 solution 함수를 작성해 주세요.</p>
<p><strong>제한사항</strong>
1 ≤ numbers의 길이 ≤ 100
1 ≤ numbers의 원소 ≤ 100
0 ≤ n &lt; numbers의 모든 원소의 합</p>
<p><strong>입출력 예 #1</strong></p>
<p>예제 1번의 numbers를 문제 설명대로 더해가는 과정을 나타내면 다음의 표와 같습니다.</p>
<p>예제 2번의 numbers의 마지막 원소 전까지의 원소를 sum에 더하면 139입니다. 139는 n 값인 139보다 크지 않고 마지막 원소인 100을 더하면 139보다 커지므로 239를 return 합니다.</p>
<br>

<hr>
<br>

<h2 id="🍎-내가-생각한-solution">🍎 내가 생각한 solution</h2>
<p>요즘 forEach문만 엄청 쓰는거 같다..</p>
<pre><code class="language-javascript">function solution(numbers, n) {
    var answer = 0;
    numbers.forEach((num)=&gt;{
        if(answer&lt;=n){
            answer+=num
        }
    })
    return answer; 
}</code></pre>
]]></description>
        </item>
    </channel>
</rss>