Skip to content

Commit

Permalink
Updates
Browse files Browse the repository at this point in the history
  • Loading branch information
phnml1 committed Oct 26, 2024
1 parent e2ec282 commit 851d3e4
Show file tree
Hide file tree
Showing 76 changed files with 42 additions and 42 deletions.
2 changes: 1 addition & 1 deletion 404.html
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><title>404: This page could not be found</title><meta name="next-head-count" content="3"/><link rel="preload" href="/_next/static/css/cea7fc6ccc7bac98.css" as="style" crossorigin=""/><link rel="stylesheet" href="/_next/static/css/cea7fc6ccc7bac98.css" crossorigin="" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" crossorigin="" nomodule="" src="/_next/static/chunks/polyfills-c67a75d1b6f99dc8.js"></script><script src="/_next/static/chunks/webpack-6f336cc197ef678d.js" defer="" crossorigin=""></script><script src="/_next/static/chunks/framework-66d32731bdd20e83.js" defer="" crossorigin=""></script><script src="/_next/static/chunks/main-aa55ffd08992d156.js" defer="" crossorigin=""></script><script src="/_next/static/chunks/pages/_app-e287481ee6e74633.js" defer="" crossorigin=""></script><script src="/_next/static/chunks/pages/_error-ee5b5fb91d29d86f.js" defer="" crossorigin=""></script><script src="/_next/static/owMDksqZMVYMHGpa0q1xs/_buildManifest.js" defer="" crossorigin=""></script><script src="/_next/static/owMDksqZMVYMHGpa0q1xs/_ssgManifest.js" defer="" crossorigin=""></script></head><body><div id="__next"><script>!function(){try{var d=document.documentElement,c=d.classList;c.remove('light','dark');var e=localStorage.getItem('theme');if('system'===e||(!e&&true)){var t='(prefers-color-scheme: dark)',m=window.matchMedia(t);if(m.media!==t||m.matches){d.style.colorScheme = 'dark';c.add('dark')}else{d.style.colorScheme = 'light';c.add('light')}}else if(e){c.add(e|| '')}if(e==='light'||e==='dark')d.style.colorScheme=e}catch(e){}}()</script><div style="font-family:system-ui,&quot;Segoe UI&quot;,Roboto,Helvetica,Arial,sans-serif,&quot;Apple Color Emoji&quot;,&quot;Segoe UI Emoji&quot;;height:100vh;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center"><div style="line-height:48px"><style>body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}</style><h1 class="next-error-h1" style="display:inline-block;margin:0 20px 0 0;padding-right:23px;font-size:24px;font-weight:500;vertical-align:top">404</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;line-height:28px">This page could not be found<!-- -->.</h2></div></div></div></div><script id="__NEXT_DATA__" type="application/json" crossorigin="">{"props":{"pageProps":{"statusCode":404}},"page":"/_error","query":{},"buildId":"owMDksqZMVYMHGpa0q1xs","nextExport":true,"isFallback":false,"gip":true,"scriptLoader":[]}</script></body></html>
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><title>404: This page could not be found</title><meta name="next-head-count" content="3"/><link rel="preload" href="/_next/static/css/cea7fc6ccc7bac98.css" as="style" crossorigin=""/><link rel="stylesheet" href="/_next/static/css/cea7fc6ccc7bac98.css" crossorigin="" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" crossorigin="" nomodule="" src="/_next/static/chunks/polyfills-c67a75d1b6f99dc8.js"></script><script src="/_next/static/chunks/webpack-6f336cc197ef678d.js" defer="" crossorigin=""></script><script src="/_next/static/chunks/framework-66d32731bdd20e83.js" defer="" crossorigin=""></script><script src="/_next/static/chunks/main-aa55ffd08992d156.js" defer="" crossorigin=""></script><script src="/_next/static/chunks/pages/_app-e287481ee6e74633.js" defer="" crossorigin=""></script><script src="/_next/static/chunks/pages/_error-ee5b5fb91d29d86f.js" defer="" crossorigin=""></script><script src="/_next/static/ouFxnvAPXOOQRIKArTLFG/_buildManifest.js" defer="" crossorigin=""></script><script src="/_next/static/ouFxnvAPXOOQRIKArTLFG/_ssgManifest.js" defer="" crossorigin=""></script></head><body><div id="__next"><script>!function(){try{var d=document.documentElement,c=d.classList;c.remove('light','dark');var e=localStorage.getItem('theme');if('system'===e||(!e&&true)){var t='(prefers-color-scheme: dark)',m=window.matchMedia(t);if(m.media!==t||m.matches){d.style.colorScheme = 'dark';c.add('dark')}else{d.style.colorScheme = 'light';c.add('light')}}else if(e){c.add(e|| '')}if(e==='light'||e==='dark')d.style.colorScheme=e}catch(e){}}()</script><div style="font-family:system-ui,&quot;Segoe UI&quot;,Roboto,Helvetica,Arial,sans-serif,&quot;Apple Color Emoji&quot;,&quot;Segoe UI Emoji&quot;;height:100vh;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center"><div style="line-height:48px"><style>body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}</style><h1 class="next-error-h1" style="display:inline-block;margin:0 20px 0 0;padding-right:23px;font-size:24px;font-weight:500;vertical-align:top">404</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;line-height:28px">This page could not be found<!-- -->.</h2></div></div></div></div><script id="__NEXT_DATA__" type="application/json" crossorigin="">{"props":{"pageProps":{"statusCode":404}},"page":"/_error","query":{},"buildId":"ouFxnvAPXOOQRIKArTLFG","nextExport":true,"isFallback":false,"gip":true,"scriptLoader":[]}</script></body></html>
File renamed without changes.
1 change: 1 addition & 0 deletions _next/data/ouFxnvAPXOOQRIKArTLFG/posts/tag/Algorithm.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions _next/data/ouFxnvAPXOOQRIKArTLFG/posts/tag/hook.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"pageProps":{"tags":["react","JavaScript","deepdive","useState","hook","클로저","생명주기","Virtual DOM","Algorithm","백준","gold","dfs","프로그래머스","lv3","bfs","이분탐색"],"currentTag":"hook","posts":[{"slug":"posts/React/React useState 훅과 클로저","title":"React useState 훅과 클로저","date":"2024-10-26T18:00:24.000Z","image":"index.png","summary":"클로저를 이용한 React useState 훅의 작동 원리를 이해해보자","tags":["react","JavaScript","deepdive","useState","hook","클로저"],"content":"# React useState 훅과 클로저\r\n\r\n클로저에 대해 개념은 알고 있었지만, 사실 면접 질문때나 쓰이는 것이고, 실제로 어떻게 쓰이는지에 대해서는 와닿지 못한 부분도 있었다. 그러던 도중 react deep dive를 공부하며, react 개발자가 아마도 가장 많이 사용하는 **useState**에 클로저가 쓰인다는 사실을 알았다! \r\n어떻게 쓰이는 지 함께 살펴보자.\r\n\r\n\r\n\r\n## 상태값을 어떻게 관리할까\r\n보통 useState의 기본 사용법은 다음과 같을 것이다\r\n```js\r\nimport { useState } from 'react'\r\n\r\nconst [state, setState] = useState\r\n```\r\n인수로 state의 초깃값을 넘겨주고, 만일 아무것도 안넘겨주면 초깃값은 undefined일 것이다.\r\n훅의 반환 값은 배열이고, 배열의 첫 번째 원소는 state 값 자체이며, 두 번째 원소는 setState 함수를 통해 해당 state 값을 변경할 수 있다.\r\n\r\n\r\n**리액트에서 렌더링은 함수 컴포넌트의 return을 실행한 다음, 실행 결과를 이전의 리액트 트리와 비교해 리렌더링이 필요한 부분만 업데이트해 이뤄진다.**\r\n그렇기 때문에 렌더링 방식이랑 메커니즘이 다른 변수를 통해서 상태값을 관리하는 것은 적절하지 못하다. (이전 글 react virtualDOM 참고)\r\n\r\n그렇다면 다음 코드를 살펴보자.\r\n\r\n```js\r\nimport React from 'react'\r\n\r\nconst Component = () => {\r\n const [,triggerRender] = useState()\r\n let state = 'hello'\r\n\r\n function handleButtonClick() {\r\n state = 'hi'\r\n triggerRender()\r\n }\r\n return (\r\n <>\r\n <h1>{state}</h1>\r\n <button onClick={handleButtonClick}>hi</button>\r\n </>\r\n )\r\n}\r\n```\r\nuseState 반환값의 두 번째 원소를 실행해 리액트에 렌더링이 일어나게끔 변경했다. \r\n그럼에도 여전히 버튼 클릭시 state의 변경된 값이 렌더링되고 있지 않다. \r\n\r\n그 이유는 리액트의 렌더링은 **함수 컴포넌트에서 반환한 결과물인 return의 값을 비교해 실행되기 때문이다.** \r\n\r\n즉, 매번 렌더링이 발생할 때마다 함수는 새롭게 실행이 되고, 실행한 함수에서 state는 매번 hello로 초기화 되므로 아무리 state를 변경해도 hello로 초기화 되는 것이다. \r\n\r\n근데 렌더링이 될 때마다 초기화되는 변수(값)와는 달리, useState의 결과값은 어떻게 그 값을 유지할까?\r\n\r\nuseState의 결과 값이 유지되도록, state를 함수로 하여 state 값을 호출할 때마다 현재 state를 반환하게 해보자.\r\n```js\r\nfunction useState(initialValue) {\r\n\tlet initialState = initialValue;\r\n\t\r\n\tfunction state() {\r\n\t\treturn initialState\r\n\t}\r\n\tfunction setState(newValue) {\r\n\t\tinitialState = newValue\r\n\t}\r\n\treturn [state, setState];\r\n}\r\nconst [value, setState] = useState(0);\r\nsetValue(1);\r\nconsole.log(value()); // 1\r\n```\r\n위의 코드도 나쁘진 않지만, 우리에게 익숙한 useState훅은 state를 함수가 아닌 상수처럼 사용하고 있다.\r\n\r\n## 클로저를 이용해 상태를 관리하는 useState\r\n이를 위해서 리액트는 **클로저**를 이용한 것이다. \r\nuseState는 클로저를 통해 useState 내부의 선언된 함수(setState)가 함수의 실행이 종료된 이후(useState가 호출된 이후)에도 지역변수인 state를 계속 참조할 수 있다.\r\n\r\nuseState 작동 방식을 대략적으로 흉내 낸 코드는 다음과 같다.\r\n\r\n```js\r\nconst MyReact = (function() {\r\n\tconst global = {}\r\n let index = 0\r\n \r\n function useState(initialState){\r\n \tif(!global.states) {\r\n \t// 애플리케이션 전체의 states 배열 초기화, 최초 접근이면 빈 배열로\r\n \tglobal.states = []\r\n }\r\n // states 정보를 조회해서, 현재 상태값이 있는지 확인\r\n // 없다면 초깃값으로 설정\r\n const currentState = global.states[index] || initialState\r\n // 위에서 조회한 값으로 states의 값 업데이트\r\n global.states[index] = currentState\r\n \r\n // 즉시실행함수로 setter 만듬\r\n const setState = (function() {\r\n \t// 클로저로 index를 가둬두어서 동일한 index에 접근이 가능\r\n \tlet currentIndex = index\r\n return function(value){\r\n \tglobal.states[currentIndex] = value\r\n //컴포넌트 렌더링이 들어가는 부분이다.(실제 코드는 생략)\r\n }\r\n })()\r\n // useState를 쓸 때마다 index를 하나씩 추가하는데, 이는 하나의 state마다\r\n // index가 할당되어있어, 그 index가 배열의 값(global.states)를 가리키고,\r\n // 필요할 때마다 그 값을 가져오게 하는 것이다.\r\n index = index + 1\r\n \r\n return [currentState,setState]\r\n}\r\n\r\nfunction Component() {\r\n\tconst [value, setValue] = useState(0);\r\n}\r\n})();\r\n```\r\n\r\n실제 리액트 코드에서는 useReducer를 이용해 구현되어 있어 약간의 차이가 있다.\r\n\r\n아무튼 여기서 함수의 실행이 끝났음에도 함수가 선언된 환경을 기억할 수 있는 방법이 바로 클로저인 것이다. 만약 클로저가 없다면, `setState`는 항상 `index`의 현재 값에 의존하게 된다. 즉, 컴포넌트가 여러 상태를 갖고 있을 때 마지막 `index`만 참조하므로, `setState`가 올바른 위치를 참조하지 않게 되는 것이다.\r\n\r\n매번 실행되는 함수 컴포넌트 환경에서 state의 값을 유지하고 사용하기 위해 리액트는 클로저를 활용하고 있다.\r\n\r\n`\r\n훅에 대한 구현체를 github에서 타고 올라가다보면 __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED 라는 문구를 만나게된다(무섭다 ㅋㅋ)\r\n위의 코드는 Preact의 구현을 기준으로 하고 있다. Preact는 react의 경량화 버전으로,\r\n대부분의 리액트 API를 지원하고 있다. \r\n`\r\n## 결론\r\nReact의 `useState`는 클로저를 통해 상태값을 안정적으로 유지하며, 함수 컴포넌트가 여러 번 호출되더라도 **각 상태값이 고유한 위치에 저장**될 수 있게 한다. `useState`가 반환하는 `setState` 함수는 생성 당시의 상태 위치(`index`)를 클로저로 캡처하여, 해당 상태값만 정확히 업데이트하도록 구현되어 있다.\r\n\r\n정리하자면, 클로저는 `setState`가 함수가 선언된 당시의 환경을 유지하게 해주기 때문에 **컴포넌트가 매번 재실행될 때마다 상태가 초기화되는 것을 방지**하고, 상태가 올바르게 유지될 수 있게 해준다.\r\n\r\n**참고**\r\n\r\n[서적] 모던 리액트 Deep Dive\r\n"}]},"__N_SSG":true}
1 change: 1 addition & 0 deletions _next/data/ouFxnvAPXOOQRIKArTLFG/posts/tag/react.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions _next/data/ouFxnvAPXOOQRIKArTLFG/posts/tag/백준.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"pageProps":{"tags":["react","JavaScript","deepdive","useState","hook","클로저","생명주기","Virtual DOM","Algorithm","백준","gold","dfs","프로그래머스","lv3","bfs","이분탐색"],"currentTag":"백준","posts":[{"slug":"posts/Algorithm/[백준 gold 5] 빌런 호석","title":"[백준 gold 5] 빌런 호석","date":"2024-08-09T17:05:24.000Z","image":"index.png","summary":"dfs을 활용한 프로그래머스 [level 3] 징검다리 건너기 문제 풀이 입니다.","tags":["Algorithm","백준","gold","dfs"],"content":"# [gold 3] 빌런 호석\r\n\r\n## 문제 설명\r\n\r\n치르보기 빌딩은 11층부터 NN층까지 이용이 가능한 엘리베이터가 있다. 엘리베이터의 층수를 보여주는 디스플레이에는 KK 자리의 수가 보인다. 수는 00으로 시작할 수도 있다. 00부터 99까지의 각 숫자가 디스플레이에 보이는 방식은 아래와 같다. 각 숫자는 7개의 표시등 중의 일부에 불이 들어오면서 표현된다.\r\n\r\n![](1.png)\r\n\r\n예를 들어 K=4K=4인 경우에 16801680층과 501501층은 아래와 같이 보인다.\r\n\r\n![](2.png)\r\n\r\n\r\n\r\n빌런 호석은 치르보기 빌딩의 엘리베이터 디스플레이의 LED 중에서 최소 11개, 최대 PP개를 반전시킬 계획을 세우고 있다. 반전이란 켜진 부분은 끄고, 꺼진 부분은 켜는 것을 의미한다. 예를 들어 숫자 11을 22로 바꾸려면 총 5개의 LED를 반전시켜야 한다. 또한 반전 이후에 디스플레이에 올바른 수가 보여지면서 11 이상 NN 이하가 되도록 바꿔서 사람들을 헷갈리게 할 예정이다. 치르보기를 사랑하는 모임의 회원인 당신은 호석 빌런의 행동을 미리 파악해서 혼쭐을 내주고자 한다. 현재 엘리베이터가 실제로는 XX층에 멈춰있을 때, 호석이가 반전시킬 LED를 고를 수 있는 경우의 수를 계산해보자.\r\n\r\n### 입력\r\n\r\n N,K,P,XN,K,P,X 가 공백으로 구분되어 첫째 줄에 주어진다.\r\n\r\n### 출력\r\n\r\n호석 빌런이 엘리베이터 LED를 올바르게 반전시킬 수 있는 경우의 수를 계산해보자.\r\n\r\n## 접근 방법\r\n\r\n숫자에 따른 LED를 먼저 구현하기 위해, \r\n\r\n그림과 같이, 각 LED의 위치에 번호를 매겨, 배열안에 그 번호가 있으면 불이 켜져있는 것으로, 없다면 불이 꺼져 있는 것으로 표현하였다.\r\n<img src=\"3.png\" alt=\"이미지 설명\" width=\"200\" height=\"300\" />\r\n\r\n\r\n그림처럼 0을 표현하면 3번자리를 제외한 모든 번호가 켜져있으므로, `[0,1,2,4,5,6]`으로 표현 할 수 있다.\r\n\r\n각 번호를 이와 같이 바꾸어 numbers 배열에 저장하면, 이와 같다.\r\n```python\r\nnumbers = [[0,1,2,4,5,6],[2,5],[0,2,3,4,6],[0,2,3,5,6],[1,2,3,5],[0,1,3,5,6],[0,1,3,4,5,6],[0,2,5],[0,1,2,3,4,5,6],[0,1,2,3,5,6]];\r\n```\r\n이후 만일 현재 번호와 비교할 번호의 LED를 비교하기 위해 서로의 차집합을 더해서 두 번호가 서로를 비교했을 때, 가지고 있는 혹은 없는 번호의 개수를 구한다.\r\n```python\r\ncur_count = len(list(cur.difference(compare))) + len(list(compare.difference(cur)));\r\n```\r\n이와 같은 방식으로 반전시킬 LED의 개수를 구하고, dfs를 활용하여 x의 모든 자릿수를 순회하여 p보다 작거나 같게 LED를 반전하면서, n보다 번호가 작거나 같다면 result를 1 증가 시킨다.\r\n\r\n전체코드는 다음과 같다.\r\n```python\r\nimport sys;\r\ninput = sys.stdin.readline;\r\n\r\nn,k,p,x = map(int, input().split());\r\nresult = 0;\r\nnumbers = [[0,1,2,4,5,6],[2,5],[0,2,3,4,6],[0,2,3,5,6],[1,2,3,5],[0,1,3,5,6],[0,1,3,4,5,6],[0,2,5],[0,1,2,3,4,5,6],[0,1,2,3,5,6]];\r\n\r\nx = list(str(x));\r\nif len(x) != k:\r\n\t# k 보다 자릿수 x가 자릿수가 작다면 작은 만큼 앞에 0을 채워주어야 한다.\r\n for _ in range(k-len(x)):\r\n x.insert(0,'0');\r\n \r\ndef dfs(index,count,st):\r\n global result;\r\n if count>p:\r\n return;\r\n if index == k:\r\n if 0<count<=p and 0<int(st)<=n:\r\n result += 1;\r\n return;\r\n cur = set(numbers[int(x[index])]);\r\n for i in range(len(numbers)):\r\n compare = set(numbers[i]);\r\n cur_count = len(list(cur.difference(compare))) + len(list(compare.difference(cur)));\r\n if count + cur_count <=p:\r\n dfs(index+1,count + cur_count,st + str(i));\r\ndfs(0,0,'');\r\nprint(result);\r\n```\r\n\r\n## 느낀 점\r\n사실 이 문제와 관련하여 다른 풀이도 많이 찾아보았고, 더욱 시간이 적게 걸리는 풀이도 많았어서 시간 초과는 나지 않았지만 다소 비효율적인 풀이였다는 생각이 들었다.\r\n\r\n또한 제한 사항중 `또한 반전 이후에 디스플레이에 올바른 수가 보여지면서 1 이상 N 이하가 되도록 바꿔서 사람들을 헷갈리게 할 예정이다.`를 못봐서 계속 `0<=int(st)<=n`로 조건을 설정해놓고 헤맸었다. 문제의 조건을 유심히 보는 습관을 들여야 함을 다시한번 느낀다."}]},"__N_SSG":true}
Loading

0 comments on commit 851d3e4

Please sign in to comment.