<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>slow 개발 일지</title>
    <link>https://songji.tistory.com/</link>
    <description>개발자 songji 님의 블로그입니다 :)
Go back in a hurry.</description>
    <language>ko</language>
    <pubDate>Mon, 5 Oct 2026 14:33:16 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>__songji__</managingEditor>
    <image>
      <title>slow 개발 일지</title>
      <url>https://tistory1.daumcdn.net/tistory/5279516/attach/c35482b2aa6249eca8c532f614a5aba1</url>
      <link>https://songji.tistory.com</link>
    </image>
    <item>
      <title>React Context</title>
      <link>https://songji.tistory.com/7</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이전 포스팅 &lt;a href=&quot;https://songji.tistory.com/5&quot;&gt;Redux와 Ducks Pattern&lt;/a&gt;에 연장성으로 React Context API 에 대해 알아보자.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;React Context&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #999999;&quot;&gt;react 16.3 버전부터, &lt;span&gt;context api&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #999999;&quot;&gt;를 내장하여 정식적으로 지원한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 컴포넌트에서 접근가능한 전역상태를 생성하여, props를 일일이 전달해야하는 props-drilling을 보완할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(props-drilling :&amp;nbsp; &lt;a href=&quot;https://songji.tistory.com/5&quot;&gt;Redux와 Ducks Pattern&lt;/a&gt; 참고)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Context의 주요 개념은 &lt;b&gt;context, context provider, context consumer&lt;/b&gt; 정도로 보면 된다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;1. createContext&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;전역상태를 저장하는 context 생성&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;2. provider&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;리액트 컴포넌트&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;전역 상태의 데이터를 초기화&lt;/li&gt;
&lt;li&gt;전역 상태를 하위 컴포넌트들에게 제공&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;3. consumer&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;리액트 컴포넌트&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;provider로부터 제공받은 전역상태를 조회&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;&lt;span style=&quot;color: #f89009; font-family: 'Nanum Gothic'; background-color: #eeeeee;&quot;&gt;&lt;b&gt;useContext(MyContext)&lt;/b&gt;&lt;/span&gt;, &lt;span style=&quot;color: #f89009; font-family: 'Nanum Gothic'; background-color: #eeeeee;&quot;&gt;&lt;b&gt;static contextType = MyContext&lt;/b&gt;&lt;/span&gt; 또는&amp;nbsp; &lt;span style=&quot;background-color: #eeeeee;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #f89009; font-family: 'Nanum Gothic';&quot;&gt;&amp;lt;MyContext.Consumer&amp;gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt; 모두 Context Consumer에 해당&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;Context Api 예제&lt;/blockquote&gt;
&lt;pre id=&quot;code_1650020076008&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React, { useContext } from &quot;react&quot;;

const CounterContext = React.createContext(); // 1. context 생성

export default function App() {
	
  // 2. Provider로 context 제공
  return (
    &amp;lt;CounterContext.Provider value=&quot;0&quot;&amp;gt;
      &amp;lt;Counter /&amp;gt;
      &amp;lt;CountButton /&amp;gt;
    &amp;lt;/CounterContext.Provider&amp;gt;
  );
}

const Counter = () =&amp;gt; {
  const count = useContext(CounterContext); // 3. Consumer로 context 접근

  return &amp;lt;div&amp;gt;{count}&amp;lt;/div&amp;gt;;
};

const CountButton = () =&amp;gt; {
  const count = useContext(CounterContext); // 3. Consumer로 context 접근

  return &amp;lt;button&amp;gt; + &amp;lt;/button&amp;gt;;
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대게 Context를 &lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;b&gt;상태관리도구&lt;/b&gt;&lt;/span&gt;라고 일컫지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 예제와 같이,&lt;b&gt; Context가 제공하는 메소드만으로는 redux의 reducer나, react의 setState처럼 상태를 직접적으로 변경하고 관리할 수 없다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;상태를 변경하고 관리할수 없는 &lt;b&gt;Context 자체만으로는&lt;/b&gt; 완전한 상태관리도구라고 부르기에는 알맞지 않은듯하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면 위의 예제의 button을 클릭하여 context의 값을 어떻게 변경할 수 있을까?&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Context 상태를 변경하는 방법에는 여러가지 방법이 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Class Component&lt;/b&gt; :&amp;nbsp; &lt;b&gt;component state&lt;/b&gt; 활용 (&lt;a href=&quot;https://ko.reactjs.org/docs/context.html#dynamic-context&quot;&gt;Class component에서 값이 변하는 Context 만들기 참고&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Function Component&lt;/b&gt; : &lt;b&gt;usetState, useReducer&lt;/b&gt; 등을 활용&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 예제를 usetState를 활용해서 상태가 업데이트되도록 수정해보자.&lt;/p&gt;
&lt;pre id=&quot;code_1650020919840&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import &quot;./styles.css&quot;;
import React, { useContext, useState } from &quot;react&quot;;

const CounterContext = React.createContext(); // 1. context 생성


// 2. Provider 생성 : useState로 상태값 관리
const CounterProvider = ({ children }) =&amp;gt; {
  const [count, setCount] = useState(0);

  return (
    &amp;lt;CounterContext.Provider value={[count, setCount]}&amp;gt;
      {children}
    &amp;lt;/CounterContext.Provider&amp;gt;
  );
};


// 2-2. Provider로 context 제공
export default function App() {
  return (
    &amp;lt;CounterProvider&amp;gt;
      &amp;lt;Counter /&amp;gt;
      &amp;lt;CountButton /&amp;gt;
    &amp;lt;/CounterProvider&amp;gt;
  );
}


const Counter = () =&amp;gt; {
  const [count] = useContext(CounterContext); // 3. Consumer로 context 접근

  return &amp;lt;div&amp;gt;{count}&amp;lt;/div&amp;gt;;
};

const CountButton = () =&amp;gt; {
  const [,setCount] = useContext(CounterContext); // 3. Consumer로 context 접근

  return &amp;lt;button onClick={() =&amp;gt; setCount((count) =&amp;gt; count+1)} &amp;gt; + &amp;lt;/button&amp;gt;;
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 위의 Counter context는 상태가 업데이트가 가능해졌다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 여기서 더 생각해볼 점이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상태값 count가 업데이트되며느 &amp;lt;Counter&amp;gt; 뿐만 아니라,&amp;nbsp; &amp;lt;CounterButton&amp;gt;도 함께 리렌더링이 이루어진다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;512&quot; data-origin-height=&quot;398&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cKRzxT/btrzuOF51k7/4rFohjWUNyYeYQFztotTI1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cKRzxT/btrzuOF51k7/4rFohjWUNyYeYQFztotTI1/img.png&quot; data-alt=&quot;countButton 실행했을 때의 콘솔로그 결과값&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cKRzxT/btrzuOF51k7/4rFohjWUNyYeYQFztotTI1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcKRzxT%2FbtrzuOF51k7%2F4rFohjWUNyYeYQFztotTI1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;279&quot; height=&quot;218&quot; data-origin-width=&quot;512&quot; data-origin-height=&quot;398&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;countButton 실행했을 때의 콘솔로그 결과값&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것은 불필요한 렌더링이 이루어지고 있는 것이다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;이런 부분 또한 Context의 단점으로, Context가 온전한 상태관리도구라고 할 수 없다는 점이다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;불필요한 리렌더링을 방지하기 위해서, 다시 코드를 수정해보자.&lt;/p&gt;
&lt;pre id=&quot;code_1650022982551&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import &quot;./styles.css&quot;;
import React, { useContext, useState } from &quot;react&quot;;

// ** Context를 두가지로 분리
const CounterContext = React.createContext();
const CounterDispatchContext = React.createContext(() =&amp;gt; {});

// ** Provider 감싸기
const CounterProvider = ({ children }) =&amp;gt; {
  const [count, setCount] = useState(0);

  return (
    &amp;lt;CounterContext.Provider value={count}&amp;gt;
      &amp;lt;CounterDispatchContext.Provider value={setCount}&amp;gt;
        {children}
      &amp;lt;/CounterDispatchContext.Provider&amp;gt;
    &amp;lt;/CounterContext.Provider&amp;gt;
  );
};

export default function App() {
  return (
    &amp;lt;CounterProvider&amp;gt;
      &amp;lt;Counter /&amp;gt;
      &amp;lt;CountButton /&amp;gt;
    &amp;lt;/CounterProvider&amp;gt;
  );
}

const Counter = () =&amp;gt; {
  const count = useContext(CounterContext); // ** CounterContext에만 반응함
  return (
    &amp;lt;div&amp;gt;
      &amp;lt;div&amp;gt;{count}&amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  );
};

const CountButton = () =&amp;gt; {
  const setCount = useContext(CounterDispatchContext); // ** CounterDispatchContext에만 반응함
  return (
    &amp;lt;button onClick={() =&amp;gt; setCount((count) =&amp;gt; count + 1)}&amp;gt; + &amp;lt;/button&amp;gt;
  );
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;528&quot; data-origin-height=&quot;232&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/N28lf/btrzxyBjKYR/AZ1I7Gos8RhK2VA82XHVJk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/N28lf/btrzxyBjKYR/AZ1I7Gos8RhK2VA82XHVJk/img.png&quot; data-alt=&quot;countButton 실행했을 때의 콘솔로그 결과값&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/N28lf/btrzxyBjKYR/AZ1I7Gos8RhK2VA82XHVJk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FN28lf%2FbtrzxyBjKYR%2FAZ1I7Gos8RhK2VA82XHVJk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;337&quot; height=&quot;148&quot; data-origin-width=&quot;528&quot; data-origin-height=&quot;232&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;countButton 실행했을 때의 콘솔로그 결과값&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 최종적으로 나름 괜찮은 상태관리가되는 Context를 만들보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 상태관리를 해야하는 코드가 많아진다면, Provider Hell에 빠질 수 밖에 없을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 포스팅에서는 다소 Context Api가 부정적으로 보여질 수 있지만, Context Api 만의 장점은 분명히 존재한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 상태관리를 사용해야하는데에는 정답이 없기에, 상황에 따라 잘 판단하여 잘 활용해볼 수 있도록 하자 !&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;✅ Context의 장점&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;구조가 비교적 간단하다.
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;Redux도 내부적으로는 Context로 이루어져 있다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;간단한 전역 상태 또는 정적인 전역상태가 필요하다면, Context를 적극적으로 사용하자.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;코드가 비교적 간결하다.&lt;/li&gt;
&lt;li&gt;여러개의 Context를 생성할 수 있고, 가시적이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;✅&lt;span&gt; &amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;Context의&amp;nbsp;단점&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;context만으로 상태관리를 할 수 없다.
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;context로 상태관리를 해야하는 경우에는
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&amp;nbsp;high-frequency한 어플리케이션에서는 성능 이슈가 있을 수 있다.&lt;/li&gt;
&lt;li&gt;Provider Hell을 야기할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://yrnana.dev/post/2021-08-21-context-api-redux&quot;&gt;https://yrnana.dev/post/2021-08-21-context-api-redux&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://olaf-go.medium.com/context-api-vs-redux-e8a53df99b8&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://olaf-go.medium.com/context-api-vs-redux-e8a53df99b8&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ko.reactjs.org/docs/hooks-reference.html#usecontext&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://ko.reactjs.org/docs/hooks-reference.html#usecontext&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://velog.io/@cada/React-Redux-vs-Context-API#context-api%EB%9E%80-&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://velog.io/@cada/React-Redux-vs-Context-API#context-api%EB%9E%80-&lt;/a&gt;&lt;/p&gt;</description>
      <category>reactjs</category>
      <category>context</category>
      <category>JavaScript</category>
      <category>REACT</category>
      <category>react-context</category>
      <category>Redux</category>
      <author>__songji__</author>
      <guid isPermaLink="true">https://songji.tistory.com/7</guid>
      <comments>https://songji.tistory.com/7#entry7comment</comments>
      <pubDate>Fri, 15 Apr 2022 21:09:43 +0900</pubDate>
    </item>
    <item>
      <title>환경변수 / 멀티 환경변수</title>
      <link>https://songji.tistory.com/6</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;200&quot; data-origin-height=&quot;200&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UIMYL/btrxXL98koT/VRNHQA7uRu8K74pHTYR3z1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UIMYL/btrxXL98koT/VRNHQA7uRu8K74pHTYR3z1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UIMYL/btrxXL98koT/VRNHQA7uRu8K74pHTYR3z1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUIMYL%2FbtrxXL98koT%2FVRNHQA7uRu8K74pHTYR3z1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;200&quot; height=&quot;200&quot; data-origin-width=&quot;200&quot; data-origin-height=&quot;200&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;nodejs에서는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트 환경에서 노출되면 안되는 정보, 전역에서 필요한 정보 등을 관리할 수 있는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;dotenv(환경변수)를 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;a href=&quot;https://www.npmjs.com/package/dotenv&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;dotenv npm&lt;/a&gt;&lt;/blockquote&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;전역으로 필요한 정보 관리&lt;/li&gt;
&lt;li&gt;보안 정보 관리&lt;span&gt;&amp;nbsp;&lt;/span&gt;:&lt;span&gt;&amp;nbsp;&lt;/span&gt;외부에 노출이 되면 안 되는 정보 ( 세션키 , 개인정보 ( host, user, password ..) 등 ... )&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;a id=&quot;user-content-1-dotenv-패키지설치&quot; href=&quot;https://github.com/songji1165/songji1165.github.io/blob/build/source/_posts/node.js/%ED%99%98%EA%B2%BD%EB%B3%80%EC%88%98.md#1-dotenv-%ED%8C%A8%ED%82%A4%EC%A7%80%EC%84%A4%EC%B9%98&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;1. dotenv 패키지설치&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;shell&quot; data-ke-language=&quot;shell&quot;&gt;&lt;code&gt;npm i --save dotenv&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;a id=&quot;user-content-2-env-파일-생성-후-db정보-입력&quot; href=&quot;https://github.com/songji1165/songji1165.github.io/blob/build/source/_posts/node.js/%ED%99%98%EA%B2%BD%EB%B3%80%EC%88%98.md#2-env-%ED%8C%8C%EC%9D%BC-%EC%83%9D%EC%84%B1-%ED%9B%84-db%EC%A0%95%EB%B3%B4-%EC%9E%85%EB%A0%A5&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;2. env 파일 생성&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;// .env
DB_USERNAME = song
DB_PASSWORD = 1165&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;a id=&quot;user-content-4-비밀정보가-들어갈-해당-파일에-환경변수-입력&quot; href=&quot;https://github.com/songji1165/songji1165.github.io/blob/build/source/_posts/node.js/%ED%99%98%EA%B2%BD%EB%B3%80%EC%88%98.md#4-%EB%B9%84%EB%B0%80%EC%A0%95%EB%B3%B4%EA%B0%80-%EB%93%A4%EC%96%B4%EA%B0%88-%ED%95%B4%EB%8B%B9-%ED%8C%8C%EC%9D%BC%EC%97%90-%ED%99%98%EA%B2%BD%EB%B3%80%EC%88%98-%EC%9E%85%EB%A0%A5&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;3. 환경변수 접근 예시&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;import dotenv from 'dotenv'

dotenv.config()

process.env.DB_USERNAME
process.env.DB_PASSWORD&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;require('dotenv').config()

const db = require(&quot;db&quot;)
db.connect({
  key: process.env.SESSION_SECRET
})&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;4. 멀티 환경변수&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로 개발환경/배포환경에 따라 설정값이 달라지게 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 환경별로 환경변수를 선언을 한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;.env&lt;/b&gt; : 기본&lt;/li&gt;
&lt;li&gt;&lt;b&gt;.env.local&lt;/b&gt; : 로컬 재정의 , test 환경을 제외한 모든 환경에 대해 로드&lt;/li&gt;
&lt;li&gt;.&lt;b&gt;env.development&lt;/b&gt; : 환경별 설정 (.env.test / .env.production)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;.env.development&lt;/b&gt; : 환결병 설정 로컬 재정의 (.env.test / .env.production)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;cross-env&lt;/b&gt; 라이브러리를 같이 활용하면, cli 에서 환경값을 설정하여, 환경에 따른 환경변수를 채택할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1648565964753&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm i -s cross-env&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;shell&quot; data-ke-language=&quot;shell&quot;&gt;&lt;code&gt;cross-env NODE_ENV=production node config.js&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1648565489308&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import dotenv from 'dotenv'
import path from 'path'

dotenv.config({ path: path.resolve(__dirname, '../env.${process.env.NODE_ENV}')});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;5. React, Next 환경변수&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;CRA 환경변수&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CRA를 설치하면, 환경변수의 우선순위가 자동으로 설정된다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1648567352884&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm run start&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(NODE_ENV = development)&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;.env.development.local&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;.env.local&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;.env.development&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;.env&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1648567657701&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm run build&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;(NODE_ENV =&lt;span&gt; production&lt;/span&gt;&lt;/span&gt;)&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;.env.production.local&lt;/li&gt;
&lt;li&gt;.env.local&lt;/li&gt;
&lt;li&gt;.env.development&lt;/li&gt;
&lt;li&gt;.env&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1648567744220&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm run test&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;(NODE_ENV =&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;test&lt;/span&gt;&lt;/span&gt;)&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;.env.test.local&lt;/li&gt;
&lt;li&gt;.env.test&lt;/li&gt;
&lt;li&gt;.env&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;  NODE_ENV를 제외한 환경변수는 REACT_APP_을 붙여서 변수를 정의해야 한다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;Next 환경변수&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;nextjs의 환경변수는 react의 확장이라고 생각하자. (각 NODE_ENV에 따라, 우선순위도 동일)&lt;/p&gt;
&lt;pre id=&quot;code_1648568830202&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;next dev   // development
next build // production
next start // production
next test  // test&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;  process.env.변수명 :&amp;nbsp; node.js 환경에서 접근가능한 환경변수&lt;br /&gt;  process.env.NEXT_PUBLIC_변수명 :&amp;nbsp; 브라우저 환경에서 접근가능한 환경변수&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;-&amp;nbsp; &lt;b&gt;next.config.js &amp;gt; env 옵션&lt;/b&gt; : NEXT_PUBLIC_과 같은 환경변수로, next.config.js에 정의된 환경변수는 &lt;b&gt;process.env.변수명&lt;/b&gt;으로 접근 가능하다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;Custom .env&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/facebook/create-react-app/issues/3903&quot;&gt;custom .env 참고&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;react와 next처럼&amp;nbsp; 내부적으로 이미 예약된 NODE_ENV(development, production, test)는 변경이 까다롭지만,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;env-cmd&lt;/b&gt; 라이브러리를 사용하면, 좀 더 간편하게 환경변수를 변경할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;env-cmd로 선언한 환경변수가 최우선순위가 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1648570170046&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm i env-cmd&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1648570271636&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// package.json

{
	&quot;scripts&quot; : {
    	&quot;build:dev&quot; : &quot;env-cmd -f .env.development next build&quot;
    },
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://create-react-app.dev/docs/adding-custom-environment-variables/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://create-react-app.dev/docs/adding-custom-environment-variables/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://velog.io/@public_danuel/process-env-on-node-js&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://velog.io/@public_danuel/process-env-on-node-js&lt;/a&gt;​&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://nextjs.org/docs/basic-features/environment-variables&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://nextjs.org/docs/basic-features/environment-variables&lt;/a&gt;​&lt;/p&gt;</description>
      <category>nodejs</category>
      <category>CRA</category>
      <category>cross-env</category>
      <category>dotenv</category>
      <category>env</category>
      <category>JavaScript</category>
      <category>nextJS</category>
      <category>node.js</category>
      <category>REACT</category>
      <author>__songji__</author>
      <guid isPermaLink="true">https://songji.tistory.com/6</guid>
      <comments>https://songji.tistory.com/6#entry6comment</comments>
      <pubDate>Wed, 30 Mar 2022 01:12:11 +0900</pubDate>
    </item>
    <item>
      <title>Redux와 Ducks Pattern</title>
      <link>https://songji.tistory.com/5</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;Redux&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;react는 상태를 자식 컴포넌트로 전달, 전달하는 방식으로,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전달의 단계가 많아진다면 상당히 복잡한 구조가 되고, 리소스 낭비가 되곤한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;515&quot;&gt;&lt;a href=&quot;https://pagepro.co/blog/what-is-react-context-and-how-to-use-it/&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQ9I0D/btrw9NonSq9/IYnqKzE7YkO1pB6VqLaZo0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQ9I0D%2Fbtrw9NonSq9%2FIYnqKzE7YkO1pB6VqLaZo0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;733&quot; height=&quot;369&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;515&quot;/&gt;&lt;/a&gt;&lt;figcaption&gt;props-driliing&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 전달의 구조가 깊어지는 것을 &lt;b&gt;props-drilling&lt;/b&gt;이라고 부른다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 props-driliing을 해소하기 위해, 전역에서 상태관리가 가능한 여러방법들이 존재한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;context api, redux, mobx ,, 등 여러가지 방법이 있는데,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 방법 중, 우리나라에서 가장 사용률이 높은 redux에 관해 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;redux는 &lt;b&gt;전역 상태 저장소(store)&lt;/b&gt;를 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;react의 모든 컴포넌트는 이 store에 접근 가능하다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1834&quot; data-origin-height=&quot;1080&quot;&gt;&lt;a href=&quot;https://eatnug.github.io/frontend/react-redux/&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oO1pv/btrxcaXWjgp/eZGX1KUqeBekhjd1n40R8K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoO1pv%2FbtrxcaXWjgp%2FeZGX1KUqeBekhjd1n40R8K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;669&quot; height=&quot;394&quot; data-origin-width=&quot;1834&quot; data-origin-height=&quot;1080&quot;/&gt;&lt;/a&gt;&lt;figcaption&gt;without Redux vs with Redux&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 그림과 같이 redux를 사용하게 되면, Store를 통해 상태의 관계를 맺게 되기 때문에, 좀 더 편한 상태전달이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;Redux 개념&lt;/b&gt;&lt;/blockquote&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Store&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앱의 전역 상태를 갖는 저장소&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;store는 독립적이고 무결성을 보장해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;store의 상태를 변경하는 요소는 action 뿐이다.&lt;/p&gt;
&lt;pre id=&quot;code_1648121671903&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { createStore } from 'redux';
import todoApp from './reducers';

// Reducer들을 store에 넘겨 연결하기
let store = createStore(todoApp);&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Action&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상태 변화에 대한 정보를 담은 객체 (순수 자바스크립트의 object 타입)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;액션 객체는 상태에 행위를 나타내는&amp;nbsp; type 문자열 필수&lt;/p&gt;
&lt;pre id=&quot;code_1648119518571&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{ type: &quot;ADD_TODO&quot;, todo: 'to do list item' }&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Action Creater&amp;nbsp;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Dispatch에 인자로 전달하기 위해, Action을 함수로 감싼 형태&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;즉, Action을 Return하는 함수로, 최종적으로 해당 액션이 호출됨&lt;/p&gt;
&lt;pre id=&quot;code_1648120965791&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function addTodo(todo) {
  return {
    type: ADD_TODO,
    todo
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Reducer&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;액션에 대한 함수를 정의하고, 함수를 실행하여 상태를 업데이트&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529;&quot;&gt;상태의 Data를 변화시키는 개념이 아닌, 상태변화한 Data를 &lt;b&gt;새로운 상태로 Store에 반환하는 것&lt;/b&gt;이 상태 업데이트라고 생각하자.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1648119690436&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export default function reducer(state, action){
	...
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Dispatch&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;액션을 Reducer에 전달&lt;/p&gt;
&lt;pre id=&quot;code_1648121995017&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;store.dispatch(addTodo('Learn about Redux'));&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;Redux 원칙&lt;/b&gt;&lt;/blockquote&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;앱의 전역상태는 단일 저장소 내의 트리에 저장된다. (단일 Redux Store)&lt;/li&gt;
&lt;li&gt;상태는 읽기 전용 (Read-Only)&lt;/li&gt;
&lt;li&gt;상태는 순수 함수에 의해서 변경되어야 한다.( Action &amp;amp; Action Creator)&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;Redux Flow&lt;/b&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;500&quot;&gt;&lt;a href=&quot;https://velog.io/@kimhr08/Redux-%EB%9E%80&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c9cbnt/btrxdO7IqlR/Mllk3USEFudgKRkCKK42m0/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc9cbnt%2FbtrxdO7IqlR%2FMllk3USEFudgKRkCKK42m0%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;722&quot; height=&quot;361&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;500&quot;/&gt;&lt;/a&gt;&lt;figcaption&gt;Redux Flow&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Component에서 이벤트 발생&lt;/li&gt;
&lt;li&gt;이벤트에 해당하는 &lt;b&gt;Action Creator&lt;/b&gt;를&amp;nbsp; &lt;b&gt;Dispatch&lt;/b&gt;에&amp;nbsp; 전달&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Dispatch&lt;/b&gt;가 ActionCreator에서 생성된 &lt;b&gt;Action&lt;/b&gt;을 &lt;b&gt;Reducer&lt;/b&gt;에 전달 및 실행&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Reducer&lt;/b&gt;는 Action에 타입에 따라 정의된 함수를 실행하여, &lt;b&gt;새로운 상태로 업데이트&lt;/b&gt;&amp;nbsp; &lt;br /&gt;&lt;span style=&quot;background-color: #f6e199; color: #666666;&quot;&gt;&amp;nbsp;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt; reducer(prevState, action)&amp;nbsp;&lt;/span&gt;&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;Component 렌더링&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;Redux sample code&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아주 간단한 redux 예제를 만들어보자. (to do list)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; background-color: #f6e199; color: #666666;&quot;&gt;react &amp;amp; redux 셋팅&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1648126200918&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npx create-react-app my-project  
npm install --save react-redux&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;* 파일구조 *&lt;br /&gt;- src&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; - actions / index.js&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; - reducers / index.js&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; - index.js&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; - App.js&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; background-color: #f6e199; color: #666666;&quot;&gt;src/actions/index.js&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1648126246330&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export const ADD_TODO = 'ADD_TODO';
export const addTodo = (todo) =&amp;gt; {
    return {
        type: ADD_TODO,
        todo
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; background-color: #f6e199; color: #666666;&quot;&gt;src/reducers/index.js&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1648126403891&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import {combineReducers} from 'redux';
import {ADD_TODO} from &quot;../actions&quot;;


const todoState = {
    todos : []
}

const todoReducer = (state = todoState, action) =&amp;gt; {
    switch (action.type){
        case ADD_TODO:
            return {...state, todos: state.todos.concat(action.todo)}
        default:
            return state
    }
}

// combineReducers : 여러개의 리듀서를 하나로 합쳐주는 메서드
const AppReducer = combineReducers({
    todoReducer
})

export default AppReducer;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; background-color: #f6e199; color: #666666;&quot;&gt;src/index.js&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1648126454549&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import {createStore} from 'redux'
import reducers from &quot;./reducers&quot;;
import {Provider} from &quot;react-redux&quot;;

const store = createStore(reducers);

ReactDOM.render(
    &amp;lt;React.StrictMode&amp;gt;
        &amp;lt;Provider store={store}&amp;gt;
            &amp;lt;App/&amp;gt;
        &amp;lt;/Provider&amp;gt;
    &amp;lt;/React.StrictMode&amp;gt;,
    document.getElementById('root')
);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; background-color: #f6e199; color: #666666;&quot;&gt;src/App.js&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1648129214975&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import {useDispatch, useSelector} from &quot;react-redux&quot;;
import {useState} from &quot;react&quot;;
import {addTodo} from &quot;./actions&quot;;


function App() {
    const [text, setText] = useState(&quot;&quot;);

    // store에 접근하여 state 가져오기
    const { todos } = useSelector(state =&amp;gt; state.todoReducer);

    // dispatch를 사용하기 위한 준비
    const dispatch = useDispatch();
    const add = () =&amp;gt; {
        // store에 있는 state 바꾸는 함수 실행
        dispatch(addTodo(text));
    };
  return (
    &amp;lt;div className=&quot;App&quot;&amp;gt;
      &amp;lt;h1 className=&quot;App-header&quot;&amp;gt;
          To Do List
      &amp;lt;/h1&amp;gt;
        &amp;lt;ul&amp;gt;
            {todos.map((item, idx)=&amp;gt;(
                &amp;lt;li key={idx}&amp;gt;{item}&amp;lt;/li&amp;gt;
            ))}
        &amp;lt;/ul&amp;gt;
        &amp;lt;div&amp;gt;
            &amp;lt;input type=&quot;text&quot; onChange={(e)=&amp;gt;setText(e.currentTarget.value)} value={text}/&amp;gt;
            &amp;lt;button onClick={()=&amp;gt;add()}&amp;gt;할일 추가하기&amp;lt;/button&amp;gt;
        &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

export default App;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 아주 간단한&amp;nbsp; To do List에 추가하는 기능을 Redux로 구현해보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 생각해볼 점이,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 디렉터리 구조로 redux를 계속 추가할 경우, 각 actions와 reducers 폴더를 나누어서 관리를 해주어야 하는 번거로움이 생긴다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 샘플코드와 맞지 않는 조금 앞서나가는 생각이긴 하지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 구조와 같이 실제 리덕스를 작업하다보면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;redux 관련한 코드가 수정이 될 경우 import를 타고가서 actions와 reducers 폴더 모두 확인해보고 수정해야하거나,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리듀서가 많아지면 리듀서가 꼬였을때 어디가 문제인지 파악하는데 어려움이 생기는 등의 여러 불편한 점을 흔히들 경험하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 리덕스의 복잡도를 해소하기 위해, ducks 패턴이란 것이 생겨났다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;Ducks Pattern&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ducks pattern은 자바스크립트 개발자인 Erik Rasmussen이 제안한, 리덕스 사용 방법이다. ( &lt;a href=&quot;https://github.com/erikras/ducks-modular-redux&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ducks pattern 원문&lt;/a&gt; )&lt;span style=&quot;background-color: #000000; color: #24292f;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ducsk pattern은 파일중심이 아닌 &lt;b&gt;모듈 중심&lt;/b&gt;으로 파일을 나눈다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로 redux를 사용하기 위해서는 actionType, actions, reducer 가 함께 추가되어야 하고, action과 reducer가 짝을 이뤄 하나의 redux flow를 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서, &lt;b&gt;ducks pattern은 actionType, actions, reducer를 하나의 파일 안에서 모듈형식으로 관리&lt;/b&gt;하자는 제안을 하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;Ducks Pattern 규칙&lt;/b&gt;&lt;/blockquote&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;항상&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;reducer()란 이름의 함수를&lt;span&gt;&amp;nbsp;&lt;/span&gt;export default&lt;span&gt;&amp;nbsp;&lt;/span&gt;해야합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;항상&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;모듈의 action 생성자들을 함수형태로&lt;span&gt;&amp;nbsp;&lt;/span&gt;export&lt;span&gt;&amp;nbsp;&lt;/span&gt;해야합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;항상&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;npm-module-or-app/reducer/ACTION_TYPE&lt;span&gt;&amp;nbsp;&lt;/span&gt;형태의 action 타입을 가져야합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;경우에 따라,&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;action 타입들을&lt;span&gt;&amp;nbsp;&lt;/span&gt;UPPER_SNAKE_CASE로&lt;span&gt;&amp;nbsp;&lt;/span&gt;export&lt;span&gt;&amp;nbsp;&lt;/span&gt;할 수 있습니다. &lt;br /&gt;만약, 외부&lt;span&gt;&amp;nbsp;&lt;/span&gt;reducer가 해당 action들이 발생하는지 계속 기다리거나, 재사용할 수 있는 라이브러리로 퍼블리싱할 경우에 말이죠.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;재사용가능한 Redux 라이브러리 형태로 공유하는&lt;span&gt;&amp;nbsp;&lt;/span&gt;{actionType, action, reducer}&lt;span&gt;&amp;nbsp;&lt;/span&gt;묶음에도 위 규칙을 추천합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;Redux sample code -&amp;gt; Ducks Pattern sample code&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞에서 작성해보았던 Redux sample code를 Ducks Pattern으로 변경해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;* 파일구조 *&lt;br /&gt;- src&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; - &lt;b&gt;store&lt;/b&gt; &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; - index.js&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; - todo.js&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; - index.js&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; - App.js&lt;br /&gt;&lt;br /&gt;✅ ducks pattern에서 리덕스 디렉터리는 &lt;b&gt;store&lt;/b&gt; 또는 &lt;b&gt;modules&lt;/b&gt; 로 많이 사용된다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; background-color: #f6e199; color: #666666;&quot;&gt;src/store/todo.js&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1648132270890&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;
// 1. 액션타입
export const ADD_TODO = 'todo/ADD_TODO';

// 2. 액션 creator
export const addTodo = (todo) =&amp;gt; {
    return {
        type: ADD_TODO,
        todo
    }
}

// 3. 모듈의 상태 초기값
const initTodoState = {
    todos : []
};

// 4. 리듀서
export default function todoReducer(state = initTodoState, action) {
    switch (action.type){
        case ADD_TODO:
            return {...state, todos: state.todos.concat(action.todo)}
        default:
            return state
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199; color: #666666; font-family: 'Nanum Gothic';&quot;&gt;src/store/index.js&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1648134039219&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { combineReducers } from 'redux';
import todoReducer from &quot;./todo&quot;;

const AppReducer = combineReducers({
    todoReducer,
});


export default AppReducer;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; background-color: #f6e199; color: #666666;&quot;&gt;src/index.js&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1648134093755&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import {createStore} from 'redux'
import reducers from &quot;./store&quot;; // * 경로만 바뀜
import {Provider} from &quot;react-redux&quot;;
import { composeWithDevTools } from 'redux-devtools-extension';


const store = createStore(reducers);

ReactDOM.render(
    &amp;lt;React.StrictMode&amp;gt;
        &amp;lt;Provider store={store}&amp;gt;
            &amp;lt;App/&amp;gt;
        &amp;lt;/Provider&amp;gt;
    &amp;lt;/React.StrictMode&amp;gt;,
    document.getElementById('root')
);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; background-color: #f6e199; color: #666666;&quot;&gt;src/App.js&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1648134131839&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import {useDispatch, useSelector} from &quot;react-redux&quot;;
import {useState} from &quot;react&quot;;
import {addTodo} from &quot;./store/todo&quot;; // * 경로만 바뀜


function App() {
    const [text, setText] = useState(&quot;&quot;);

    const { todos } = useSelector(state =&amp;gt; state.todoReducer);

    const dispatch = useDispatch();
    const add = () =&amp;gt; {
        dispatch(addTodo(text));
    };
  return (
    &amp;lt;div className=&quot;App&quot;&amp;gt;
      &amp;lt;h1 className=&quot;App-header&quot;&amp;gt;
          To Do List
      &amp;lt;/h1&amp;gt;
        &amp;lt;ul&amp;gt;
            {todos.map((item, idx)=&amp;gt;(
                &amp;lt;li key={idx}&amp;gt;{item}&amp;lt;/li&amp;gt;
            ))}
        &amp;lt;/ul&amp;gt;
        &amp;lt;div&amp;gt;
            &amp;lt;input type=&quot;text&quot; onChange={(e)=&amp;gt;setText(e.currentTarget.value)} value={text}/&amp;gt;
            &amp;lt;button onClick={()=&amp;gt;add()}&amp;gt;할일 추가하기&amp;lt;/button&amp;gt;
        &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

export default App;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 ducks pattern을 사용하다보면,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드 작성도 용이하고 가독성도 좋아진는 등의 훨씬 더 많은 이점이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특별한 이유가 없다면 ducks pattern을 활용하자 !&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dinn.github.io/web/redux-ducks-pattern/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://dinn.github.io/web/redux-ducks-pattern/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ahnanne.tistory.com/34&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://ahnanne.tistory.com/34&lt;/a&gt;​&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://velog.io/@gyrbs22/React-Redux-flow-Architecture-%EA%B0%9C%EB%85%90&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://velog.io/@gyrbs22/React-Redux-flow-Architecture-%EA%B0%9C%EB%85%90&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://eatnug.github.io/frontend/react-redux/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://eatnug.github.io/frontend/react-redux/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://velog.io/@mokyoungg/Redux-Redux%EC%9D%98-%EA%B8%B0%EC%B4%88-%EA%B0%9C%EB%85%90&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://velog.io/@mokyoungg/Redux-Redux%EC%9D%98-%EA%B8%B0%EC%B4%88-%EA%B0%9C%EB%85%90&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>reactjs</category>
      <category>ducks</category>
      <category>ducks pattern</category>
      <category>JavaScript</category>
      <category>REACT</category>
      <category>Redux</category>
      <author>__songji__</author>
      <guid isPermaLink="true">https://songji.tistory.com/5</guid>
      <comments>https://songji.tistory.com/5#entry5comment</comments>
      <pubDate>Fri, 25 Mar 2022 00:06:00 +0900</pubDate>
    </item>
    <item>
      <title>Class Component  vs UseEffect  LifeCycle</title>
      <link>https://songji.tistory.com/4</link>
      <description>&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;react hook(react 16.8 이상)이 나오기 전에는 , 리액트의 라이프사이클을 활용하기 위해 Class Component를 사용해야 했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;나 또한, Class Component를 통해 리액트 개발을 해왔다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;Class&amp;nbsp;Component로 개발하다보면, 별거아닌 코드도 길고 거창해지기 마련이다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;또한, 라이프사이클을 잘못 건들면 어느순간 뒤엉켜 머리가 아파진다 ,,&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;특히, react hook을 활용하면 라이프사이클이 좀더 폐쇄적으로 관리되기 때문에, 이런 라이프사이클의 뒤엉킴에 있어서는 좀 더 안전한 듯하다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;React hook을 활용하여 Function Component 개발은 당연해졌고, React에서도 공식적으로 Function Component를 권장하고 있다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;워낙 리액트 문서가 한글로 지원이 잘 되어있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서, 기본 개념은 건너뛰고 &lt;b&gt;useEffect hook과 class 라이프사이클만 비교&lt;/b&gt;해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(react 공식문서 : &lt;a href=&quot;https://ko.reactjs.org/docs/hooks-effect.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://ko.reactjs.org/docs/hooks-effect.html)&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;b&gt;  useEffect hook = componentDidMount + componentDidUpdate + componentWillUnMount&amp;nbsp;&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;Class Component LifeCycle&lt;/b&gt;&lt;/blockquote&gt;
&lt;pre id=&quot;code_1646561518721&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React from 'react'

class Home extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            count: 0
        }
    }

    componentDidMount() {}

    componentDidUpdate() {}

    componentWillUnmount() {}

    render() {
        return (
            &amp;lt;div&amp;gt;
                &amp;lt;h1&amp;gt;HOME&amp;lt;/h1&amp;gt;
                &amp;lt;div&amp;gt;
                    &amp;lt;button onClick={() =&amp;gt; {
                        this.setState({count : this.state.count++})
                    }}&amp;gt;
                    click ME
                    &amp;lt;/button&amp;gt;
                &amp;lt;/div&amp;gt;
                &amp;lt;div&amp;gt;
                    &amp;lt;Link to=&quot;/about&quot;&amp;gt;about&amp;lt;/Link&amp;gt;
                &amp;lt;/div&amp;gt;
            &amp;lt;/div&amp;gt;
        )
    }
}

export default Home&lt;/code&gt;&lt;/pre&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;&amp;nbsp;페이지 진입 시점 (component mount) :&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;constructor&lt;/li&gt;
&lt;li&gt;render&lt;/li&gt;
&lt;li&gt;componentDidMount&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;state 업데이트 (component update) :&amp;nbsp;&lt;/span&gt;&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;render&lt;/li&gt;
&lt;li&gt;componentDidUpdate&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&amp;nbsp;페이지 변경 시점 (component unmount) :&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;componentWillUnmount&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;useEffect LifeCycle&lt;/b&gt;&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;useEffect( &lt;b&gt;effectFunction&lt;/b&gt; , [&lt;b&gt;Array&lt;/b&gt;] )&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666;&quot;&gt;effectFunction&lt;/span&gt;&lt;/b&gt;&amp;nbsp;: useEffect가 실행할 함수&lt;/span&gt;&lt;br /&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;&lt;b&gt;clean-up&lt;/b&gt; : &lt;span style=&quot;background-color: #fcfcfc; color: #666666;&quot;&gt;useEffect가 실행할 함수(&lt;span style=&quot;background-color: #fcfcfc; color: #666666;&quot;&gt;effectFunction)&lt;/span&gt;의 반환값&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666;&quot;&gt;&lt;b&gt;Array 옵션&lt;/b&gt; : &lt;span style=&quot;background-color: #fcfcfc; color: #666666;&quot;&gt;effectFunction을 실행시킬 조건&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1646562055741&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React, {useEffect, useState} from 'react'
import {Link} from &quot;react-router-dom&quot;;

export default function About (){
    let [count, setCount] = useState(0);
    let [test, setTest] = useState(0);

    // (1)
    
    useEffect(()=&amp;gt;{
    	// (3)        
        return ()=&amp;gt;{
		    // (4)
        }
    }, [ count ])
    
    // (2)
    
    return (
        &amp;lt;div&amp;gt;
            &amp;lt;h1&amp;gt;About&amp;lt;/h1&amp;gt;
            &amp;lt;div&amp;gt;
                &amp;lt;button onClick={() =&amp;gt; setCount(count++)}&amp;gt;click ME&amp;lt;/button&amp;gt;
            &amp;lt;/div&amp;gt;
            &amp;lt;div&amp;gt;
                &amp;lt;Link to=&quot;/&quot;&amp;gt;Home&amp;lt;/Link&amp;gt;
            &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
    )
}&lt;/code&gt;&lt;/pre&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;페이지 진입 시점 (component mount) :&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;function scope&amp;nbsp; : (1),(2)&lt;/li&gt;
&lt;li&gt;useEffect scope : (3)&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&amp;nbsp;state 업데이트 (component update) :&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;Array option 이 undefined인 경우 / Array option이 변경된 state [count] 인 경우&lt;/b&gt;&amp;nbsp; :&amp;nbsp;&lt;/span&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;function scope : (1), (2)&lt;/li&gt;
&lt;li&gt;useEffect scope :
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;clean-up : (4)&lt;/li&gt;
&lt;li&gt;(3)&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;Array option이 [ ] 인 경우 /&amp;nbsp; Array option이 변경되지 않을 state [test] 인 경우&lt;/b&gt; :&lt;/span&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;function scope : (1), (2)&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;페이지 변경 시점 (component unmount) :&lt;/span&gt;&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;useEffect clean-up : (4)&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;useEffect는 &quot;&lt;span style=&quot;background-color: #fcfcfc;&quot;&gt;componentDidMount + componentDidUpdate + componentWillUnMount&quot; 이므로,&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #000000;&quot;&gt;각 라이프사이클 단계에서 useEffect가 모두 실행되는 것을 볼 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #000000;&quot;&gt;하지만, &lt;b&gt;Array option에 따라 useEffect의 동작 방식이 다른다는 것&lt;/b&gt;을 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffc1c8; color: #000000;&quot;&gt;여기서 가장 중요한건, Array option을 적절하게 부여하지 않으면, 불가피한 렌더링이 발생할 수 있다는 것을 유념하자 !&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #fcfcfc;&quot;&gt;&lt;span style=&quot;background-color: #fcfcfc;&quot;&gt;불필요한 리렌더링을 방지하기 위해서는, 기준이 될만한 state가 없을 경우에는 &lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;[ ]&lt;/span&gt; 를 사용하자 !!&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고자료&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://killu.tistory.com/44&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://killu.tistory.com/44&lt;/a&gt;&lt;/p&gt;</description>
      <category>reactjs</category>
      <category>JavaScript</category>
      <category>React hook</category>
      <category>React lifecycle</category>
      <category>react.js</category>
      <author>__songji__</author>
      <guid isPermaLink="true">https://songji.tistory.com/4</guid>
      <comments>https://songji.tistory.com/4#entry4comment</comments>
      <pubDate>Sun, 6 Mar 2022 20:08:28 +0900</pubDate>
    </item>
    <item>
      <title>npm vs npx</title>
      <link>https://songji.tistory.com/3</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;200&quot; data-origin-height=&quot;200&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/60BRP/btrxUZu6gD9/vWbAWPZOGa2K4jZWPvKKfk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/60BRP/btrxUZu6gD9/vWbAWPZOGa2K4jZWPvKKfk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/60BRP/btrxUZu6gD9/vWbAWPZOGa2K4jZWPvKKfk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F60BRP%2FbtrxUZu6gD9%2FvWbAWPZOGa2K4jZWPvKKfk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;200&quot; height=&quot;200&quot; data-origin-width=&quot;200&quot; data-origin-height=&quot;200&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;npm&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;javascript 개발을 한다면, 쉽게 접하는게 npm(Node Package Manage)이다.&lt;br /&gt;Node Package Manage, 말 그대로 &lt;b&gt;Nodejs로 만들어진 패키지(즉, 모듈)를 관리해주는 프로그램&lt;/b&gt;이다.&lt;br /&gt;&lt;b&gt;nodejs의 의존성과 패키지 관리, 버전관리 등을 지원&lt;/b&gt;한다.&lt;br /&gt;몇 줄의 npm 명령어를 통해 쉽게 설치할 수 있고, 다양한 모듈을 활용하여 원하는 개발을 쉽게 할 수 있다.&lt;br /&gt;javascript 개발자라면 필수적으로 사용하는 프로그램이라고 할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;npm init&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;npm을 사용해보았다면, 종종 npx를 접하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 둘은 비슷한듯 다르기 때문에, 차이점을 확실히 알아두자! (&lt;b&gt;&lt;code&gt;npm !== npx&lt;/code&gt;&lt;/b&gt;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;npx&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;npx는 npm5.2 버전부터 추가된, &lt;b&gt;Node 패키지를 실행시키는 하나의 도구&lt;/b&gt;이다.&lt;br /&gt;새로운 프로그램 개념이 아니다!&lt;br /&gt;기존의 npm을 좀더 편리하게 사용하라고 제공되었다고 한다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;  npx의 실행과정

1. 실행되어야할 패키지가 로컬 경로에 있는지 먼저 확인
2. 존재한다면, 그대로 실행
3. 존재하지 않다면, npx가 최신 버전의 패키지 설치 후 실행&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가로, npx를 사용하면 패키지를 global 또는 local로 설치했는지 여부가 상관 없다.&lt;br /&gt;npx가 일시적으로 설치하여 알아서 실행시켜준다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;npm은 Manager 패키지 관리자&lt;/b&gt;&lt;br /&gt;&lt;code&gt;npm install ~&lt;/code&gt; 설치 후, &lt;code&gt;npm run ~&lt;/code&gt; 실행 필요&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;npx는 eXecute 패키지 실행&lt;/b&gt;&lt;br /&gt;&lt;code&gt;npx ~&lt;/code&gt; 설치 및 실행&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 링크는 npm,npx의 핵심이 잘 정리되어, 참고하기 좋은 블로그인 것 같다.&lt;br /&gt;&lt;a href=&quot;https://hanamon.kr/npm-npx-%EC%B0%A8%EC%9D%B4/&quot;&gt;https://hanamon.kr/npm-npx-%EC%B0%A8%EC%9D%B4/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고자료&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://velog.io/@kimkyeseung/%EB%B2%88%EC%97%AD-%EA%B7%B8%EB%9E%98-npx-npm%EB%A7%90%EA%B3%A0-%EC%B0%A8%EC%9D%B4%EC%A0%90-%EC%84%A4%EB%AA%85&quot;&gt;https://velog.io/@kimkyeseung/%EB%B2%88%EC%97%AD-%EA%B7%B8%EB%9E%98-npx-npm%EB%A7%90%EA%B3%A0-%EC%B0%A8%EC%9D%B4%EC%A0%90-%EC%84%A4%EB%AA%85&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://basemenks.tistory.com/232&quot;&gt;https://basemenks.tistory.com/232&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://seizemymoment.tistory.com/106&quot;&gt;https://seizemymoment.tistory.com/106&lt;/a&gt;&lt;/p&gt;</description>
      <category>nodejs</category>
      <category>frontend</category>
      <category>JavaScript</category>
      <category>nodejs</category>
      <category>npm</category>
      <category>npx</category>
      <author>__songji__</author>
      <guid isPermaLink="true">https://songji.tistory.com/3</guid>
      <comments>https://songji.tistory.com/3#entry3comment</comments>
      <pubDate>Sun, 6 Mar 2022 17:32:00 +0900</pubDate>
    </item>
  </channel>
</rss>