<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>All Day Tired</title>
    <link>https://yj-dev.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Mon, 15 Jun 2026 11:31:11 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>yu.dev</managingEditor>
    <image>
      <title>All Day Tired</title>
      <url>https://tistory1.daumcdn.net/tistory/5202648/attach/8714eec561464750afa5ceabef8b60c5</url>
      <link>https://yj-dev.tistory.com</link>
    </image>
    <item>
      <title>VScode에서 NodeJS 디버깅 하는 법</title>
      <link>https://yj-dev.tistory.com/45</link>
      <description>&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;1. launch.json 파일 만들기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;노드 세팅을 했다면&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1277&quot; data-origin-height=&quot;339&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ydNAD/dJMcajudtaR/JZdpjkkMH1izUwXfDNWAgk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ydNAD/dJMcajudtaR/JZdpjkkMH1izUwXfDNWAgk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ydNAD/dJMcajudtaR/JZdpjkkMH1izUwXfDNWAgk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FydNAD%2FdJMcajudtaR%2FJZdpjkkMH1izUwXfDNWAgk%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;1277&quot; height=&quot;339&quot; data-origin-width=&quot;1277&quot; data-origin-height=&quot;339&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;숫자 순서대로 Run and Debug 클릭 &amp;gt; create a launch.json file. 클릭 &amp;gt; Node.js 클릭&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;2. launch.json 파일 설정해주기&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1425&quot; data-origin-height=&quot;695&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tQ8kZ/dJMcahDck2z/4ZqxdLxKzpfewHKkYRNdP1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tQ8kZ/dJMcahDck2z/4ZqxdLxKzpfewHKkYRNdP1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tQ8kZ/dJMcahDck2z/4ZqxdLxKzpfewHKkYRNdP1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtQ8kZ%2FdJMcahDck2z%2F4ZqxdLxKzpfewHKkYRNdP1%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;1425&quot; height=&quot;695&quot; data-origin-width=&quot;1425&quot; data-origin-height=&quot;695&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Add Configuration 클릭 &amp;gt; Node.js: Attach to Process 클릭 &amp;gt; launch.json 저장&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;3. Attach by Process ID 확인&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;363&quot; data-origin-height=&quot;223&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cAHahF/dJMcadHyfi9/yYO1nfkDFddn7XC8xM2qL0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cAHahF/dJMcadHyfi9/yYO1nfkDFddn7XC8xM2qL0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cAHahF/dJMcadHyfi9/yYO1nfkDFddn7XC8xM2qL0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcAHahF%2FdJMcadHyfi9%2FyYO1nfkDFddn7XC8xM2qL0%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;363&quot; height=&quot;223&quot; data-origin-width=&quot;363&quot; data-origin-height=&quot;223&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;lauch.json 파일을 저장했으면 Attach by Process ID가 추가된 것을 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Attach by Process ID를 선택한 상태에서 node 또는 nodemon으로 서버 실행&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;4. 서버를 실행 했으면 F5를 눌러서 디버깅을 시작한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;727&quot; data-origin-height=&quot;108&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/INc0H/dJMcac2WASr/I14t9ByX4dhkl1afk3Aa7k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/INc0H/dJMcac2WASr/I14t9ByX4dhkl1afk3Aa7k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/INc0H/dJMcac2WASr/I14t9ByX4dhkl1afk3Aa7k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FINc0H%2FdJMcac2WASr%2FI14t9ByX4dhkl1afk3Aa7k%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;727&quot; height=&quot;108&quot; data-origin-width=&quot;727&quot; data-origin-height=&quot;108&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;F5를 누르면 디버깅 할 process를 선택할 수 있고 실행할 process를 클릭하면 디버깅을 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(저기에 있는 node app.js를 보통 클릭함)&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;서버가 꺼졌다 켜지면 디버깅 모드도 꺼지기때문에 다시 F5를 눌러서 디버깅을 시작해줘야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(nodemon 사용시 저장할때마다 서버가 재시작되므로 저장하고나서 F5를 눌러서 디버깅을 시작해주자)&lt;/p&gt;</description>
      <category>Back/NodeJS</category>
      <category>nodejs</category>
      <category>VSCode</category>
      <category>노드제이에스</category>
      <category>디버깅</category>
      <author>yu.dev</author>
      <guid isPermaLink="true">https://yj-dev.tistory.com/45</guid>
      <comments>https://yj-dev.tistory.com/45#entry45comment</comments>
      <pubDate>Sun, 25 Jan 2026 19:32:25 +0900</pubDate>
    </item>
    <item>
      <title>동기와 비동기</title>
      <link>https://yj-dev.tistory.com/44</link>
      <description>&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;s&gt;난 왜... 동기와 비동기가 참 이해가 안될까...&lt;/s&gt;&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;&lt;b&gt;동기&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드를 위에서부터 아래로 &lt;b&gt;순차적으로 실행&lt;/b&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;그러면 손님 여러 명이 와도 주인장 1명만 일하니까&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;...&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&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1772&quot; data-origin-height=&quot;450&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b6OqmA/dJMcafE6Tcw/Kenmhkmn9ivG27o91HRbh1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b6OqmA/dJMcafE6Tcw/Kenmhkmn9ivG27o91HRbh1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b6OqmA/dJMcafE6Tcw/Kenmhkmn9ivG27o91HRbh1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb6OqmA%2FdJMcafE6Tcw%2FKenmhkmn9ivG27o91HRbh1%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;1772&quot; height=&quot;450&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1772&quot; data-origin-height=&quot;450&quot;/&gt;&lt;/span&gt;&lt;/figure&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;비동기&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드가 &lt;b&gt;동시에 일을 처리&lt;/b&gt;할 수 있음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;식당이 있는데 주인장 한 명이랑 직원 2명이 있음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 손님 여러 명이 오면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫번째 손님이 직원1한테 주문 받는 동시에 두번째 손님이 직원2한테 주문 받고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주인장이 첫번째 손님 요리하고 직원1이 첫번째 손님 음식 나가고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주인장이 두번째 손님 요리하고 직원2가 두번째 손님 음식 나가고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 직원1,2가 동시에 일하는 구간이 생기게 됨. 이것이 비동기&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그림으로 표현하면 아래와 같다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;939&quot; data-origin-height=&quot;426&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/676Ev/dJMcadHfzG3/kv8f4B4dnWq15TwTmJ3Lxk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/676Ev/dJMcadHfzG3/kv8f4B4dnWq15TwTmJ3Lxk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/676Ev/dJMcadHfzG3/kv8f4B4dnWq15TwTmJ3Lxk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F676Ev%2FdJMcadHfzG3%2Fkv8f4B4dnWq15TwTmJ3Lxk%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;465&quot; height=&quot;211&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;939&quot; data-origin-height=&quot;426&quot;/&gt;&lt;/span&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;/p&gt;
&lt;pre id=&quot;code_1765197198396&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;console.log(1);

function a(){
	API 호출 ajax
}

function callback(){
	a함수 callback 함수
    console.log(3);
}

console.log(2);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 이 코드가 무조건 &lt;b&gt;동기적으로 처리&lt;/b&gt;된다고 생각하면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1 이 출력되고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;API 호출을 하고 서버에서 응답을 받아서 callback 함수가 실행(시간이 꽤 걸릴 것임)되어서 3이 출력&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2 가 출력되어서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 1 -&amp;gt; 3 -&amp;gt; 2 순서로 출력된다.&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;비동기 처리&lt;/b&gt;가 된다면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1 이 출력되고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;API 호출을 하고 서버에서 응답을 받아서 callback 함수가 실행하는데 시간이 오래 걸리니까 2가 먼저 출력&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 callback함수가 실행이 완료되어서 3 이 출력되어서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1 -&amp;gt; 2 -&amp;gt; 3 순서로 출력된다.&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;u&gt;동기와 비동기의 큰 차이는 동시 처리&lt;/u&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 프론트에서 API호출할 때 서버로부터 응답을 받아오는 시간까지 마냥 화면이 멈춰있지 않고 다른일을 할 수 있다.(가령... 뭐 다른 버튼들을 클릭을 할 수 있다던가... 그런 일...?)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이래서 API호출을 비동기로 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;까먹지 말자...&lt;/p&gt;</description>
      <category>기타</category>
      <category>동기</category>
      <category>비동기</category>
      <author>yu.dev</author>
      <guid isPermaLink="true">https://yj-dev.tistory.com/44</guid>
      <comments>https://yj-dev.tistory.com/44#entry44comment</comments>
      <pubDate>Mon, 8 Dec 2025 21:42:52 +0900</pubDate>
    </item>
    <item>
      <title>리액트 쿼리(react query)</title>
      <link>https://yj-dev.tistory.com/43</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;리액트 상태는 크게 3가지로 구분된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 지역: useState로 관리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 전역: store로 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;상태관리&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 서버: API통신할때 필요한 상태 &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;리액트쿼리&lt;/b&gt;는 특히 &lt;b&gt;서버상태관리&lt;/b&gt;를 하는데 유용한 라이브러리이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 리액트쿼리를 사용하기위해 &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;1.&amp;nbsp;react&amp;nbsp;query&amp;nbsp;설치(버전&amp;nbsp;5로&amp;nbsp;설치함)&lt;/p&gt;
&lt;pre id=&quot;code_1762085884005&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm i @tanstack/react-query&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;2.&amp;nbsp;index.js&amp;nbsp;또는&amp;nbsp;main.jsx에서&amp;nbsp;import&amp;nbsp;해주고&amp;nbsp;기본&amp;nbsp;세팅하기&lt;/p&gt;
&lt;pre id=&quot;code_1762085907439&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { createRoot } from 'react-dom/client'
import './index.css'
import App from './App.jsx'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'//import를 해주고

const queryClient = new QueryClient();//QueryClient 인스턴스를 생성해주고
createRoot(document.getElementById('root')).render(
  &amp;lt;QueryClientProvider client={queryClient}&amp;gt;//&amp;lt;App&amp;gt;을 QueryClientProvider로 감싸준다
    &amp;lt;App /&amp;gt;
  &amp;lt;/QueryClientProvider&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;3. Devtool을 설치. 이걸 설치하는 이유는 리액트쿼리를 사용하면서 캐시 상태를 보기위한 목적이다.&lt;/p&gt;
&lt;pre id=&quot;code_1762085956389&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm i @tanstack/react-query-devtools&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;4.&amp;nbsp;index.js&amp;nbsp;또는&amp;nbsp;main.jsx에&amp;nbsp;Devtool&amp;nbsp;import&amp;nbsp;해주기&lt;/p&gt;
&lt;pre id=&quot;code_1762085982865&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { ReactQueryDevtools } from '@tanstack/react-query-devtools'&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;5.&amp;nbsp;index.js&amp;nbsp;또는&amp;nbsp;main.jsx에&amp;nbsp;Devtool&amp;nbsp;세팅하기&lt;/p&gt;
&lt;pre id=&quot;code_1762085998069&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { createRoot } from 'react-dom/client'
import './index.css'
import App from './App.jsx'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'

const queryClient = new QueryClient();
createRoot(document.getElementById('root')).render(
  &amp;lt;QueryClientProvider client={queryClient}&amp;gt;
    &amp;lt;App /&amp;gt;
    &amp;lt;ReactQueryDevtools initialIsOpen={false} /&amp;gt;//QueryClientProvider 안에 넣어주기
  &amp;lt;/QueryClientProvider&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;여기까지가 아주 기본적으로 리액트쿼리를 사용하기위한 기본 세팅이다.&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;리액트 쿼리는 서버 상태를 관리해주는 라이브러리이니까 API를 호출을 해줘야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;fetch로도 할 수 있지만 &lt;b&gt;axios&lt;/b&gt;라는 좋은게 있으니 이걸로 &lt;b&gt;API를 호출&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;1.&amp;nbsp;axios&amp;nbsp;설치&lt;/p&gt;
&lt;pre id=&quot;code_1762086050524&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm i axios&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;2. 리액트&amp;nbsp;쿼리에서&amp;nbsp;제공하는&amp;nbsp;대표적인&amp;nbsp;훅인&amp;nbsp;useQuery를&amp;nbsp;사용,&amp;nbsp;디폴트로&amp;nbsp;useQuery&amp;nbsp;훅은&amp;nbsp;컴포넌트&amp;nbsp;들어오자마자&amp;nbsp;실행되는데&amp;nbsp;나는&amp;nbsp;어떤&amp;nbsp;이벤트&amp;nbsp;뒤에&amp;nbsp;실행하고&amp;nbsp;싶다!&amp;nbsp;하고싶을땐&amp;nbsp;따로&amp;nbsp;설정이&amp;nbsp;필요&lt;/p&gt;
&lt;pre id=&quot;code_1762086078093&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { useQuery } from '@tanstack/react-query'//import 해주고

.
.
.

const {data, isLoading, isError, error} = useQuery({//data: API호출해서 받아온 data, isLoading: 로딩중인지 아닌지 상태값(로딩중이면 true, 아니면 false), isError: 에러가 난 상태값, error: 에러가 났다면 에러 정보가 들어가있는 에러 객체(에러 메세지 등등)
	queryKey: ['todos'], 
	queryFn: getTodos,
	retry: 2
});
//useQuery는 객체 하나를 매개변수로 받는다.(버전 5여서 그런데 다른 버전에서는 매개변수가 3개임)
//첫번째 key는 queryKey로 API 호출하는 이름으로 생각하면 된다. 유니크한 이름이여야 함.
//두번째 key는 queryFn으로 함수이다. API를 호출하는 로직의 함수가 들어감. 이렇게 2개까지가 가장 기본적으로 꼭 들어가야하는 것들
//세번째 key는 retry로 API 호출에 실패했을때 다시 시도하는 횟수이다. 디폴트로 설정해주지 않으면 3번임

const getTodos = () =&amp;gt; {
	...//API 호출하는 로직
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통 &lt;b&gt;useQuery는 따로 js파일을 만들어서 커스텀훅으로 관리&lt;/b&gt;하는 경우가 많다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에처럼 쓰면 UI부분과 로직부분이 합쳐져 있어 관리하기가 까다롭다.&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;그럼 이렇게 API 호출하려고 리액트쿼리를 쓰냐?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아니! &lt;b&gt;리액트 쿼리를 쓰는 진짜 이유는 캐시관리&lt;/b&gt;를 해주기 때문 &lt;br /&gt;캐시는 임시 저장 공간으로 API를 호출해서 가져온 데이터를 캐시라는 임시저장공간에 잠깐만 가지고 있어 하면서 저장&lt;br /&gt;리액트&amp;nbsp;쿼리는&amp;nbsp;모든&amp;nbsp;데이터를&amp;nbsp;이&amp;nbsp;캐시에&amp;nbsp;저장시켜줌 &lt;br /&gt;그래서&amp;nbsp;이런&amp;nbsp;경험이&amp;nbsp;있을&amp;nbsp;것이다. &lt;br /&gt;어디&amp;nbsp;사이트를&amp;nbsp;갔는데&amp;nbsp;처음&amp;nbsp;들어갔을&amp;nbsp;때&amp;nbsp;데이터&amp;nbsp;로딩이&amp;nbsp;되고&amp;nbsp;두번째로&amp;nbsp;들어갔을때(데이터가&amp;nbsp;동일하다는&amp;nbsp;가정)&amp;nbsp;로딩&amp;nbsp;없이&amp;nbsp;바로&amp;nbsp;데이터가&amp;nbsp;나오는&amp;nbsp;경우! &lt;br /&gt;이&amp;nbsp;경우가&amp;nbsp;바로&amp;nbsp;캐시에서&amp;nbsp;데이터를&amp;nbsp;꺼내온&amp;nbsp;경우이다. &lt;br /&gt;그렇다면&amp;nbsp;캐시에&amp;nbsp;데이터가&amp;nbsp;있으면&amp;nbsp;API&amp;nbsp;호출을&amp;nbsp;안하냐?&amp;nbsp;그건&amp;nbsp;아니다. &lt;br /&gt;일단&amp;nbsp;우선적으로&amp;nbsp;캐시에&amp;nbsp;있는&amp;nbsp;데이터를&amp;nbsp;뿌려주고&amp;nbsp;뒤에서는&amp;nbsp;API를&amp;nbsp;호출하고&amp;nbsp;다시&amp;nbsp;데이터를&amp;nbsp;가져와서&amp;nbsp;가져온&amp;nbsp;데이터를&amp;nbsp;다시&amp;nbsp;캐시에&amp;nbsp;넣어주고&amp;nbsp;이런&amp;nbsp;작업을&amp;nbsp;하고&amp;nbsp;있다. &lt;br /&gt;&lt;br /&gt;useQuery를&amp;nbsp;사용하면&amp;nbsp;이렇게&amp;nbsp;알아서&amp;nbsp;데이터를&amp;nbsp;캐시관리를&amp;nbsp;해준다. &lt;br /&gt;캐시&amp;nbsp;저장&amp;nbsp;시간도&amp;nbsp;useQuery로&amp;nbsp;설정해줄수있는데 &lt;br /&gt;gcTime으로&amp;nbsp;설정해줄&amp;nbsp;수&amp;nbsp;있다.(버전&amp;nbsp;5에서&amp;nbsp;gcTime,&amp;nbsp;그&amp;nbsp;이하버전은 cacheTime) &lt;br /&gt;캐시는 주기적으로 비워주는것도 중요. 메모리차지를 하기때문이다.&lt;/p&gt;</description>
      <category>Front/React</category>
      <category>API</category>
      <category>axios</category>
      <category>react</category>
      <category>ReactQuery</category>
      <category>리액트</category>
      <category>리액트쿼리</category>
      <category>캐시</category>
      <author>yu.dev</author>
      <guid isPermaLink="true">https://yj-dev.tistory.com/43</guid>
      <comments>https://yj-dev.tistory.com/43#entry43comment</comments>
      <pubDate>Sun, 2 Nov 2025 21:25:29 +0900</pubDate>
    </item>
    <item>
      <title>Zustand로 리액트 상태관리</title>
      <link>https://yj-dev.tistory.com/42</link>
      <description>&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;Zutand는 상태관리를 위해 만들어진 라이브러리다.&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;a href=&quot;https://yj-dev.tistory.com/41&quot;&gt;리액트 redux 상태관리&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1761747002623&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;리액트 redux 상태관리&quot; data-og-description=&quot;코딩알려주는 누나 강의를 보고 쓰는 글입니다. 리액트를 사용하면서 문제점이 있다.이렇게 부모에서 자식으로만 state가 전달된다는 문제!이렇게 되면 넘겨줘야하는 props가 너무 많아져서 관리&quot; data-og-host=&quot;yj-dev.tistory.com&quot; data-og-source-url=&quot;https://yj-dev.tistory.com/41&quot; data-og-url=&quot;https://yj-dev.tistory.com/41&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dCOwbe/hyZMNlkIKs/MU4dc0rwgDkbxvjugwZKY1/img.png?width=800&amp;amp;height=1151&amp;amp;face=0_0_800_1151,https://scrap.kakaocdn.net/dn/350kh/hyZMQWFuNL/cELi039a1NCLB50fi0KN7K/img.png?width=800&amp;amp;height=1151&amp;amp;face=0_0_800_1151,https://scrap.kakaocdn.net/dn/p1wRn/hyZLitICmj/333xi4jjNRjcLQ0AT0M5Z0/img.png?width=1738&amp;amp;height=873&amp;amp;face=0_0_1738_873&quot;&gt;&lt;a href=&quot;https://yj-dev.tistory.com/41&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://yj-dev.tistory.com/41&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dCOwbe/hyZMNlkIKs/MU4dc0rwgDkbxvjugwZKY1/img.png?width=800&amp;amp;height=1151&amp;amp;face=0_0_800_1151,https://scrap.kakaocdn.net/dn/350kh/hyZMQWFuNL/cELi039a1NCLB50fi0KN7K/img.png?width=800&amp;amp;height=1151&amp;amp;face=0_0_800_1151,https://scrap.kakaocdn.net/dn/p1wRn/hyZLitICmj/333xi4jjNRjcLQ0AT0M5Z0/img.png?width=1738&amp;amp;height=873&amp;amp;face=0_0_1738_873');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;리액트 redux 상태관리&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;코딩알려주는 누나 강의를 보고 쓰는 글입니다. 리액트를 사용하면서 문제점이 있다.이렇게 부모에서 자식으로만 state가 전달된다는 문제!이렇게 되면 넘겨줘야하는 props가 너무 많아져서 관리&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;yj-dev.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 확실히 Zustand 쓰는게 편하긴 한듯...&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;Zustand를 사용하는 방법은 아래와 같다.&lt;br /&gt;&lt;br /&gt;1.&amp;nbsp;Zustand를&amp;nbsp;설치한다.&lt;/p&gt;
&lt;pre id=&quot;code_1761747043517&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install zustand&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;2.&amp;nbsp;store를&amp;nbsp;만들자.&amp;nbsp;src&amp;nbsp;&amp;gt;&amp;nbsp;stores&amp;nbsp;&amp;gt;&amp;nbsp;personStore.js&amp;nbsp;파일을&amp;nbsp;만들어준다. &lt;br /&gt;&lt;br /&gt;3.&amp;nbsp;Store.js에&amp;nbsp;create를&amp;nbsp;import해준다.&amp;nbsp;state를&amp;nbsp;저장해주는&amp;nbsp;store를&amp;nbsp;만들어주는&amp;nbsp;것이&amp;nbsp;create&lt;/p&gt;
&lt;pre id=&quot;code_1761747057393&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import {create} from &quot;zustand&quot;

const personStore = create (() =&amp;gt; ({
person: [] //사용하는 state를 써주고 초기화까지 시켜준다.
}));

export default personStore;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;4.&amp;nbsp;store에&amp;nbsp;있는&amp;nbsp;state를&amp;nbsp;사용해보자&lt;/p&gt;
&lt;pre id=&quot;code_1761747073513&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import personStore from './stores/personStore'

.
.
.

const {person} = personStore();//personStore에 있는 state인 person을 가져옴&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;5.&amp;nbsp;함수를&amp;nbsp;store에&amp;nbsp;만들어보자.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1761747100188&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import {create} from &quot;zustand&quot;

const personStore = create ((set) =&amp;gt; ({//set은 state를 set해주기위해 zustand가 제공해준 함수
  person: [],
  addPerson: (name, age) =&amp;gt; set((state) =&amp;gt; ({//매개변수가 있으면 (name, age) 같이 매개변수를 넣어주면 된다.
    person: [...state.person, {name: name, age: age}]
  }))
}));

export default personStore;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;6.&amp;nbsp;store에&amp;nbsp;있는&amp;nbsp;함수를&amp;nbsp;사용해보자&lt;/p&gt;
&lt;pre id=&quot;code_1761747238171&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import personStore from './stores/personStore'

.
.
.

const {addPerson} = personStore();
addPerson('아무개', 20);&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Front/React</category>
      <category>react</category>
      <category>zustand</category>
      <category>리액트</category>
      <category>상태관리</category>
      <author>yu.dev</author>
      <guid isPermaLink="true">https://yj-dev.tistory.com/42</guid>
      <comments>https://yj-dev.tistory.com/42#entry42comment</comments>
      <pubDate>Wed, 29 Oct 2025 23:14:22 +0900</pubDate>
    </item>
    <item>
      <title>리액트 redux 상태관리</title>
      <link>https://yj-dev.tistory.com/41</link>
      <description>&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;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;리액트 문제.png&quot; data-origin-width=&quot;1503&quot; data-origin-height=&quot;719&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bHOSpu/dJMcai2FBVi/X5THTuldqkLs0VZMcwv9g1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bHOSpu/dJMcai2FBVi/X5THTuldqkLs0VZMcwv9g1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bHOSpu/dJMcai2FBVi/X5THTuldqkLs0VZMcwv9g1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbHOSpu%2FdJMcai2FBVi%2FX5THTuldqkLs0VZMcwv9g1%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;1503&quot; height=&quot;719&quot; data-filename=&quot;리액트 문제.png&quot; data-origin-width=&quot;1503&quot; data-origin-height=&quot;719&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 &lt;b&gt;부모에서 자식으로만 state가 전달된다는 문제&lt;/b&gt;!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 되면 넘겨줘야하는 props가 너무 많아져서 관리하기도 힘들어지는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것을 &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;&lt;b&gt;store라는 공간에 state들을 넣어주어서 어느 컴포넌트든 사용할 수 있게 해주는 것&lt;/b&gt;!&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;상태관리 필요성.png&quot; data-origin-width=&quot;1656&quot; data-origin-height=&quot;727&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dTAMM5/dJMcadfZmXO/KFZtqzahXmd6kra3WpdNZ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dTAMM5/dJMcadfZmXO/KFZtqzahXmd6kra3WpdNZ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dTAMM5/dJMcadfZmXO/KFZtqzahXmd6kra3WpdNZ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdTAMM5%2FdJMcadfZmXO%2FKFZtqzahXmd6kra3WpdNZ0%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;1656&quot; height=&quot;727&quot; data-filename=&quot;상태관리 필요성.png&quot; data-origin-width=&quot;1656&quot; data-origin-height=&quot;727&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;figure data-ke-type=&quot;image&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; data-ke-style=&quot;alignCenter&quot;&gt;&lt;span class=&quot;bar_progress&quot;&gt;&lt;/span&gt;
&lt;figcaption style=&quot;display: none;&quot;&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 상태관리를 도와주는 것이 바로 redux이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;redux는 라이브러리로 구조는 아래와 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;리억스.png&quot; data-origin-width=&quot;1738&quot; data-origin-height=&quot;873&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/STdbx/dJMcad776u7/1PDfqRhkFa3L2WxopjKihK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/STdbx/dJMcad776u7/1PDfqRhkFa3L2WxopjKihK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/STdbx/dJMcad776u7/1PDfqRhkFa3L2WxopjKihK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSTdbx%2FdJMcad776u7%2F1PDfqRhkFa3L2WxopjKihK%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;1738&quot; height=&quot;873&quot; data-filename=&quot;리억스.png&quot; data-origin-width=&quot;1738&quot; data-origin-height=&quot;873&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Reducer&lt;/b&gt;는 단순히 &lt;b&gt;함수&lt;/b&gt;로 그 아래에는 &lt;b&gt;if문이나 switch문으로 action의 type들이 나열되어서 각각 하는 기능을 구현&lt;/b&gt;한 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Action&lt;/b&gt;은 &lt;b&gt;type과 payload로 이루어진 객체&lt;/b&gt;로 type은 액션의 이름, payload는 매개변수라고 생각하면 된다.&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;br /&gt;&lt;br /&gt;1.&amp;nbsp;터미널&amp;nbsp;열어서&amp;nbsp;redux와&amp;nbsp;react-redux&amp;nbsp;설치 &lt;/p&gt;
&lt;pre id=&quot;code_1761746430588&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm i redux react-redux&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;2.&amp;nbsp;&lt;b&gt;index.js&lt;/b&gt;&amp;nbsp;또는&amp;nbsp;&lt;b&gt;main.jsx&lt;/b&gt;에&amp;nbsp;&amp;lt;App&amp;gt;을&amp;nbsp;&amp;lt;Provider&amp;gt;로&amp;nbsp;감싸주기.&amp;nbsp;왜냐하면&amp;nbsp;store를&amp;nbsp;제공해주기&amp;nbsp;위해서,&amp;nbsp;Provider는&amp;nbsp;항상&amp;nbsp;기본적으로&amp;nbsp;들어가는&amp;nbsp;props가&amp;nbsp;store다! &lt;/p&gt;
&lt;pre id=&quot;code_1761746449464&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { createRoot } from 'react-dom/client'
import './index.css'
import App from './App.jsx'
import { Provider } from 'react-redux'

createRoot(document.getElementById('root')).render(
  &amp;lt;Provider store={store}&amp;gt;
    &amp;lt;App /&amp;gt;
  &amp;lt;/Provider&amp;gt;,
)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;3. store파일 만들어주기. src &amp;gt; redux &amp;gt; store.js 이렇게 만들어줌 &lt;br /&gt;&lt;br /&gt;4.&amp;nbsp;&amp;nbsp;store를&amp;nbsp;만드는&amp;nbsp;함수인&amp;nbsp;createStore를&amp;nbsp;import해주고&amp;nbsp;store를&amp;nbsp;만들어준다. &lt;/p&gt;
&lt;pre id=&quot;code_1761746474500&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { createStore } from &quot;redux&quot;

let store = createStore(reducer);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;5.&amp;nbsp;행동지침이&amp;nbsp;있을&amp;nbsp;reducer파일을&amp;nbsp;만들어준다.&amp;nbsp;src&amp;nbsp;&amp;gt;&amp;nbsp;redux&amp;nbsp;&amp;gt;&amp;nbsp;reducer&amp;nbsp;&amp;gt;&amp;nbsp;reducer.js&amp;nbsp;이렇게&amp;nbsp;만들어줌 &lt;br /&gt;&lt;br /&gt;6.&amp;nbsp;reducer는&amp;nbsp;state와&amp;nbsp;action을&amp;nbsp;가진&amp;nbsp;함수이다. &lt;/p&gt;
&lt;pre id=&quot;code_1761746493700&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let initialState = {};//state 초기값을 넣어줄 애들

function reducer(state = initialState, action){

}

export default reducer;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;7.&amp;nbsp;ruducer을&amp;nbsp;export했으니&amp;nbsp;store.js에서&amp;nbsp;import&amp;nbsp;해주고&amp;nbsp;export&amp;nbsp;해준다. &lt;/p&gt;
&lt;pre id=&quot;code_1761746525967&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { createStore } from &quot;redux&quot;
import reducer from &quot;./reducer/reducer&quot;;

let store = createStore(reducer);

export default store;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;8.&amp;nbsp;store를&amp;nbsp;export했으니&amp;nbsp;다시&amp;nbsp;index.js&amp;nbsp;또는&amp;nbsp;main.jsx에서&amp;nbsp;store를&amp;nbsp;import&amp;nbsp;해주자 &lt;/p&gt;
&lt;pre id=&quot;code_1761746557334&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import store from './redux/store.js'&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;여기까지가&amp;nbsp;redux를&amp;nbsp;사용하기&amp;nbsp;위한&amp;nbsp;기본&amp;nbsp;세팅이다. &lt;br /&gt;그렇다면&amp;nbsp;store의&amp;nbsp;값을&amp;nbsp;사용하고&amp;nbsp;변경하고&amp;nbsp;기타&amp;nbsp;등등&amp;nbsp;일을&amp;nbsp;하기위해서는&amp;nbsp;어떻게&amp;nbsp;할까? &lt;br /&gt;&lt;br /&gt;먼저 store의 값을 저장하기 위한 방법, store에 만든 함수를 사용하는 방법&lt;br /&gt;1.&amp;nbsp;useDispatcher를&amp;nbsp;import&amp;nbsp;하고&amp;nbsp;사용해주자 &lt;/p&gt;
&lt;pre id=&quot;code_1761746585526&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { useDispatch } from 'react-redux';

.
.
.

const dispatch = useDispatch();
dispatch({type: 'ADD_PERSEON', payload: {name:'아무개', age:20}}); //dispatch의 매개변수는 action이고 action은 type(액션이름)과 payload(액션에 넘겨주는 값)으로 이루어진 객체이다&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;2.&amp;nbsp;이렇게&amp;nbsp;던진&amp;nbsp;action은&amp;nbsp;reducer로&amp;nbsp;가서&amp;nbsp;추가해주자 &lt;/p&gt;
&lt;pre id=&quot;code_1761746605456&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let initialState = {
person: []
};//state 초기값을 넣어줄 애들

function reducer(state = initialState, action){
    switch(action.type){
        case 'ADD_PERSEON':
            return {...state, person:[...state.person, {name:action.payload.name, age:action.payload.age}]};
        default:
            return {...state};
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;이렇게&amp;nbsp;store의&amp;nbsp;state&amp;nbsp;값을&amp;nbsp;변경하거나&amp;nbsp;저장하거나&amp;nbsp;하는&amp;nbsp;일을&amp;nbsp;했다면&amp;nbsp;이&amp;nbsp;값을&amp;nbsp;사용하는건&amp;nbsp;어떻게&amp;nbsp;할까? &lt;br /&gt;1.&amp;nbsp;useSelector를&amp;nbsp;import&amp;nbsp;해주고&amp;nbsp;사용하기 &lt;/p&gt;
&lt;pre id=&quot;code_1761746621165&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { useSelector } from 'react-redux'

.
.
.

const people = useSelector(state =&amp;gt; state.person);&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Front/React</category>
      <category>react</category>
      <category>Redux</category>
      <category>State</category>
      <category>리덕스</category>
      <category>리액트</category>
      <category>상태관리</category>
      <author>yu.dev</author>
      <guid isPermaLink="true">https://yj-dev.tistory.com/41</guid>
      <comments>https://yj-dev.tistory.com/41#entry41comment</comments>
      <pubDate>Wed, 29 Oct 2025 23:08:55 +0900</pubDate>
    </item>
    <item>
      <title>리액트 state, useState</title>
      <link>https://yj-dev.tistory.com/40</link>
      <description>&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;b&gt;state가 변하면 UI를 바꾼다&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;state 형태는 아래와 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1761053341616&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const [변수, setState] = useState(초기값);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;state값을 변경하기 위해서는 setState 함수를 통해서 바꿔야한다&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;state가&amp;nbsp;바뀌면&amp;nbsp;UI가&amp;nbsp;랜더링&amp;nbsp;됨 &lt;br /&gt;그래서&amp;nbsp;&lt;b&gt;setState&amp;nbsp;함수를&amp;nbsp;실행한다고&amp;nbsp;바로&amp;nbsp;실행되지&amp;nbsp;않고&amp;nbsp;비동기적으로&amp;nbsp;실행&lt;/b&gt;이&amp;nbsp;됨 &lt;br /&gt;setState 함수를 감싼 함수가 끝나야 setState가 실행된다&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_1761053410198&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { useState } from 'react'
import './App.css'

function App() {
  const [count, setCount] = useState(0);
  
  const increase = () =&amp;gt; {
  setCount(count + 1);//이 state는 increase 함수가 끝나야 count라는 state가 1 증가하므로 increase 함수안에서 count state를 사용하게 되면 이전 값이 들어가게 되는 문제 발생! 주의하자!
  };

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;div&amp;gt;{count}&amp;lt;/div&amp;gt;
      &amp;lt;button onClick='{increase}'&amp;gt;&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  )
}

export default App&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Front/React</category>
      <category>State</category>
      <category>useState</category>
      <category>리액트</category>
      <author>yu.dev</author>
      <guid isPermaLink="true">https://yj-dev.tistory.com/40</guid>
      <comments>https://yj-dev.tistory.com/40#entry40comment</comments>
      <pubDate>Tue, 21 Oct 2025 22:31:23 +0900</pubDate>
    </item>
    <item>
      <title>리액트 pathVariable/쿼리파라미터 값 받기, redirect</title>
      <link>https://yj-dev.tistory.com/39</link>
      <description>&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;url을 넘길 때 많은 정보를 넘기곤 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;http://www.yj-dev.com/history&quot;&gt;http://www.yj-dev.com/history&lt;/a&gt; 이런식으로 pathVariable로 history라는 정보를 넘기던가&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;http://www.yj-dev.com?id=1&amp;amp;num=23&quot;&gt;http://www.yj-dev.com?id=1&amp;amp;num=23&lt;/a&gt; 이런식으로 쿼리파라미터로 id와 num이라는 정보를 넘기던가&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;b&gt;pathVariable&lt;/b&gt;을 하려면 history같은 값은 변해야하는 값인데 &lt;u&gt;Router에 어떻게 지정을 해줘야할까?&lt;/u&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1761051287926&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;mport { useState } from 'react'
import './App.css'
import PageA from './page/PageA'
import { Routes, Route, Navigate } from 'react-router-dom'//import 필요!

function App() {

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;Routes&amp;gt;
        &amp;lt;Route path='/pagea/:key' element={&amp;lt;PageA&amp;gt;&amp;lt;/PageA&amp;gt;}&amp;gt;&amp;lt;/Route&amp;gt;
      &amp;lt;/Routes&amp;gt;
    &amp;lt;/div&amp;gt;
  )
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 &lt;b&gt;콜론으로 지정&lt;/b&gt;하면 pathVariable이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러개의 콜론을 지정하면 지정한 갯 수 만큼 pathVariable이 추가&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;pathVariable을 받아오려면 어떻게 해야할까?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때 필요한 것이 &lt;b&gt;usePrams 훅&lt;/b&gt;이다.&lt;/p&gt;
&lt;pre id=&quot;code_1761051482789&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 { useParams } from 'react-router-dom' //import 필요!

const ProductDetailpage = () =&amp;gt; {
    const params = useParams();//이렇게 useParams 훅을 이용하면 콜론으로 넘긴 값이 객체로 전달! 만약 여러개의 파라미터를 담아서 보냈다면? 보낸 파라미터들이 객체(key-value 형태)로 다 가지고 옴!

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;h1&amp;gt;useParams 이용해서 pathVariable 값 받기&amp;lt;/h1&amp;gt;
    &amp;lt;/div&amp;gt;
  )
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 :id/:num/:cnt 이런식으로 3개의 pathVariable을 보냈다면 params에는&lt;/p&gt;
&lt;pre id=&quot;code_1761051598742&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
    id: yj,
    num: 3,
    cnt: 10
}&lt;/code&gt;&lt;/pre&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;쿼리파라미터로 보낸 값은 어떻게 받아야할까?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;useSearchParams 훅&lt;/b&gt;을 사용하면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1761051718826&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 { useSearchParams } from 'react-router-dom'//import 필요!

const PageA = () =&amp;gt; {
    let [query, setQuery] = useSearchParams();//useState와 비슷한 형태로 선언을 해준다
    console.log(query.get('q'));//그리고 넘어오는 쿼리파라미터 중 필요한 값의 key값을 get 해주면 그 값을 사용할 수 있다!
    
  return (
    &amp;lt;div&amp;gt;
      &amp;lt;h1&amp;gt;useSearchParams 훅으로 쿼리파라미터 값 받기&amp;lt;/h1&amp;gt;
    &amp;lt;/div&amp;gt;
  )
}

export default PageA&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;url이 &lt;a href=&quot;http://www.yj-dev.com/q=123&quot;&gt;http://www.yj-dev.com/q=123&lt;/a&gt; 이렇게 넘어왔다면 위에서 찍히는 console.log는 123이 된다.&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;redirect를 하기 위해서는&lt;/b&gt; 리액트 Router에서 제공하는 &lt;b&gt;Navigate 컴포넌트를 이용&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 주의할 것은 &lt;u&gt;Navigate와 useNavigate 훅은 전혀 다른것이라는 것!&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Navigate 사용은&lt;/p&gt;
&lt;pre id=&quot;code_1761051933768&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { Routes, Route, Navigate } from 'react-router-dom'
//위와 같이 import
//return 에서
&amp;lt;Navigate to='/pagea'&amp;gt;&amp;lt;/Navigate&amp;gt;;//Route의 path를 써주면 redirect가 된다&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 해주면 redirect가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;redirect가 많이 쓰이는 사용자만 보여야하는 페이지에 접근하려고 했을 때 로그인 페이지로 이동하도록 하는 경우 많이 쓰인다.&lt;/p&gt;</description>
      <category>Front/React</category>
      <category>Navigate</category>
      <category>PathVariable</category>
      <category>react</category>
      <category>usePrams</category>
      <category>useSearchParams</category>
      <category>리액트</category>
      <category>쿼리파라미터</category>
      <author>yu.dev</author>
      <guid isPermaLink="true">https://yj-dev.tistory.com/39</guid>
      <comments>https://yj-dev.tistory.com/39#entry39comment</comments>
      <pubDate>Tue, 21 Oct 2025 22:10:09 +0900</pubDate>
    </item>
    <item>
      <title>리액트 Router 쓰는 법</title>
      <link>https://yj-dev.tistory.com/38</link>
      <description>&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;b&gt;여러 페이지를 이동&lt;/b&gt;하면서 사용하게 되는데 이 때 리액트에서 필요한 것이 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Router&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;Router를 사용하기 위해서는 가장 먼저 &lt;b&gt;리액트 프로젝트에 Router를 설치&lt;/b&gt;하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 명령어를 터미널에 치면 Router 6버전이 설치 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1761049698734&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install react-router-dom@6&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;그럼 진짜로 Router를 사용해주기 위해서는 &lt;b&gt;main.jsx 파일에서 BrowserRouter를 사용&lt;/b&gt;해주자&lt;/p&gt;
&lt;pre id=&quot;code_1761049810788&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import './index.css'
import App from './App.jsx'
import { BrowserRouter } from 'react-router-dom' //import 필요!

createRoot(document.getElementById('root')).render(
  &amp;lt;StrictMode&amp;gt; //없애줘도 상관없긴 함
    &amp;lt;BrowserRouter&amp;gt; //BrowserRouter로 App을 감싸준다
      &amp;lt;App /&amp;gt;
    &amp;lt;/BrowserRouter&amp;gt;
  &amp;lt;/StrictMode&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;그 후 &lt;b&gt;App.jsx로 가서 진짜로 Router를 사용&lt;/b&gt;해보자&lt;/p&gt;
&lt;pre id=&quot;code_1761050009432&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { useState } from 'react'
import './App.css'
import PageA from './page/PageA'
import PageB from './page/PageB'
import { Routes, Route } from 'react-router-dom' //import 필요!

function App() {
  const [count, setCount] = useState(0)

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;Routes&amp;gt; {/* Routes 사용 */}
        &amp;lt;Route path='/' element={&amp;lt;PageA&amp;gt;&amp;lt;/PageA&amp;gt;}&amp;gt;&amp;lt;/Route&amp;gt; {/* 실제로 갈 페이지를 Route 함! path는 주소값으로 url 끝에 오게됨, element는 실제 페이지 태그를 넣어준다! */}
        &amp;lt;Route path='/pageb' element={&amp;lt;PageB&amp;gt;&amp;lt;/PageB&amp;gt;}&amp;gt;&amp;lt;/Route&amp;gt; {/* 이 경우 url이 http://www.yj-dev.com/pageb 이런식으로 path값인 about이 주소 끝에 옴 */}
      &amp;lt;/Routes&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;이렇게 되면 주소창에 url이 &lt;a href=&quot;http://yj-dev.com/&quot;&gt;http://yj-dev.com/&lt;/a&gt; 인 경우&amp;nbsp; PageA가 보일 것이고 &lt;a href=&quot;http://yj-dev.com/pageb&quot;&gt;http://yj-dev.com/pageb&lt;/a&gt; 인 경우에는 PageB가 보이게 된다.&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;근데 항상 이렇게 주소창에 url을 칠 수 없으니 &lt;u&gt;a태그나 버튼을 클릭했을 경우 페이지가 이동하는 것처럼 하는 방법&lt;/u&gt;은 무엇일까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그것은 &lt;b&gt;Link&lt;/b&gt;와 &lt;b&gt;useNavigate 훅&lt;/b&gt;을 이용하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Link를 이용&lt;/b&gt;하기 위해서는 아래와 같이 import를 해주고&lt;/p&gt;
&lt;pre id=&quot;code_1761050354695&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { Link } from 'react-router-dom'&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1761050428519&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;Link to='/pageb'&amp;gt;b페이지로 이동합니다.&amp;lt;/Link&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 사용하면 a태그처럼 링크가 걸려서 이동하게 된다. to는 Route에서 지정한 path값을 넣어주면 된다.&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;color: #333333; text-align: start;&quot;&gt;&lt;b&gt;useNavigate&lt;/b&gt;&lt;span&gt;&lt;b&gt; 훅은 아래와 같이 사용&lt;/b&gt;한다. useNavigate는 보통 함수를 통해서 이동해야하는 경우 자주 쓰인다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1761050522707&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//useNavigate 사용하기
import React from 'react'
import { useNavigate } from 'react-router-dom';//import 필요!

const PageB = () =&amp;gt; {
    const navigate = useNavigate();//useNavigate 훅을 선언

    const goToHomepage = () =&amp;gt; {
        navigate('/');//파라미터로 내가 가고싶은 주소를 넣는다! App.jsx에 Route의 path값을 넣으면 됨
    };

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;button onClick={goToPageA}&amp;gt;a페이지로 갑니다.&amp;lt;/button&amp;gt;//onClick 함수로 호출
    &amp;lt;/div&amp;gt;
  )
}

export default PageB&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Front/React</category>
      <category>link</category>
      <category>react</category>
      <category>Router</category>
      <category>useNavigate</category>
      <category>라우터</category>
      <category>리액트</category>
      <author>yu.dev</author>
      <guid isPermaLink="true">https://yj-dev.tistory.com/38</guid>
      <comments>https://yj-dev.tistory.com/38#entry38comment</comments>
      <pubDate>Tue, 21 Oct 2025 21:47:34 +0900</pubDate>
    </item>
    <item>
      <title>MsSQL 문자열을 날짜 및/또는 시간으로 변환하지 못했습니다.</title>
      <link>https://yj-dev.tistory.com/37</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;일 하는데 이딴 에러가 남...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내 경우에는 프로시저 호출하는데 데이터가 안 넘어와서 직접 mssm으로 조회해보는데 안됨...&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;날짜&amp;nbsp;및/또는&amp;nbsp;시간으로&amp;nbsp;변환하지&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;문제 쿼리는 UNION ALL 절인데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대략 쿼리를 쓰자면&lt;/p&gt;
&lt;pre id=&quot;code_1753345297449&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;DECLARE @TEMP TABLE
(
    ID VARCHAR(40)
    , EVENTTIME VARCHAR(MAX)
)

INSERT INTO @TEMP
SELECT ID
     , EVENTTIME
FROM SAMPLE1
;

SELECT ID
     , EVENTTIME
FROM SAMPLE2
UNION ALL
SELECT ID
     , EVENTTIME
FROM @TEMP&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이런 형식의 쿼리였음.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;근데 여기서 &lt;b&gt;SAMPLE1에 EVENTTIME컬럼이 DATETIME 같은 날짜형식일 경우 저런 에러가 나서&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;CONVERT를 해줘야한다.&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1753345413754&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;DECLARE @TEMP TABLE
(
    ID VARCHAR(40)
    , EVENTTIME VARCHAR(MAX)
)

INSERT INTO @TEMP
SELECT ID
     , CONVERT(CHAR(19), EVENTTIME, 120)
FROM SAMPLE1
;

SELECT ID
     , EVENTTIME
FROM SAMPLE2
UNION ALL
SELECT ID
     , EVENTTIME
FROM @TEMP&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Back/DB</category>
      <category>mssql</category>
      <category>쿼리</category>
      <author>yu.dev</author>
      <guid isPermaLink="true">https://yj-dev.tistory.com/37</guid>
      <comments>https://yj-dev.tistory.com/37#entry37comment</comments>
      <pubDate>Thu, 24 Jul 2025 17:24:50 +0900</pubDate>
    </item>
    <item>
      <title>PRG, Redirect, Forward</title>
      <link>https://yj-dev.tistory.com/36</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;강의 듣다가 오 이거 학원에서도 배웠는데 해서 정리 겸 작성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;학원 다닌지도 벌써 3년이네...;;&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;홈페이지가 있으면 form을 작성해서 저장 버튼을 눌러 내가 작성한 데이터를 저장하는 기능이 반드시 있을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쇼핑몰만 하더라도 Q&amp;amp;A 글을 작성하고 저장한다.&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;PRG가 아닌 경우&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;1180&quot; data-origin-height=&quot;757&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CZJs9/btsN7ZybI1j/jTFDsdTBLuMfVDhOnvZ3yk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CZJs9/btsN7ZybI1j/jTFDsdTBLuMfVDhOnvZ3yk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CZJs9/btsN7ZybI1j/jTFDsdTBLuMfVDhOnvZ3yk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCZJs9%2FbtsN7ZybI1j%2FjTFDsdTBLuMfVDhOnvZ3yk%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;1180&quot; height=&quot;757&quot; data-origin-width=&quot;1180&quot; data-origin-height=&quot;757&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PRG를 안 쓴다면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Q&amp;amp;A글을 남길 때 저장을 누르고 해당 Q&amp;amp;A로 이동하게 되더라고 주소창을 본다면 '/add'로 남아있을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 상태에서 새로고침을 누르면 다시 입력했던 내용이 똑같이 또 저장되고, 또 저장되고, ... 반복...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 상황을 피하기 위해 쓰는 것이 PRG(POST Redirect GET)&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;PRG인 경우&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;1293&quot; data-origin-height=&quot;1077&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/D2Nth/btsN8ppHc13/YrPcYnPvKZoIAw5gUItwlK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/D2Nth/btsN8ppHc13/YrPcYnPvKZoIAw5gUItwlK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/D2Nth/btsN8ppHc13/YrPcYnPvKZoIAw5gUItwlK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FD2Nth%2FbtsN8ppHc13%2FYrPcYnPvKZoIAw5gUItwlK%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;1293&quot; height=&quot;1077&quot; data-origin-width=&quot;1293&quot; data-origin-height=&quot;1077&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것이 PRG 형태&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 점이 있다면 Controller에서 글을 저장하고 서버에서 &lt;b&gt;Redirect&lt;/b&gt;를 해준다는 것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;Redirect를 해주면 서버에서 클라이언트에게 다른 URL로 이동하라고 응답을 보내 주소창을 보면 다른 주소로 바뀌게 된다.&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 되면 다른 URL로 페이지가 이동 되었기때문에 새로고침을 누르더라도 바뀐 URL로 호출하기 때문에 다시 저장이 되는 등 같은 문제가 없어짐!&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;u&gt;되도록이면 개발할 때 저장/수정 하면 PRG패턴을 쓰도록 하자&lt;/u&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;View를 이동하는데는 Forward도 있는데 Forward와 Redirect를 비교하자면&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;Redirect vs Forward&lt;/b&gt;&lt;/blockquote&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 122px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style13&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 13.7984%; height: 17px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 41.0078%; text-align: center; height: 17px;&quot;&gt;&lt;b&gt;Redirect&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 45.1937%; text-align: center; height: 17px;&quot;&gt;&lt;b&gt;Forward&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 13.7984%; height: 21px;&quot;&gt;방식&lt;/td&gt;
&lt;td style=&quot;width: 41.0078%; height: 21px;&quot;&gt;클라이언트에게 새 요청 지시(302 응답)&lt;/td&gt;
&lt;td style=&quot;width: 45.1937%; height: 21px;&quot;&gt;서버 내부에서 요청을 다른 리소스로 전달&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 13.7984%; height: 21px;&quot;&gt;URL 변경&lt;/td&gt;
&lt;td style=&quot;width: 41.0078%; height: 21px;&quot;&gt;O (주소창 바뀜)&lt;/td&gt;
&lt;td style=&quot;width: 45.1937%; height: 21px;&quot;&gt;X (주소창 그대로)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 42px;&quot;&gt;
&lt;td style=&quot;width: 13.7984%; height: 42px;&quot;&gt;요청 객체 유지&lt;/td&gt;
&lt;td style=&quot;width: 41.0078%; height: 42px;&quot;&gt;X (원래 POST 요청 데이터는 사라짐, 새 요청은 GET으로 시작)&lt;/td&gt;
&lt;td style=&quot;width: 45.1937%; height: 42px;&quot;&gt;O (객체가 유지되기 때문에 새로고침을 하면 Q&amp;amp;A 글 작성한게 또 저장됨)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 13.7984%; height: 21px;&quot;&gt;사용 목적&lt;/td&gt;
&lt;td style=&quot;width: 41.0078%; height: 21px;&quot;&gt;페이지 이동, 새 요청 유도&lt;/td&gt;
&lt;td style=&quot;width: 45.1937%; height: 21px;&quot;&gt;내부 자원 연결&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;</description>
      <category>Back/Spring</category>
      <category>forward</category>
      <category>get</category>
      <category>POST</category>
      <category>PRG</category>
      <category>redirect</category>
      <category>리다이렉트</category>
      <author>yu.dev</author>
      <guid isPermaLink="true">https://yj-dev.tistory.com/36</guid>
      <comments>https://yj-dev.tistory.com/36#entry36comment</comments>
      <pubDate>Wed, 21 May 2025 23:06:29 +0900</pubDate>
    </item>
  </channel>
</rss>