<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>alex im</title>
    <link>https://alexim.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Tue, 7 Apr 2026 05:20:47 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>Alexim</managingEditor>
    <image>
      <title>alex im</title>
      <url>https://tistory1.daumcdn.net/tistory/4699430/attach/9d2dc297728a4134a973304e48d181e0</url>
      <link>https://alexim.tistory.com</link>
    </image>
    <item>
      <title>[컴퓨터구조] 프로세서와 스레드</title>
      <link>https://alexim.tistory.com/46</link>
      <description>&lt;h1&gt;프로세서&lt;/h1&gt;
&lt;p&gt;명령어들을 처리하고 반응하기 위한 논리 회로를 말한다.크게는 소프트웨어 신호를 받아 다른 하드웨어 부분으로 신호를 보내는 제어장치와 연산을 담당하는 연산장치로 구성된다.프로세스가 존재한다면 무조건 스레드도 하나 이상 존재한다.&lt;/p&gt;
&lt;h1&gt;스레드&lt;/h1&gt;
&lt;p&gt;프로세스 내에서 실행되는 흐름 단위멀티프로세스와 멀티스레드는 양쪽 모두 여러 흐름이 동시에 진행된다는 공통점을 가지고 있다. &lt;/p&gt;
&lt;h1&gt;멀티 프로세스&lt;/h1&gt;
&lt;p&gt;하나의 어플리케이션을 여러 개의 프로세스로 구성하여 각 프로세스가 하나의 작업을 처리하도록 하는 것 .    각 프로세스는 독립적으로 실행되며 각각 별개의 메모리를 차지하고 있다.     안정성이 좋다. 자식 프로세스 중 하나에 문제가 발생해도 다른 자식 프로세스에 영향이 확산되지 않는다. 작업량이 많을 수록 오버헤드가 발생할 수 있다.&lt;/p&gt;
&lt;h1&gt;멀티 스레드&lt;/h1&gt;
&lt;p&gt;하나의 애플리케이션을 여러 개의 스레드로 구성하여 하나의 스레드가 하나의 작업을 처리하도록 하는 것.   자원 공유가 쉽다. 스레드들은 부모 프로세스의 자원과 메모리를 공유할 수 있다. 프로세스 간의 전환 속도보다 스레드 간의 전환 속도가 빠르다. 자식 스레드 중 하나에 문제가 생긴 경우 전체 프로세스에 영향을 줄 수 있다. 프로그램 디버깅이 어렵다.  (동시다발적으로 실행되기 때문에)&lt;/p&gt;
&lt;h1&gt;클러스터&lt;/h1&gt;
&lt;p&gt;노드 js는 기본적으로 싱글 스레드. 노드js 어플리케이션은 하나의 코어에서 실행되기 때문에 cpu가 멀티 코어인 경우에는 컴퓨터가 가진 성능을 온전히 발휘하지 못하는 일이 될 수 있어 클러스터라는 기능을 제공하고 있다.    어플리케이션 스레드 간에 워크로드를 분산할 수 있는 node.js의 여러 인스턴스를 실행할 수 있다. 클러스터 모듈을 사용하면 모든 서버 포트를 공유하는 자식 프로세스를 쉽게 만들 수 있다.&lt;/p&gt;</description>
      <category>기타</category>
      <author>Alexim</author>
      <guid isPermaLink="true">https://alexim.tistory.com/46</guid>
      <comments>https://alexim.tistory.com/46#entry46comment</comments>
      <pubDate>Mon, 26 Sep 2022 00:01:52 +0900</pubDate>
    </item>
    <item>
      <title>[HTTP] HTTP 인증</title>
      <link>https://alexim.tistory.com/45</link>
      <description>&lt;h1&gt;HTTP 인증&lt;/h1&gt;
&lt;p&gt;http는 액세스 제어 및 인증을 위한 일반 프레임워크를 제공한다.&lt;/p&gt;
&lt;h2&gt;일반적인 HTTP 인증 프레임워크&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;http-auth-sequence-diagram.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;서버는 클라이언트에게 401 (Unauthorized) 응답 코드를 가지고 응답한다.  최소한 한 번의 시도에 포함된  &lt;code&gt;WWW-Authenticate&lt;/code&gt;  응답헤더로 권한을 부여하는 방법에 대한 정보를 제공한다. &lt;/li&gt;
&lt;li&gt;서버와 인증을 하기를 원하는 클라이언트는 Authorization 요청 헤더 필드에 인증 정보를 포함함으로써 인증을 수행할 수 있다. &lt;/li&gt;
&lt;li&gt;그림에서 보는 것과 같이 &lt;strong&gt;Basic&lt;/strong&gt; 인증의 경우, 교환은 안전을 위해 HTTPS (TLS) 위에서 발생하여야 한다.&lt;/li&gt;
&lt;li&gt;위의 그림에 사용된 “Basic” 인증 체계는 인코딩되지만 암호화되지 않은 자격 증명을 보낸다. 교환이 보완 연결(HTTP/TLS)을 통하지 않는 한 이것은 완전히 안전하지 않다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;프록시 인증&lt;/h2&gt;
&lt;p&gt;동일한 시도 및 응답 메커니즘이 프록시 인증을 위해서도 사용될 수 있다. 이 경우에 이것은 인증을 요구하는 중간 프록시이다.&lt;br&gt;리소스 인증 및 프록시 인증은 &lt;strong&gt;함께 존재&lt;/strong&gt; 할 수 있기 때문에, 헤더와 상태 코드의 다른 세트가 필요하다. 프록시의 경우, 요청에 대한 상태 코드는 &lt;code&gt;407&lt;/code&gt; , 요청 헤더는 (Proxy-Authentication 이고 요청 헤더는 프록시 서버에 인증 정보를 제공하기 위해 사용된다., 응답 헤더인 Proxy-Authoricate에는 프록시에 적용 가능한 하나 이상의 챌린지가 포함되며 요청 헤더는 프록시 서버에 인증 정보를 제공하는 데 사용된다.&lt;/p&gt;
&lt;h3&gt;접근 거부&lt;/h3&gt;
&lt;p&gt;프록시 서버가 주어진 리소스에 대한 접근 권한을 얻기 위해 적절하지 않은 유효한 인증 정보를 수신한다면, 서버는 &lt;code&gt;403``Forbidden&lt;/code&gt; 상태 코드로 응답해야 한다. &lt;code&gt;401``Unauthorizaed&lt;/code&gt;나 &lt;code&gt;407``Proxy Authentication Required&lt;/code&gt;와는 다르게, 해당 사용자에 대한 인증은 불가능하다.&lt;/p&gt;
&lt;h2&gt;WWW-Authenticate와 Proxy-Authenticate 헤더&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;이 응답 헤더들은 자원에 대한 액세스를 얻기 위해 사용되어야 할 인증 방법을 정의한다.&lt;/li&gt;
&lt;li&gt;이들은 인증을 하려는 클라이언트가 인증 정보를 제공할 방법을 알기 위해, 어떤 인증 &lt;strong&gt;스킴&lt;/strong&gt; 이 사용될 것인지를 구체적으로 적어야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;WWW-Authenticate: &amp;lt;type&amp;gt; realm=&amp;lt;realm&amp;gt;
Proxy-Authenticate: &amp;lt;type&amp;gt; realm=&amp;lt;realm&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;type&amp;gt;&lt;/code&gt; : 인증 스킴(Scheme)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;realm&lt;/code&gt; : 보호되는 영역을 설명하거나 보호의 범위를 알리는데 사용된다. 이는 어떤 공간에 사용자가 접근하려고 시도하는지를 알리기 위하여, “중간 단계의 사이트에 대한 접근”과 같거나 또는 비슷한 메시지가 될 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;인증 스킴&lt;/h2&gt;
&lt;p&gt;일반적인  HTTP 인증 프레임워크는 여러 인증 스킴에 의해 사용된다. 스킴은 보안 강도와 클라이언트 또는 서버 소프트웨어에서 사용 가능성에 따라 달라질 수 있다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;일반적인 인증 스킴 목록&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;Basic (base64-encoded credentials)&lt;ul&gt;
&lt;li&gt;이는 base64를 이용하여 인코딩된 사용자 ID/비밀번호 쌍의 인증 정보를 전달한다.&lt;/li&gt;
&lt;li&gt;사용자 ID와 비밀번호가 평문으로 네트워크를 통해 전달되기 때문에 (base64로 인코딩 되어 있으나, base64는 복호화가 가능한 인코딩이다.) Basic 인증 스킴은 안전하지 않기 때문에 HTTPS/TLS와 함께 사용해야 한다. 이러한 추가적인 보안상의 향상 없이는 민감하거나 귀중한 정보를 보호하는 데 사용되어서는 안된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Bearer (bearer tokens to access OAuth 2.0-protected resources)&lt;ul&gt;
&lt;li&gt;OAuth: Bearer를 이용한 토큰 기반인증의 공개 표준 프로토콜&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Digest &lt;/li&gt;
&lt;li&gt;HOBA&lt;/li&gt;
&lt;li&gt;Mutual&lt;/li&gt;
&lt;li&gt;AWS4-HMAC-SHA256&lt;/li&gt;
&lt;/ol&gt;</description>
      <category>기타</category>
      <author>Alexim</author>
      <guid isPermaLink="true">https://alexim.tistory.com/45</guid>
      <comments>https://alexim.tistory.com/45#entry45comment</comments>
      <pubDate>Mon, 26 Sep 2022 00:00:47 +0900</pubDate>
    </item>
    <item>
      <title>[React] 공식문서 HOOK 4 ~ 8정리</title>
      <link>https://alexim.tistory.com/44</link>
      <description>&lt;h1&gt;Effect Hook&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;side effect를 수행할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Side Effect란?&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;데이터 가져오기&lt;/li&gt;
&lt;li&gt;구독(subscription) 설정하기&lt;/li&gt;
&lt;li&gt;수동으로 React 컴포넌트 DOM 수정하기&lt;/li&gt;
&lt;li&gt;결과를 예상할 수 없는 것&lt;/li&gt;
&lt;li&gt;렌더링 과정에서 구현할 수 없는 작업&lt;/li&gt;
&lt;li&gt;다른 컴포넌트에 영향을 줄 수 있는 작업&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;정리(Clean-up)를 이용하지 않는 Effects&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;네트워크 리퀘스트, DOM 수동 조작, 로깅 등은 정리가 필요 없는 경우들이다. 이러한 예들은 실행 이후 신경 쓸 것이 없기 때문&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;useEffect가 하는 일&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;컴포넌트가 렌더링 이후에 어떤 일을 수행해야하는 지를 말한다.&lt;/li&gt;
&lt;li&gt;useEffect 안의 함수는 DOM 업데이트를 수행한 이후에 불러낸다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;useEffect를 컴포넌트 안에서 불러내는 이유&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;effect를 통해 state 변수 또는 prop에 접근할 수 있게 된다.&lt;/li&gt;
&lt;li&gt;함수 범위 안에 존재하기 때문에 특별한 API 없이도 값을 얻을 수 있는 것&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;useEffect 렌더링 순서&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;기본적으로 첫번째 렌더링과 이후의 모든 업데이트에서 수행된다.&lt;/li&gt;
&lt;li&gt;마운팅과 업데이트라는 방식으로 생각하는 대신 effect를 렌더링 이후에 발생하는 것으로 생각하는 것이 더 쉬울 것&lt;/li&gt;
&lt;li&gt;컴포넌트를 렌더링할 때 React는 이용한 effect를 기억하였다가 DOM을 업데이트한 이후에 실행한다. &lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;대부분의 effect는 동기적으로 실행될 필요가 없다.&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;흔하지는 않지만 동기적 실행이 필요한 경우에는 useEffect와 동일한 API를 사용하는 useLayoutEffect라는 별도의 Hook이 존재한다. (먼저 useEffect를 사용해 보고 문제가 있다면 그 다음으로 useLayoutEffect를 사용해 보기를 권한다.)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;정리(clean-up)를 이용하는 Effects&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;외부 데이터에 구독(subscription)을 설정해야 하는 경우에는 &lt;strong&gt;메모리 누수&lt;/strong&gt; 가 발생하지 않도록 정리하는 것은 매우 중요하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;effect에 정리가 필요한 경우에는 함수를 반환한다.&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;  useEffect(() =&amp;gt; {
    function handleStatusChange(status) {
      setIsOnline(status.isOnline);
    }

    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    return () =&amp;gt; {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import React, { useState, useEffect } from &amp;#39;react&amp;#39;;

function FriendStatus(props) {
  const [isOnline, setIsOnline] = useState(null);

  useEffect(() =&amp;gt; {
    function handleStatusChange(status) {
      setIsOnline(status.isOnline);
    }
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange); // 구독
    // effect 이후에 어떻게 정리(clean-up)할 것인지 표시합니다.
    return function cleanup() {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });

  if (isOnline === null) {
    return &amp;#39;Loading...&amp;#39;;
  }
  return isOnline ? &amp;#39;Online&amp;#39; : &amp;#39;Offline&amp;#39;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;effect에서 함수를 반환하는 이유?&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;이는 effect를 위한 추가적인 정리 메커니즘. 모든 effect는 정리를 위한 함수를 반환할 수 있다. 이 점이 구독의 추가와 제거를 위한 로직을 가까이 묶어둘 수 있게 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;React가 effect를 정리하는 시점은 언제?&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;React는 컴포넌트가 마운트 해제되는 때에 정리를 실행한다.&lt;/li&gt;
&lt;li&gt;위의 예시에서 보면 effect는 한 번이 아니라 렌더링이 실행되는 때마다 실행된다. React가 다음 차례의 effect를 실행하기 전에 이전의 렌더링에서 파생된 effect 또한 정리하는 이유는 메모리 누수나 충돌이 발생하는 것을 방지하기 위함이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Effect를 건너뛰어 성능 최적화하기&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;모든 렌더링 이후에 effect를 정리하거나 적용하는 것이 때때로 성능 저하를 발생시키는 경우도 있다.&lt;/li&gt;
&lt;li&gt;클래스 컴포넌트의 경우에는 &lt;code&gt;componentDidUpdate&lt;/code&gt;에서 &lt;code&gt;prevProps&lt;/code&gt;나 &lt;code&gt;prevState&lt;/code&gt;와의 비교를 통해 이러한 문제를 해결할 수 있다.&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;componentDidUpdate(prevProps, prevState) {
if (prevState.count !== this.state.count) {
  document.title = `You clicked ${this.state.count} times`;
}
}&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;useEffect에는 이러한 기능이 내장되어 있다. useEffect의 선택적 인수인 두 번째 인수로 배열을 넘기면 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;useEffect에서 의존성 배열을 사용할 때 주의해야 할 점&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;배열이 컴포넌트 범위 내에서 바뀌는 값들과 effect에 의해 사용되는 값들을 모두 포함해야 한다. 그렇지 않으면 현재 값이 아닌 이전의 렌더링 때의 값을 참고하게 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Hook 규칙&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;최상위에서만 Hook을 호출해야 한다.&lt;/li&gt;
&lt;li&gt;오직 React 함수 내에서 Hook을 호출해야 한다. (또는 Custom Hook)&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;자신만의 Hook 만들기&lt;/h1&gt;
&lt;h2&gt;사용자 정의 Hook 추출하기&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;두 개의 자바스크립트 함수에서 같은 로직을 공유하고자 할 때는 또 다른 함수로 분리한다. 컴포넌트와 Hook 또한 함수이기 때문에 같은 방법을 사용할 수 있다.&lt;/li&gt;
&lt;li&gt;사용자 정의 Hook은 이름이 &lt;code&gt;use&lt;/code&gt;로 시작하는 자바스크립트 함수이다.&lt;/li&gt;
&lt;li&gt;같은 Hook을 사용하는 두 개의 컴포넌트는 state를 공유하지 않는다. 사용자 정의 Hook은 상태 관련 로직을 재사용하는 매커니즘이지만 사용자 Hook을 사용할 때마다 그 안의 state와 effect는 완전히 &lt;strong&gt;독립적이다.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;useEffect의 콜백이 개별 사용자 입력의 결과이거나 flushSync로 래핑된 업데이트의 결과인 경우&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;레이아웃 및 페인트 전에 동기적으로 실행된다. &lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;useRef&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;useRef hook은 DOM ref 만을 위한 것이 아니다. &amp;quot;ref&amp;quot; 객체는 현재 프로퍼티가 변경할 수 있고 어떤 값이든 보유할 수 있는 일반 컨테이너이다. 이는 class의 인스턴스 프로퍼티와 유사하다.&lt;/li&gt;
&lt;li&gt;useEffect 내부에서 쓸 수 있다.&lt;/li&gt;
&lt;li&gt;지연 초기화를 수행하지 않는 한, 렌더링 중이 ref 설정을 피해라. 일반적으로 이벤트 처리와 effect에서 ref를 수정하는 것이 좋다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;고비용의 객체를 지연해서 생성하는 법&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;useMemo&lt;/code&gt;를 사용하면 종속성이 동일한 경우 값비싼 계산을 메모할 수 있다. 그러나 힌트 역할을 할 뿐이며 계산이 다시 실행되지 않는다는 보장은 없다. 때로는 객체가 한 번만 생성되었는지 확인해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;1. 일반적인 사용 사례 : 초기 state를 만드는 데 비용이 많이 드는 경우&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;function Table(props) {
  // ✅ createRows()는 한 번만 호출됩니다
  const [rows, setRows] = useState(() =&amp;gt; createRows(props.count));
  // ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;무시된 초기 state를 다시 생성하지 않으려면 &lt;code&gt;useState&lt;/code&gt;에 함수 컴포넌트를 전달할 수 있다.&lt;/li&gt;
&lt;li&gt;React는 첫 번째 렌더링 중에만 함수 컴포넌트를 호출한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;useRef() 초깃값을 다시 작성하고 싶지 않을 때&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;예를 들어 명령형 class 인스턴스가 한 번만 생성되도록 하고 싶다면&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;function Image(props) {
// ⚠️ IntersectionObserver는 모든 렌더링에서 생성됩니다
const ref = useRef(new IntersectionObserver(onIntersect));
// ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;useRef&lt;/code&gt; 는 &lt;code&gt;useState&lt;/code&gt;와 같은 특수 함수 컴포넌트 오버로드를 허용하지 않는다. 대신 느리게 생성하고 설정하는 자체 함수 컴포넌트를 작성할 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;function Image(props) {
const ref = useRef(null);

// ✅ IntersectionObserver는 한 번 느리게 생성됩니다
function getObserver() {
  if (ref.current === null) {
    ref.current = new IntersectionObserver(onIntersect);
  }
  return ref.current;
}

// 필요할 때 getObserver()를 호출해주세요
// ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;이렇게 하면 처음에 진정으로 필요할 때까지는 값비싼 개체를 만들지 않아도 된다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>React</category>
      <author>Alexim</author>
      <guid isPermaLink="true">https://alexim.tistory.com/44</guid>
      <comments>https://alexim.tistory.com/44#entry44comment</comments>
      <pubDate>Tue, 6 Sep 2022 17:36:21 +0900</pubDate>
    </item>
    <item>
      <title>[React] 공식문서 주요 개념 10 ~ 12, HOOK 1 ~ 3정리</title>
      <link>https://alexim.tistory.com/43</link>
      <description>&lt;h1&gt;State 끌어올리기&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;state는 렌더링에 그 값을 필요로 하는 컴포넌트에 먼저 추가된다. 그러고 나서 다른 컴포넌트도 역시 그 값이 필요하게 되면 그 값을 그들의 가장 가까운 공통 조상으로 끌어올리면 된다. 다른 컴포넌트 간에 존재하는 state를 동기화시키려고 노력하는 대신 하향식 데이터 흐름에 기대는 걸 추천&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;어떤 값이 props 또는 state로부터 계산될 수 있다면, 그 값을 state에 두는 걸 추천하지 x&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;합성 (Composition) vs 상속 (Inheritance)&lt;/h1&gt;
&lt;h2&gt;어떤 자식 엘리먼트가 들어올 지 예상할 수 없는 컴포넌트&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;범용적인 &amp;quot;박스&amp;quot; 역할을 하는 Sidebar 혹은 Dialog와 같은 컴포넌트에서 특히 자주 볼 수 있다.&lt;/li&gt;
&lt;li&gt;이러한 컴포넌트에서는 특수한 children prop을 사용하여 자식 엘리먼트를 출력에 그대로 전달하는 것이 좋다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;children 대신 자신만의 고유한 방식으로 전달하기&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;function SplitPane(props) {
  return (
    &amp;lt;div className=&amp;quot;SplitPane&amp;quot;&amp;gt;
      &amp;lt;div className=&amp;quot;SplitPane-left&amp;quot;&amp;gt;
        {props.left}
      &amp;lt;/div&amp;gt;
      &amp;lt;div className=&amp;quot;SplitPane-right&amp;quot;&amp;gt;
        {props.right}
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

function App() {
  return (
    &amp;lt;SplitPane
      left={
        &amp;lt;Contacts /&amp;gt;
      }
      right={
        &amp;lt;Chat /&amp;gt;
      } /&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;Contacts /&amp;gt;&lt;/code&gt;와 &lt;code&gt;&amp;lt;Chat /&amp;gt;&lt;/code&gt; 같은 React 엘리먼트는 단지 객체이기 때문에 다른 데이터 처럼 prop으로 전달할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;React로 사고하기&lt;/h1&gt;
&lt;h2&gt;목업으로 시작하기&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;UI를 컴포넌트 계층 구조로 나누기&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;모든 컴포넌트 주변에 박스를 그리고 각각에 이름을 붙이기&lt;/li&gt;
&lt;li&gt;단일 책임 원칙!&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;React로 정적인 버전 만들기&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;정적인 버전을 만들기 위해 state를 사용하지 x&lt;/li&gt;
&lt;li&gt;state는 오직 상호작용을 위해, 즉 시간이 지남에 따라 데이터가 바뀌는 것에 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;UI state에 대한 최소한의 표현 찾아내기&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;애플리케이션을 올바르게 만들기 위해서는 애플리케이션에서 필요로 하는 변경 가능한 state의 최소 집합을 생각해보아야 한다.&lt;/li&gt;
&lt;li&gt;핵심은 &lt;strong&gt;중복배제원칙&lt;/strong&gt; &lt;/li&gt;
&lt;li&gt;애플리케이션이 필요로 하는 가장 최소한의 state를 찾기&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;State가 어디에 있어야 할 지 찾기&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;state를 기반으로 렌더링하는 모든 컴포넌트 찾기&lt;/li&gt;
&lt;li&gt;공통 소유 컴포넌트 찾기&lt;/li&gt;
&lt;li&gt;공통 혹은 더 상위에 있는 컴포넌트가 state를 가져야 한다.&lt;/li&gt;
&lt;li&gt;state를 소유할 적절한 컴포넌트를 찾지 못했다면 state를 소유하는 컴포넌트를 하나 만들어서 공통 소유 컴포넌트의 상위 계층에 추가하기&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;역방향 데이터 흐름 추가하기&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;리액트는 전통적인 양방향 데이터 바인딩과 비교하면 더 많은 타이핑을 필요로 하지만 데이터 흐름을 명시적으로 보이게 만들어서 프로그램이 어떻게 동작하는지 파악할 수 있게 도와준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h1&gt;Hook의 개요&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;Hook을 사용하면 컴포넌트로부터 상태 관련 로직을 추상화할 수 있다. Hook 이전에는 render props나 고차 컴포넌트와 같은 패턴을 통해 재사용 가능한 로직을 붙이는 문제를 해결해왔다. 그러나 이런 패턴의 사용은 컴포넌트의 재구성을 강요하며 코드의 추적을 어렵게 만든다.&lt;/li&gt;
&lt;li&gt;Hook은 class 안에서는 동작하지 않는다. 대신 class 없이 React를 사용할 수 있게 해주는 것&lt;/li&gt;
&lt;li&gt;Hook은 함수 컴포넌트에서 React state와 생명주기 기능을 &amp;quot;연동(hook into)&amp;quot; 할 수 있게 해주는 함수&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Effect Hook&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;side effects : 다른 컴포넌트에 영향을 줄 수도 있고, 렌더링 과정에서는 구현할 수 없는 작업&lt;/li&gt;
&lt;li&gt;함수 컴포넌트 내에서 이런 side effects를 수행할 수 있게 해준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Hook 사용 규칙&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;최상위에서만 Hook을 호출해야 한다. 반복문, 조건문, 중첩된 함수 내에서 실행하지 않기&lt;/li&gt;
&lt;li&gt;React 함수 컴포넌트 내에서만 Hook을 호출해야 한다. (+custom Hook)&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;useState&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;useState를 이용하여 변수를 선언하면 2개의 아이템 쌍이 들어있는 배열로 만들어진다. 첫 번째 아이템은 현재 변수를 의미하고, 두 번째 아이템은 해당 변수를 갱신해주는 함수이다. 배열 구조 분해라는 특별한 방법으로 변수를 선언해주었기 때문에 &lt;code&gt;[0]&lt;/code&gt;이나 &lt;code&gt;[1]&lt;/code&gt;로 배열에 접근하는 것은 좋지 않을 수 있다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>React</category>
      <author>Alexim</author>
      <guid isPermaLink="true">https://alexim.tistory.com/43</guid>
      <comments>https://alexim.tistory.com/43#entry43comment</comments>
      <pubDate>Mon, 5 Sep 2022 21:00:53 +0900</pubDate>
    </item>
    <item>
      <title>[React] 공식문서 주요 개념 1 ~ 9 정리</title>
      <link>https://alexim.tistory.com/42</link>
      <description>&lt;h1&gt;JSX&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;const element = &amp;lt;h1&amp;gt;Hello, world!&amp;lt;/h1&amp;gt;;&lt;/code&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JavaScript를 확장한 문법&lt;/li&gt;
&lt;li&gt;JavaScript 모든 기능이 포함&lt;/li&gt;
&lt;li&gt;React &quot;element&quot;를 생성한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;React + JSX&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;리엑트에서는 본질적으로 렌더링 로직이 UI 로직과 연결된다는 사실을 받아들인다.&lt;/li&gt;
&lt;li&gt;리엑트는 별도의 파일에 마크업과 로직을 넣어 기술을 인위적으로 분리하는 대신, 둘 다 포함하는 &quot;컴포넌트&quot; 라고 부르는 느슨하게 연결된 유닛으로 관심사를 분리한다.&lt;/li&gt;
&lt;li&gt;JSX는 HTML 보다는 JS에 가깝기 때문에 React DOM은 HTML 어트리뷰트 이름 대신 카멜케이스 규칙을 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;JSX에 표현식 포함하기&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JSX에 중괄호 안에는 유효한 모든 JS 표현식을 넣을 수 있다.&lt;/li&gt;
&lt;li&gt;JSX도 표현식이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;JSX는 객체를 표현한다.&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Babel은 JSX를 &lt;code&gt;React.createElement()&lt;/code&gt; 호출로 컴파일한다.
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;const element = (
&amp;lt;h1 className=&quot;greeting&quot;&amp;gt;
  Hello, world!
&amp;lt;/h1&amp;gt;
);&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;const element = React.createElement(
  'h1',
  {className: 'greeting'},
  'Hello, world!'
);&lt;/code&gt;&lt;/pre&gt;
&lt;ul 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;code&gt;React.createElement()&lt;/code&gt;는 버그가 없는 코드를 작성하는 데 도움이 되도록 몇 가지 검사를 수행하고 객체를 생성한다. 생성된 객체를 &quot;React Element&quot;라고 하며 화면에서 보고 싶은 것을 나타내는 표현이라 생각하면 된다. React는 이 객체를 읽어서 DOM을 구성하고 최신 상태로 유지하는 데 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;엘리먼트 렌더링&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;엘리먼트는 React 앱의 가장 작은 단위이다. 화면에 표시할 내용을 기술한다.&lt;/li&gt;
&lt;li&gt;브라우저 DOM 엘리먼트와 달리 React 엘리먼트는 일반 객체이며(plain obj) 쉽게 생성할 수 있다. React DOM은 엘리먼트와 일치하도록 DOM을 업데이트한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;엘리먼트&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;React 엘리먼트는 불변객체이다. 엘리먼트를 생성한 이후에는 해당 엘리먼트의 자식이나 속성을 변경할 수 없다.&lt;/li&gt;
&lt;li&gt;엘리먼트는 특정 시점의 UI를 보여준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;root DOM 노드&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;&amp;lt;div id=&quot;root&quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 안에 들어가는 모든 엘리먼트를 React DOM에서 관리하기 때문에 이것을 루트 DOM 노드라고 부른다.&lt;/li&gt;
&lt;li&gt;React로 구현된 애플리케이션은 일반적으로 하나의 루트 DOM 노드가 있다.&lt;/li&gt;
&lt;li&gt;React 엘리먼트를 루트 DOM 노드에 렌더링하려면 둘 다 &lt;code&gt;ReactDOM.render()&lt;/code&gt;로 전달하면 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;const element = &amp;lt;h1&amp;gt;Hello, world&amp;lt;/h1&amp;gt;;
ReactDOM.render(element, document.getElementById('root'));&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Components와 Props&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Component&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JS 함수와 유사하다.&lt;/li&gt;
&lt;li&gt;&quot;props&quot;라고 하는 임의의 입력을 받은 후, 화면에 어떻게 표시되는지를 기술하는 React 엘리먼트를 반환한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;함수 컴포넌트와 클래스 컴포넌트&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컴포넌트를 정의하는 가장 간단한 방법은 JS 함수를 작성하는 것이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;function Welcome(props) {
  return &amp;lt;h1&amp;gt;Hello, {props.name}&amp;lt;/h1&amp;gt;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 함수는 React 엘리먼트를 반환하므로 유효한 React 컴포넌트이다. 이러한 컴포넌트는 JS 함수이기 때문에 말 그대로 &quot;함수 컴포넌트&quot; 라고 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;scala&quot;&gt;&lt;code&gt;class Welcome extends React.Component {
  render() {
    return &amp;lt;h1&amp;gt;Hello, {this.props.name}&amp;lt;/h1&amp;gt;;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위 두가지는 동일한 컴포넌트이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;컴포넌트 렌더링&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;const element = &amp;lt;Welcome name=&quot;Sara&quot; /&amp;gt;;&lt;/code&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;React 엘리먼트는 사용자 정의 컴포넌트로도 나타낼 수 있다.&lt;/li&gt;
&lt;li&gt;React가 사용자 정의 컴포넌트로 작성한 엘리먼트를 발견하면 JSX 어트리뷰트와 자식을 해당 컴포넌트에 단일 객체로 전달한다. 이 객체를 props라고 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;컴포넌트 이름은 항상 대문자로 시작한다.&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;React는 소문자로 시작하는 컴포넌트를 DOM 태그로 처리한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;컴포넌트 합성&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컴포넌트는 자신의 출력에 다른 컴포넌트를 참조할 수 있다. 이는 모든 세부 단계에서 동일한 추상 컴포넌트를 사용할 수 있음을 의미한다.&lt;/li&gt;
&lt;li&gt;React앱에서는 버튼, 폼, 다이얼로그, 화면 등의 모든 것들이 흔히 컴포넌트로 표현된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;props&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;props의 이름은 사용될 문맥이 아닌 &lt;b&gt;컴포넌트 자체의 관점에서&lt;/b&gt; 짓는 것을 권장한다.&lt;/li&gt;
&lt;li&gt;props는 &lt;b&gt;읽기 전용&lt;/b&gt; 이다. (순수 함수이다.)&lt;/li&gt;
&lt;li&gt;모든 React 컴포넌트는 자신의 props를 다룰 때 반드시 순수 함수처럼 동작해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;State and Lifecycle&lt;/h1&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }

  componentDidMount() {
    this.timerID = setInterval(
      () =&amp;gt; this.tick(),
      1000
    );
  }

  componentWillUnmount() {
    clearInterval(this.timerID);
  }

  tick() {
    this.setState({
      date: new Date()
    });
  }

  render() {
    return (
      &amp;lt;div&amp;gt;
        &amp;lt;h1&amp;gt;Hello, world!&amp;lt;/h1&amp;gt;
        &amp;lt;h2&amp;gt;It is {this.state.date.toLocaleTimeString()}.&amp;lt;/h2&amp;gt;
      &amp;lt;/div&amp;gt;
    );
  }
}

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(&amp;lt;Clock /&amp;gt;);&lt;/code&gt;&lt;/pre&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;Clock /&amp;gt;&lt;/code&gt; 엘리먼트가 ReactDOM.render()로 전달되었을 때 React는 Clock 컴포넌트의 constructor를 호출한다. Clock 에서는 this.state를 초기화한다.&lt;/li&gt;
&lt;li&gt;React에서는 Clock 컴포넌트의 render() 메서드를 호출한다. 이를 통해 React는 화면에 표시되어야 할 내용을 알게 된다. 그 다음 React는 Clock의 렌더링 출력값을 일치시키기 위해 DOM을 업데이트 한다.&lt;/li&gt;
&lt;li&gt;Clock 출력값이 DOM에 삽입되면, React는 &lt;code&gt;componentDidMount()&lt;/code&gt; 생명주기 메서드를 호출한다. 그 안에서 Clock 컴포넌트는 매초 컴포넌트의 &lt;code&gt;tick()&lt;/code&gt; 메서드를 호출하기 위한 타이머를 설정하도록 브라우저에 요청한다.&lt;/li&gt;
&lt;li&gt;매초 브라우저가 tick() 메서드를 호출한다. 그 안에서 Clock 컴포넌트는 &lt;code&gt;setState()&lt;/code&gt;에 현재 시각을 포함하는 객체를 호출하면서 UI 업데이트를 진행한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;setState()&lt;/code&gt; 호출 덕분에 React는 state가 변경된 것을 인지하고 화면에 표시될 내용을 알아내기 위해 &lt;code&gt;render()&lt;/code&gt; 메서드를 다시 호출한다. 이 때 &lt;code&gt;render()&lt;/code&gt; 메서드 안의 this.state.date가 달라지고 렌더링 출력값은 업데이트된 시각을 포함한다. React는 이에 따라 DOM을 업데이트 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Clock 컴포넌트가 DOM으로부터 한 번이라도 삭제된 적이 있다면 React는 타이머를 멈추기 위해 componentWillUnmount() 생명주기 메서드를 호출한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;State를 올바르게 사용하기&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;직접 State를 수정하지 말기 (직접 수정하게 되면 변화를 알아차리기 힘들어진다.)&lt;/li&gt;
&lt;li&gt;다음 state를 계산할 때 해당 값에 의존해서는 안된다. (비동기적으로 업데이트될 수 있기 때문에)
&lt;pre class=&quot;pf&quot;&gt;&lt;code&gt;// Correct
this.setState((state, props) =&amp;gt; ({
counter: state.counter + props.increment
}));&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;이 setState는 이전 state를 첫 번째 인자로 받아들이고 업데이트가 적용된 시점의 props를 두 번째 인자로 받아들인다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;State 업데이트는 병합된다.&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;setState()&lt;/code&gt;를 호출할 때 React는 제공한 객체를 현재 state로 병합한다.&lt;/li&gt;
&lt;li&gt;병합은 얕게 이루어진다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;데이터는 아래로 흐른다.&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모든 state는 항상 특정한 컴포넌트가 소유하고 있으며 그 state로부터 파생된 UI, 데이터는 오직 트리구조에서 자신의 &quot;아래&quot;에 있는 컴포넌트에만 영향을 미친다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;이벤트 처리하기&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;React 엘리먼트에서 이벤트를 처리하는 방식은 DOM 엘리먼트에서 이벤트를 처리하는 방식과 매우 유사하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;DOM 엘리먼트에서의 이벤트 처리와 React 이벤트 처리의 차이점&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;React의 이벤트는 소문자 대신 camelCase를 사용한다.&lt;/li&gt;
&lt;li&gt;JSX를 사용하여 문자열이 아닌 함수로 이벤트 핸들러를 전달한다.&lt;/li&gt;
&lt;li&gt;React에서는 &lt;code&gt;false&lt;/code&gt;를 반환해도 기본 동작을 방지할 수 없다. 반드시 &lt;code&gt;preventDefault&lt;/code&gt;를 명시적으로 호출해야 한다.&lt;/li&gt;
&lt;li&gt;React에서는 리스너를 추가하기 위해 &lt;code&gt;addEventListener&lt;/code&gt;를 호출할 필요가 없다. 대신 엘리먼트가 처음 렌더링될 때 리스너를 제공하면 된다. (클래스 방식 컴포넌트에서는 이벤트 핸들러를 클래스의 메서드로 만드는 것이 일반적인 패턴이다.)&lt;/li&gt;
&lt;/ol&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HTML&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-js&quot;&gt;&amp;lt;button onclick=&quot;activateLasers()&quot;&amp;gt;
Activate Lasers
&amp;lt;/button&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;React&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-js&quot;&gt;&amp;lt;button onClick={activateLasers}&amp;gt;
Activate Lasers
&amp;lt;/button&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;HTML 에서 폼을 제출할 때 가지고 있는 기본 동작을 방지하기 위해 &lt;code&gt;return false&lt;/code&gt;를 사용할 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-js&quot;&gt;&amp;lt;form onsubmit=&quot;console.log('You clicked submit.'); return false&quot;&amp;gt;
&amp;lt;button type=&quot;submit&quot;&amp;gt;Submit&amp;lt;/button&amp;gt;
&amp;lt;/form&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;React에서는 다음과 같이 작성할 수 있다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;React는 &lt;b&gt;W3C명세&lt;/b&gt; 에 따라 합성 이벤트를 정의하기 때문에 브라우저 호환성에 대해 걱정할 필요가 없다.&lt;/li&gt;
&lt;li&gt;React 이벤트는 브라우저 고유 이벤트와 정확히 동일하게 동작하지는 않는다. &lt;a href=&quot;https://ko.reactjs.org/docs/events.html&quot;&gt;합성 이벤트&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-js&quot;&gt;function Form() {
function handleSubmit(e) {
  e.preventDefault();
  console.log('You clicked submit.');
}

return (
  &amp;lt;form onSubmit={handleSubmit}&amp;gt;
    &amp;lt;button type=&quot;submit&quot;&amp;gt;Submit&amp;lt;/button&amp;gt;
  &amp;lt;/form&amp;gt;
);
}&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;조건부 렌더링&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;React에서 조건부 렌더링은 JS에서의 조건 처리와 같이 동작한다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;if&lt;/code&gt;나 &lt;code&gt;조건부 연산자&lt;/code&gt;와 같은 JS 연산자를 현재 상태를 나타내는 엘리먼트를 만드는 데에 사용하면 React는 현재 상태에 맞게 UI를 업데이트 할 것이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;논리 &amp;amp;&amp;amp; 연산자로 if를 인라인으로 표현하기&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JS 논리 연산자 &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt;을 사용하면 쉽게 엘리먼트를 조건부로 넣을 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;function Mailbox(props) {
  const unreadMessages = props.unreadMessages;
  return (
    &amp;lt;div&amp;gt;
      &amp;lt;h1&amp;gt;Hello!&amp;lt;/h1&amp;gt;
      {unreadMessages.length &amp;gt; 0 &amp;amp;&amp;amp;
        &amp;lt;h2&amp;gt;
          You have {unreadMessages.length} unread messages.
        &amp;lt;/h2&amp;gt;
      }
    &amp;lt;/div&amp;gt;
  );
}

const messages = ['React', 'Re: React', 'Re:Re: React'];
ReactDOM.render(
  &amp;lt;Mailbox unreadMessages={messages} /&amp;gt;,
  document.getElementById('root')
);&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;null을 이용해서 컴포넌트가 렌더링하는 것 막기&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컴포넌트의 render 메서드로부터 &lt;code&gt;null&lt;/code&gt;을 반환하는 것은 생명주기 메서드 호출에 영향을 주지 않는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;리스트와 Key&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Key&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Key는 React가 어떤 항목을 변경, 추가 또는 삭제할지 식별하는 것을 돕는다. key는 엘리먼트에 안정적인 고유성을 부여하기 위해 배열 내부의 엘리먼트에 지정해야 한다.&lt;/li&gt;
&lt;li&gt;대부분의 경우 데이터의 ID를 key로 사용한다.&lt;/li&gt;
&lt;li&gt;React는 key를 통해 기존 트리와 이후 트리의 자식들이 일치하는지 확인한다.&lt;/li&gt;
&lt;li&gt;React는 휴리스틱 알고리즘에 의존하고 있기 때문에 휴리스틱이 기반하고 있는 가정에 부합하지 않는 경우 성능이 나빠질 수 있다.&lt;/li&gt;
&lt;li&gt;key는 반드시 변하지 않고, 예상 가능하며, 유일해야 한다. 변하는 key를 사용하면 많은 컴포넌트 인스턴스와 DOM 노드를 불필요하게 재생성하여 성능이 나빠지거나 자식 컴포넌트의 state가 유실될 수 있다.&lt;/li&gt;
&lt;li&gt;key는 형제 사이에서만 고유한 값이어야 한다. (전체 범위에서 고유할 필요는 없다.&lt;/li&gt;
&lt;li&gt;key는 react에게 힌트를 제공할 뿐 컴포넌트로 전달하지는 않는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;폼&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HTML 폼 엘리먼트는 폼 엘리먼트 자체가 내부 상태를 가지기 때문에, React의 다른 DOM 엘리먼트와 다르게 동작한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt; 제어 컴포넌트 &lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HTML에서 &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;textarea&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;select&amp;gt;&lt;/code&gt;와 같은 폼 엘리먼트는 일반적으로 사용자의 입력을 기반으로 자신의 state를 관리하고 업데이트 한다. React에서는 변경할 수 있는 staet가 일반적으로 컴포넌트의 state 속성에 유지되며 &lt;code&gt;setState()&lt;/code&gt;에 의해 업데이트된다.&lt;/li&gt;
&lt;li&gt;React state를 &lt;b&gt;신뢰 가능한 단일 출처&lt;/b&gt; 로 만들어 두 요소를 결합할 수 있다. 그러면 폼을 렌더링하는 React 컴포넌트는 폼에 발생하는 사용자 입력값을 제어한다. 이러한 방식으로 React에 의해 값이 제어되는 입력 폼 엘리먼트를 &lt;b&gt;제어 컴포넌트&lt;/b&gt; 라고 한다.&lt;/li&gt;
&lt;li&gt;input의 &lt;code&gt;value&lt;/code&gt; 어트리뷰트는 항상 &lt;code&gt;this.state.value&lt;/code&gt; 가 되고 React state는 신뢰 가능한 단일 출처가 된다.&lt;/li&gt;
&lt;li&gt;input의 onChange에 setState를 넣어 사용자가 입력할 때 보여지는 값이 업데이트 된다.&lt;/li&gt;
&lt;li&gt;제어 컴포넌트로 사용한다면, input의 값은 항상 React state에 의해 결정된다. 이렇게 하게되면 다른 UI 엘리먼트에 input의 값을 전달하거나 다른 이벤트 핸들러에서 값을 재설정할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;textarea 태그&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HTML 에서 &lt;code&gt;&amp;lt;textarea&amp;gt;&lt;/code&gt; 엘리먼트는 텍스트를 자식으로 정의한다.
&lt;pre class=&quot;applescript&quot;&gt;&lt;code&gt;&amp;lt;textarea&amp;gt;
Hello there, this is some text in a text area
&amp;lt;/textarea&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;React에서는 value 어트리뷰트를 대신 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;select 태그&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HTML 에서 &lt;code&gt;&amp;lt;select&amp;gt;&lt;/code&gt;는 드롭 다운 목록을 만든다. selected 옵션이 있다.&lt;/li&gt;
&lt;li&gt;React에서는 selected 어트리뷰트를 사용하는 대신 최상단 select 태그에 value 어트리뷰트를 사용한다. 한 곳에서 업데이트만 하면되기 때문에 제어 컴포넌트에서 사용하기 더 편리하다.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-js&quot;&gt;        &amp;lt;select value={this.state.value} onChange={this.handleChange}&amp;gt;
          &amp;lt;option value=&quot;grapefruit&quot;&amp;gt;Grapefruit&amp;lt;/option&amp;gt;
          &amp;lt;option value=&quot;lime&quot;&amp;gt;Lime&amp;lt;/option&amp;gt;
          &amp;lt;option value=&quot;coconut&quot;&amp;gt;Coconut&amp;lt;/option&amp;gt;
          &amp;lt;option value=&quot;mango&quot;&amp;gt;Mango&amp;lt;/option&amp;gt;
        &amp;lt;/select&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;select 태그에 multiple 옵션을 허용한다면 value 어트리뷰트에 배열을 전달할 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-js&quot;&gt;&amp;lt;select multiple={true} value={['B', 'C']}&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;다중 입력 제어하기 (다중 input)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;여러 &lt;code&gt;input&lt;/code&gt; 엘리먼트를 제어해야 할 때, 각 엘리먼트에 &lt;code&gt;name&lt;/code&gt; 어트리뷰트를 추가하고 &lt;code&gt;event.target.name&lt;/code&gt; 값을 통해 핸들러가 어떤 작업을 할 지 선택할 수 있게 해준다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>React</category>
      <author>Alexim</author>
      <guid isPermaLink="true">https://alexim.tistory.com/42</guid>
      <comments>https://alexim.tistory.com/42#entry42comment</comments>
      <pubDate>Sun, 4 Sep 2022 17:34:05 +0900</pubDate>
    </item>
    <item>
      <title>[Router] React Router</title>
      <link>https://alexim.tistory.com/39</link>
      <description>&lt;h1&gt;react router&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;v5에서 v6으로 업데이트되면서 많은 게 바꼈는데 기능상의 업데이트 보다는 문법이 많이 바뀜. 직관적으로 많이 바꼈다고 함. Reach Router라는 것과 합쳐져셔 많이 바꼈다고 함.&lt;/li&gt;
&lt;li&gt;문서를 볼 때 아래의 단어가 있다면 v5이다.&lt;ul&gt;
&lt;li&gt;Switch (Routes로 바꼈다.)&lt;/li&gt;
&lt;li&gt;exact (path와 정확하게 일치하는 경우에만 이동하라는 건데 v6에서 없어졌다.)&lt;/li&gt;
&lt;li&gt;params&lt;/li&gt;
&lt;li&gt;history.push or history.replay (useNavigate로 바꼈다.)&lt;/li&gt;
&lt;li&gt;history.goback() (뒤로 가는 기능으로 navigate(-1)로 쓸 수 있다. 2페이지 전: -2)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;react router는 눈속임이다. 페이지가 여러 개 있는 게 아니라 여러 개 있는 척 하는 것. (실제로는 페이지가 하나다.)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://reactrouter.com/docs/en/v6/getting-started/concepts&quot;&gt;Main Conceps&lt;/a&gt; react router에 대해 더 깊게 들어가는 개념들&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://itchallenger.tistory.com/566&quot;&gt;Main Conceps 번역&lt;/a&gt;(고맙게도 번역해놓으심)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Routers&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;앱을 브라우저의 URL에 연결해준다.&lt;/li&gt;
&lt;li&gt;앱을 연결하기 위해서는 최상위 컴포넌트를 Router로 감싸주어야 한다.&lt;/li&gt;
&lt;li&gt;Router는 최상위 컴포넌트라고 생각하면.. 될듯 합니다. 뼈대라고 보면 된다.&lt;/li&gt;
&lt;li&gt;Router 종류는 5가지가 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;BrowserRouter&lt;ul&gt;
&lt;li&gt;웹 브라우저에서 React Router를 실행하기 위한 권장 인터페이스.&lt;/li&gt;
&lt;li&gt;제일 많이 쓴다고 함.&lt;/li&gt;
&lt;li&gt;브라우저에 내장되어 있는(built-in) history stack - HTML5 history AP(pushState, replaceState and the popstate event)를 사용해서 UI를 URL과 동기화된 상태로 유지한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;HashRouter&lt;ul&gt;
&lt;li&gt;어떤 이유로 URL을 서버에 보내지 않아야 하는 웹 브라우저에서 사용하기 위한 것&lt;/li&gt;
&lt;li&gt;서버에서 읽을 수 없기 때문에 Server Side Rendering으로 설정을 백업할 수는 없다.&lt;/li&gt;
&lt;li&gt;가장 큰 특징은 주소에 해쉬(#)가 붙고 검색 엔진이 읽지 못한다는 것&lt;/li&gt;
&lt;li&gt;hash history를 지원하지 않는다.&lt;/li&gt;
&lt;li&gt;꼭 필요한 경우가 아니면 사용하지 않는 것이 좋다고 나와있음(공홈에)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;HistoryRouter&lt;/li&gt;
&lt;li&gt;MemoryRouter&lt;/li&gt;
&lt;li&gt;NativeRouter&lt;/li&gt;
&lt;li&gt;Router&lt;/li&gt;
&lt;li&gt;StaticRoute&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;용어 정리 &lt;a href=&quot;https://itchallenger.tistory.com/566&quot;&gt;https://itchallenger.tistory.com/566&lt;/a&gt; 님 블로그 참고&lt;/h2&gt;
&lt;h1&gt;Components&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;Link&lt;/li&gt;
&lt;li&gt;NavLink&lt;/li&gt;
&lt;li&gt;Navigate&lt;/li&gt;
&lt;li&gt;Outlet&lt;/li&gt;
&lt;li&gt;Route&lt;/li&gt;
&lt;li&gt;Routes&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Navigating&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;URL이 변하는 것을 navigation이라고 한다. 방법에는 두 가지가 있다.&lt;ol&gt;
&lt;li&gt;Link&lt;/li&gt;
&lt;li&gt;navigate (hook, component)&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;Link&lt;ul&gt;
&lt;li&gt;사용자가 클릭하거나 탭하여 다른 페이지로 이동할 수 있는 요소.&lt;/li&gt;
&lt;li&gt;navigation의 기본 수단.&lt;/li&gt;
&lt;li&gt;a &lt;code&gt;&amp;lt;Link&amp;gt;&lt;/code&gt;renders an accessible &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; element with a real href that points to the resource it&amp;#39;s linking to.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/&lt;/code&gt;로 시작하지 않는 상대 값은 상위 경로를 기준으로 확인된다. 즉 해당 값을 렌더링한 경로와 일치하는 URL 경로를 기반으로 빌드된다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;..&lt;/code&gt;은 터미널의 cd와 같다.&lt;/li&gt;
&lt;li&gt;with a .. behaves differently from a normal when the current URL ends with /. ignores the trailing slash, and removes one URL segment for each ... But an value handles .. differently when the current URL ends with / vs when it does not.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;navigate function&lt;ul&gt;
&lt;li&gt;이 함수는 useNavigate hook에서 반환되어 원할 때마다 URL을 변경할 수 있도록 한다.&lt;/li&gt;
&lt;li&gt;먼저 &lt;code&gt;const navigate = useNavigate();&lt;/code&gt;로 선언을 해준다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;navigate(&amp;quot;/주소&amp;quot;)&lt;/code&gt; 하면 가려는 주소로 이동할 수 있다.&lt;/li&gt;
&lt;li&gt;Link 대신 navigate를 사용할 때에는 충분한 이유가 있어야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Navigate&lt;ul&gt;
&lt;li&gt;렌더링될 때 현재 위치를 변경한다. useNavigate의 컴포넌트 wrapper이다. useNavigate와 같은 props, 인자를 가진다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Outlet&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;자식 경로 요소를 렌더링하려면 부모 경로 요소에서 &lt;code&gt;&amp;lt;Outlet&amp;gt;&lt;/code&gt;을 사용해야 한다. 이를 통해 하위 경로가 렌더링될 때 중첩된 UI가 표시된다. 부모 라우트가 정확히 일치하면 자식 인덱스 라우트를 렌더링하거나 인덱스 라우트가 없으면 아무것도 렌더링 하지 않는다. (Index Route란 부모 URL의 부모 Outlet에서 렌더링되는 Route가 없는 Child Route)&lt;/li&gt;
&lt;li&gt;react router는 v6부터 outlet이라는 컴포넌트와 함께 컴포넌트 트리의 레이아웃에 직접적으로 관여한다. 강력한 능력이래용..&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;function Dashboard() {
  return (
    &amp;lt;div&amp;gt;
      &amp;lt;h1&amp;gt;Dashboard&amp;lt;/h1&amp;gt;

      {/* This element will render either &amp;lt;DashboardMessages&amp;gt; when the URL is
          &amp;quot;/messages&amp;quot;, &amp;lt;DashboardTasks&amp;gt; at &amp;quot;/tasks&amp;quot;, or null if it is &amp;quot;/&amp;quot;
      */}
      &amp;lt;Outlet /&amp;gt; // 자식이 렌더링 될 위치
    &amp;lt;/div&amp;gt;
  );
}

function App() {
  return (
    &amp;lt;Routes&amp;gt;
      &amp;lt;Route path=&amp;quot;/&amp;quot; element={&amp;lt;Dashboard /&amp;gt;}&amp;gt; // 부모
        &amp;lt;Route
          path=&amp;quot;messages&amp;quot;
          element={&amp;lt;DashboardMessages /&amp;gt;} // 자식
        /&amp;gt;
        &amp;lt;Route path=&amp;quot;tasks&amp;quot; element={&amp;lt;DashboardTasks /&amp;gt;} /&amp;gt;
      &amp;lt;/Route&amp;gt;
    &amp;lt;/Routes&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;Routes and Route&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Routes와 Route는 현재 location을 기반으로 React Router에서 무언가를 렌더링하는 주요 방법.&lt;/li&gt;
&lt;li&gt;Route는 일종의 if statement와 같은 것이라고 생각할 수 있다. 만일 (if) path가 현재 URL과 일치한다면 그 라우트의 element를 렌더링 할 것이다.&lt;/li&gt;
&lt;li&gt;Routes는 위치가 변경될 때마다 모든 children &lt;code&gt;&amp;lt;Route&amp;gt;&lt;/code&gt; 요소를 살펴보고 가장 일치하는 항목을 찾고 UI의 해당 분기를 렌더링한다. &lt;code&gt;&amp;lt;Route&amp;gt;&lt;/code&gt; 요소는 중첩된 URL 경로에 해당하는 중첩된 UI를 나타내기 위해 중첩될 수 있다. 상위 경로는 &lt;code&gt;&amp;lt;Outlet&amp;gt;&lt;/code&gt;을 이용하여 하위 경로를 렌더링 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;&amp;lt;Routes&amp;gt;
  &amp;lt;Route path=&amp;quot;/&amp;quot; element={&amp;lt;Dashboard /&amp;gt;}&amp;gt;
    &amp;lt;Route
      path=&amp;quot;messages&amp;quot;
      element={&amp;lt;DashboardMessages /&amp;gt;}
    /&amp;gt;
    &amp;lt;Route path=&amp;quot;tasks&amp;quot; element={&amp;lt;DashboardTasks /&amp;gt;} /&amp;gt;
  &amp;lt;/Route&amp;gt;
  &amp;lt;Route path=&amp;quot;about&amp;quot; element={&amp;lt;AboutPage /&amp;gt;} /&amp;gt;
&amp;lt;/Routes&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;For example, in the following config the parent route renders an by default, so the child route will render without any surrounding UI. But the child route&amp;#39;s path is /users/:id because it still builds on its parent.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;Route path=&amp;quot;users&amp;quot;&amp;gt; &amp;lt;Route path=&amp;quot;:id&amp;quot; element={&amp;lt;UserProfile /&amp;gt;} /&amp;gt; &amp;lt;/Route&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;HOOKS&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;useHref&lt;ul&gt;
&lt;li&gt;React Router 외부에서도 주어진 위치에 연결하는 데 사용할 수 있는 URL을 반환한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;useInRouterContext&lt;ul&gt;
&lt;li&gt;만일 컴포넌트가 &lt;code&gt;&amp;lt;Router&amp;gt;&lt;/code&gt;의 context에서 렌더된다면 &amp;quot;true&amp;quot;를 반환하고 그렇지 않으면 &amp;quot;false&amp;quot;를 반환한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;useLinkClickHandler&lt;/li&gt;
&lt;li&gt;useLinkPressHandler&lt;/li&gt;
&lt;li&gt;useLocation&lt;br&gt;-현재 locaton 개체를 반환한다. 현재 위치가 변경될 때마다 일부 side effect를 수행하려는 경우에 유용할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import \* as React from &amp;#39;react&amp;#39;;  
import { useLocation } from &amp;#39;react-router-dom&amp;#39;;

function App() {  
let location = useLocation();

React.useEffect(() =&amp;gt; {  
ga(&amp;#39;send&amp;#39;, &amp;#39;pageview&amp;#39;);  
}, \[location\]);

return (  
// ...  
);  
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;객체를 반환하며 이 객체는 현재 사용자가 보고있는 페이지의 정보를 지니고 있다. 이 객체에는 다음과 같은 값들이 있다.&lt;ul&gt;
&lt;li&gt;pathname: 현재 주소의 경로 (쿼리스트링 제외)&lt;/li&gt;
&lt;li&gt;search: 맨 앞의 ? 문자 포함한 쿼리스트링 값&lt;/li&gt;
&lt;li&gt;hash: 주소의 # 문자열 뒤의 값 (주로 History API 가 지원되지 않는 구형 브라우저에서 클라이언트 라우팅을 사용할 때 쓰는 해시 라우터에서 사용합니다.)&lt;/li&gt;
&lt;li&gt;state: 페이지로 이동할때 임의로 넣을 수 있는 상태 값&lt;/li&gt;
&lt;li&gt;key: location 객체의 고유 값, 초기에는 default 이며 페이지가 변경될때마다 고유의 값이 생성됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;useMatch&lt;ul&gt;
&lt;li&gt;현재 위치를 기준으로 주어진 경로의 경로에 대한 일치 데이터를 반환한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;useNavigate&lt;ul&gt;
&lt;li&gt;예를 들어 onSubmit에서 submit 된 후 navigate(이동, 탐색)할 수 있는 함수를 반환한다.&lt;/li&gt;
&lt;li&gt;useNavigate는 양식이 제출되거나 특정 event가 발생할 때, url을 조작할 수 있는 interface를 제공한다.&lt;/li&gt;
&lt;li&gt;replace: true 일 경우 새 항목을 추가하는 대신 history stack의 현재 항목을 대체한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;useNavigationType&lt;ul&gt;
&lt;li&gt;현재 navigate 유형 또는 사용자가 현재 페이지에 어떻게 왔는지를 반환한다. history stack 에 대한 pop, push 또는 교체 작업을 통해&lt;/li&gt;
&lt;li&gt;&lt;code&gt;navigate(&amp;quot;../success&amp;quot;, { replace: true});&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;두 번째 인자로 &lt;code&gt;{ replace, state }&lt;/code&gt; 인수를 사용한다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;replace: true&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;navigate에 적힌 주소로 넘어간 후 뒤로가기를 하더라도 방금의 페이지로 돌아오지 않는다. 이 때는 자신의 메인 페이지 (&amp;quot;/&amp;quot;)로 돌아오게 됩니다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;navigate( &amp;#39;/이동경로&amp;#39;, { state: { 키: 값, 키: 값, ... } } )&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;useOutlet&lt;ul&gt;
&lt;li&gt;내부적으로 &lt;code&gt;&amp;lt;Outlet&amp;gt;&lt;/code&gt; 자식 경로를 렌더링하는 데 사용된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;useOutletContext&lt;/li&gt;
&lt;li&gt;useParams&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;Route path&amp;gt;&lt;/code&gt;와 매치되는 현재 URL에서 동적 매개변수의 키/값 쌍의 개체를 반환한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import * as React from &amp;#39;react&amp;#39;;
import { Routes, Route, useParams } from &amp;#39;react-router-dom&amp;#39;;

function ProfilePage() {
  // Get the userId param from the URL.
  let { userId } = useParams();
  // ...
}

function App() {
  return (
    &amp;lt;Routes&amp;gt;
      &amp;lt;Route path=&amp;quot;users&amp;quot;&amp;gt;
        &amp;lt;Route path=&amp;quot;:userId&amp;quot; element={&amp;lt;ProfilePage /&amp;gt;} /&amp;gt;
        &amp;lt;Route path=&amp;quot;me&amp;quot; element={...} /&amp;gt;
      &amp;lt;/Route&amp;gt;
    &amp;lt;/Routes&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;useResolvedPath&lt;ul&gt;
&lt;li&gt;This hook resolves the pathname of the location in the given to value against the pathname of the current location.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;useRoutes&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;Routes&amp;gt;&lt;/code&gt;와 기능적으로 동일하지만 js 개체를 사용하여 경로를 정의한다.&lt;/li&gt;
&lt;li&gt;반환 값은 경로 트리를 렌더링하는 데 사용할 수 있는 유효한 React 요소이거나 일치하는 항목이 없는 경우의 null 이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;useSearchParams&lt;ul&gt;
&lt;li&gt;현재 위치에 대한 URL의 쿼리 문자열을 읽고 수정하는 데 사용된다.&lt;/li&gt;
&lt;li&gt;React의 자체 useState hook처럼 useSearchParams는 현재 위치의 검색 매개 변수와 이를 업데이트하는 데 사용할 수 있는 두 가지 값의 배열을 반환한다.&lt;/li&gt;
&lt;li&gt;useSearchParams를 통해서 쿼리스트링을 쉽게 파싱할 수 있다.(키, 값이 여러개인 경우 분리시키기 쉬워졌다.)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import \* as React from &amp;quot;react&amp;quot;;  
import```js
import * as React from &amp;quot;react&amp;quot;;
import { useSearchParams } from &amp;quot;react-router-dom&amp;quot;;

function App() {
  let [searchParams, setSearchParams] = useSearchParams();

  function handleSubmit(event) {
    event.preventDefault();
    // The serialize function here would be responsible for
    // creating an object of { key: value } pairs from the
    // fields in the form that make up the query.
    let params = serializeFormQuery(event.target);
    setSearchParams(params);
  }

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;form onSubmit={handleSubmit}&amp;gt;{/* ... */}&amp;lt;/form&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Utilities&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;createRoutesFromChillden&lt;/li&gt;
&lt;li&gt;createSearchParams&lt;/li&gt;
&lt;li&gt;generatePath&lt;/li&gt;
&lt;li&gt;Location&lt;/li&gt;
&lt;li&gt;matchPath&lt;/li&gt;
&lt;li&gt;matchRoutes&lt;/li&gt;
&lt;li&gt;renderMatches&lt;/li&gt;
&lt;li&gt;resolvePath&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>React</category>
      <author>Alexim</author>
      <guid isPermaLink="true">https://alexim.tistory.com/39</guid>
      <comments>https://alexim.tistory.com/39#entry39comment</comments>
      <pubDate>Sun, 21 Aug 2022 23:23:57 +0900</pubDate>
    </item>
    <item>
      <title>__dirname과 process.crw()의 차이</title>
      <link>https://alexim.tistory.com/38</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;D:\blog\imalex\src\server 위치에서 __dirname과 process.crw()를 호출했을 때&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(imalex가 프로젝트 경로이다.)&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;dirname -&amp;gt;&amp;nbsp; D:\blog\imalex\src\server &lt;br /&gt;process.cwd() -&amp;gt; D:\blog\imalex&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;__dirname은 모듈의 파일 경로를 말한다.&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;process는 node 전역 객체를 말한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;crw()는 노드가 실행중인 위치를 반환한다.&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;즉 process.crw()는 프로젝트 안 어디서 호출하든 같은 결과를 가져온다.&lt;/p&gt;</description>
      <category>Node</category>
      <author>Alexim</author>
      <guid isPermaLink="true">https://alexim.tistory.com/38</guid>
      <comments>https://alexim.tistory.com/38#entry38comment</comments>
      <pubDate>Sat, 6 Aug 2022 13:55:12 +0900</pubDate>
    </item>
    <item>
      <title>[JS] &amp;quot;?.&amp;quot; 옵셔널 체이닝 연산자 (Optional chaining)</title>
      <link>https://alexim.tistory.com/37</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;  Optional Chaning&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;?. 앞의 평가 대상이 undefined나 null이면 평가를 멈추고 undefined를 반환한다.&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: #555555;&quot;&gt; &lt;span&gt; 언제 사용하나?&lt;/span&gt;&lt;/span&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;옵셔널 체이닝 연산자가 없을 때는 객체에 속성이 있는지 확인하기 위해서 &quot;&amp;amp;&amp;amp;&quot; 연산자를 썼다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1659537014515&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let user = {};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;user 객체 안에서 user.address.street 을 조회하여야 하는데 주소 정보가 없는 user가 있다고 할 때&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;pre id=&quot;code_1659537021280&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;console.log(user &amp;amp;&amp;amp; user.address &amp;amp;&amp;amp; user.address.street);&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;/p&gt;
&lt;pre id=&quot;code_1659537033590&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;console.log(user?.address?.street);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 접근할 수 있게되었다. 옵셔널 체이닝으로 접근하면 타입에러가 나지 않고 값이 없는 경우에는 undefined를 반환한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&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;나의 경우 api 값을 불러올 때 사용했다. (튜토리얼 보는중..)&lt;/p&gt;
&lt;pre id=&quot;code_1659537545477&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;        &amp;lt;img
          src={channelIcon?.url} // ? 이 물음표 뭐지
          alt='channel img'
        /&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;channelIcon이 api에서 불러온 값이고 값이 없을 경우를 방지하기 위해서 옵셔널 체이닝을 사용한 것 같다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(튜토리얼에서 저 물음표를 봤을 때 오타인줄ㅎㅎ)&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 존재하지 않을 수 있는 메서드를 호출할 때 (함수의 호출)&lt;/p&gt;
&lt;pre id=&quot;code_1659537327583&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let result = someInterface.customMethod?.();&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;옵셔널 체이닝은 ?. 이전 부분만 확인하기 때문에 저 예제의 경우 someInterface 자체는 null이나 undefined가 아니어야 한다. 만약 null 또는 undefined 값이 나올 수 있는 경우라면&lt;/p&gt;
&lt;pre id=&quot;code_1659537456592&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;someInterface?.customMethod?.();&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ko.javascript.info/optional-chaining&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://ko.javascript.info/optional-chaining&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1659537797845&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;옵셔널 체이닝 '?.'&quot; data-og-description=&quot;&quot; data-og-host=&quot;ko.javascript.info&quot; data-og-source-url=&quot;https://ko.javascript.info/optional-chaining&quot; data-og-url=&quot;https://ko.javascript.info/optional-chaining&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bB3i6x/hyPjltllhg/AXx44ldfBJpZEA1tfHHbKK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/eiOQvP/hyPjgr1fxh/eerLSqqwjZL5w19Sbp3gV0/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512&quot;&gt;&lt;a href=&quot;https://ko.javascript.info/optional-chaining&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://ko.javascript.info/optional-chaining&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bB3i6x/hyPjltllhg/AXx44ldfBJpZEA1tfHHbKK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/eiOQvP/hyPjgr1fxh/eerLSqqwjZL5w19Sbp3gV0/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512');&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;옵셔널 체이닝 '?.'&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;ko.javascript.info&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/Optional_chaining&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/Optional_chaining&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1659537804130&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Optional chaining - JavaScript | MDN&quot; data-og-description=&quot;optional chaining 연산자&amp;nbsp;(?.) 는 체인의 각 참조가 유효한지 명시적으로 검증하지 않고, 연결된 객체 체인 내에 깊숙이 위치한 속성 값을 읽을 수 있다.&quot; data-og-host=&quot;developer.mozilla.org&quot; data-og-source-url=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/Optional_chaining&quot; data-og-url=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/Optional_chaining&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ctqM2o/hyPjf0XUaX/kfaAf3n4h5ekoNZAHgdT9K/img.png?width=1920&amp;amp;height=1080&amp;amp;face=0_0_1920_1080&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/Optional_chaining&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/Optional_chaining&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ctqM2o/hyPjf0XUaX/kfaAf3n4h5ekoNZAHgdT9K/img.png?width=1920&amp;amp;height=1080&amp;amp;face=0_0_1920_1080');&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;Optional chaining - JavaScript | MDN&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;optional chaining 연산자&amp;nbsp;(?.) 는 체인의 각 참조가 유효한지 명시적으로 검증하지 않고, 연결된 객체 체인 내에 깊숙이 위치한 속성 값을 읽을 수 있다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developer.mozilla.org&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;</description>
      <category>Javascript</category>
      <author>Alexim</author>
      <guid isPermaLink="true">https://alexim.tistory.com/37</guid>
      <comments>https://alexim.tistory.com/37#entry37comment</comments>
      <pubDate>Wed, 3 Aug 2022 23:42:19 +0900</pubDate>
    </item>
    <item>
      <title>[알고리즘] Leetcode. Remove Nth Node From End of List</title>
      <link>https://alexim.tistory.com/35</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Given the&lt;span&gt;&amp;nbsp;&lt;/span&gt;head&lt;span&gt;&amp;nbsp;&lt;/span&gt;of a linked list, remove the&lt;span&gt;&amp;nbsp;&lt;/span&gt;nth&lt;span&gt;&amp;nbsp;&lt;/span&gt;node from the end of the list and return its head.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연결리스트 head과 n이 주어지고 끝에서 n번째 노드를 삭제하고 head를 return 하라&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;Example 1:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;542&quot; data-origin-height=&quot;222&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7R84s/btrISO9ECSO/f6BIA7EJgGGW3y88o1gCn0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7R84s/btrISO9ECSO/f6BIA7EJgGGW3y88o1gCn0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7R84s/btrISO9ECSO/f6BIA7EJgGGW3y88o1gCn0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7R84s%2FbtrISO9ECSO%2Ff6BIA7EJgGGW3y88o1gCn0%2Fimg.jpg&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;542&quot; height=&quot;222&quot; data-origin-width=&quot;542&quot; data-origin-height=&quot;222&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;방법 1.&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;2개의 포인터가 필요함. p1(포인터1)은 head부터 시작, p2는 head.next부터 시작&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리스트 길이를 계산하고 (리스트 길이 - n) 만큼 이동해&amp;nbsp; p1.next는 지울 노드가 되고 p2는 지울 노드를 가리킨다.&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;1. n이 length와 같을 때&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;: 이 경우에는 p1 head 자체를 지워야한다.&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;2. length가 1일 때&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;: 위 첫 번째 케이스와 같은 케이스로 처리할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1659503120627&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var removeNthFromEnd = function(head, n) {
    let temp = head;
    let p1 = head.next;
    let p2 = head;
    let length = 0;

    while (temp.next) {
        length++;
        temp = temp.next;
    }
    
    // 만약 n이 node의 length와 길이가 같다면 head를 삭제
    if (length === n - 1) {
        head = head.next;
        return head;
    }

    for (let i = 0; i &amp;lt; (length - n); i++) {
        p1 = p1.next;
        p2 = p2.next;
    }

    p2.next = p1.next;
    
    return head;
};&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;방법 2.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;dummy를 사용하면 코너 케이스를 쉽게 해결할 수 있다고 한다. ( )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;head를 복사할 때 dummy = head 이렇게 하는 게 아니라 dummy.next = head 이렇게 하면 length가 1일 때 케이스를 생각하지 않아도 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1659503641459&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var removeNthFromEnd = function(head, n) {
    const dummy = new ListNode();
    dummy.next = head;
    let p1 = dummy;
    let p2 = dummy;
    
    for (let i = 0; i &amp;lt; n; i++) {
        p1 = p1.next;
    }
    
    while (p1.next) {
        p1 = p1.next;
        p2 = p2.next;
    }
    
    p2.next = p2.next.next;
    
    return dummy.next; 
}&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;만약 length = 5, n = 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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;p1을 n만큼 옮겨간다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  초록색 위치에 p1이 위치해있다.&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;p1, p2를 p1의 next가 null이 될 때까지 이동하면 2번을 이동하게 되는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  p2의 next 노드가 지워야 할 노드의 위치가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;p2.next( ) = p2.next.next ( )&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; &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;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;방법 3.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;dummy를 쓰지 않는 방법&lt;/p&gt;
&lt;pre id=&quot;code_1659504415775&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var removeNthFromEnd = function (head, n) {
    // Two pointers - fast and slow
    let slow = head;
    let fast = head;
    // Move fast pointer n steps ahead
    for (let i = 0; i &amp;lt; n; i++) {
        if (fast.next === null) {
            // If n is equal to the number of nodes, delete the head node
            if (i === n - 1) {
                head = head.next;
            }
            return head;
        }
        fast = fast.next;
    }
    // Loop until we reach to the end.
    // Now we will move both fast and slow pointers
    while (fast.next !== null) {
        slow = slow.next;
        fast = fast.next;
    }
    // Delink the nth node from last
    if (slow.next !== null) {
        slow.next = slow.next.next;
    }
    return head;
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;방법 2에서 dummy를 사용하면 다른 케이스를 생각하지 않아도 돼서 좋지만 공간을 더 사용한다는 단점이 있는데 그걸 보완해준 방법인 것 같다.&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;style6&quot; /&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;&lt;a href=&quot;https://www.fwantastic.com/2021/01/leetcode-19-remove-nth-node-from-end-of.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.fwantastic.com/2021/01/leetcode-19-remove-nth-node-from-end-of.html&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1659504473530&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;[Leetcode] #19. Remove Nth Node From End of List 뒤에서 N번째 노드 지우기&quot; data-og-description=&quot; &quot; data-og-host=&quot;www.fwantastic.com&quot; data-og-source-url=&quot;https://www.fwantastic.com/2021/01/leetcode-19-remove-nth-node-from-end-of.html&quot; data-og-url=&quot;https://www.fwantastic.com/2021/01/leetcode-19-remove-nth-node-from-end-of.html&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://www.fwantastic.com/2021/01/leetcode-19-remove-nth-node-from-end-of.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.fwantastic.com/2021/01/leetcode-19-remove-nth-node-from-end-of.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&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;[Leetcode] #19. Remove Nth Node From End of List 뒤에서 N번째 노드 지우기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.fwantastic.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://redquark.org/leetcode/0019-remove-nth-node/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://redquark.org/leetcode/0019-remove-nth-node/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1659504477051&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;LeetCode #19 - Remove Nth Node From End Of List&quot; data-og-description=&quot;Hello LeetCode enthusiasts  ! It&amp;rsquo;s time to look the nineteenth problem from LeetCode. Remove Nth Node From End Of List Problem Statement Given the head of a linked list, remove the nth node from the end of the list and return its head. Follow up: Coul&quot; data-og-host=&quot;redquark.org&quot; data-og-source-url=&quot;https://redquark.org/leetcode/0019-remove-nth-node/&quot; data-og-url=&quot;https://redquark.org/leetcode/0019-remove-nth-node/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bb6nOG/hyPjmZwxgs/6bjCJqkpc0dKgVZgIxYGL0/img.jpg?width=542&amp;amp;height=222&amp;amp;face=0_0_542_222&quot;&gt;&lt;a href=&quot;https://redquark.org/leetcode/0019-remove-nth-node/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://redquark.org/leetcode/0019-remove-nth-node/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bb6nOG/hyPjmZwxgs/6bjCJqkpc0dKgVZgIxYGL0/img.jpg?width=542&amp;amp;height=222&amp;amp;face=0_0_542_222');&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;LeetCode #19 - Remove Nth Node From End Of List&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Hello LeetCode enthusiasts  ! It&amp;rsquo;s time to look the nineteenth problem from LeetCode. Remove Nth Node From End Of List Problem Statement Given the head of a linked list, remove the nth node from the end of the list and return its head. Follow up: Coul&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;redquark.org&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;</description>
      <category>알고리즘, 자료구조</category>
      <author>Alexim</author>
      <guid isPermaLink="true">https://alexim.tistory.com/35</guid>
      <comments>https://alexim.tistory.com/35#entry35comment</comments>
      <pubDate>Wed, 3 Aug 2022 14:19:30 +0900</pubDate>
    </item>
    <item>
      <title>[알고리즘] Leetcode. Intersection of Two Linked Lists</title>
      <link>https://alexim.tistory.com/34</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Given the heads of two singly linked-lists&lt;span&gt;&amp;nbsp;&lt;/span&gt;headA&lt;span&gt;&amp;nbsp;&lt;/span&gt;and&lt;span&gt;&amp;nbsp;&lt;/span&gt;headB, return&lt;span&gt;&amp;nbsp;&lt;/span&gt;the node at which the two lists intersect. If the two linked lists have no intersection at all, return&lt;span&gt;&amp;nbsp;&lt;/span&gt;null.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;For example, the following two linked lists begin to intersect at node&lt;span&gt;&amp;nbsp;&lt;/span&gt;c1:&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;742&quot; data-origin-height=&quot;241&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cG04hm/btrIMBjaBqO/ZYlwEWBDlFkUC87rotqFS1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cG04hm/btrIMBjaBqO/ZYlwEWBDlFkUC87rotqFS1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cG04hm/btrIMBjaBqO/ZYlwEWBDlFkUC87rotqFS1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcG04hm%2FbtrIMBjaBqO%2FZYlwEWBDlFkUC87rotqFS1%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;742&quot; height=&quot;241&quot; data-origin-width=&quot;742&quot; data-origin-height=&quot;241&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;The test cases are generated such that there are no cycles anywhere in the entire linked structure.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Note&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;that the linked lists must&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;retain their original structure&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;after the function returns.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Custom Judge:&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;The inputs to the&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;judge&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;are given as follows (your program is&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;not&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;given these inputs):&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;intersectVal&lt;span&gt;&amp;nbsp;&lt;/span&gt;- The value of the node where the intersection occurs. This is&lt;span&gt;&amp;nbsp;&lt;/span&gt;0&lt;span&gt;&amp;nbsp;&lt;/span&gt;if there is no intersected node.&lt;/li&gt;
&lt;li&gt;listA&lt;span&gt;&amp;nbsp;&lt;/span&gt;- The first linked list.&lt;/li&gt;
&lt;li&gt;listB&lt;span&gt;&amp;nbsp;&lt;/span&gt;- The second linked list.&lt;/li&gt;
&lt;li&gt;skipA&lt;span&gt;&amp;nbsp;&lt;/span&gt;- The number of nodes to skip ahead in&lt;span&gt;&amp;nbsp;&lt;/span&gt;listA&lt;span&gt;&amp;nbsp;&lt;/span&gt;(starting from the head) to get to the intersected node.&lt;/li&gt;
&lt;li&gt;skipB&lt;span&gt;&amp;nbsp;&lt;/span&gt;- The number of nodes to skip ahead in&lt;span&gt;&amp;nbsp;&lt;/span&gt;listB&lt;span&gt;&amp;nbsp;&lt;/span&gt;(starting from the head) to get to the intersected node.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;The judge will then create the linked structure based on these inputs and pass the two heads,&lt;span&gt;&amp;nbsp;&lt;/span&gt;headA&lt;span&gt;&amp;nbsp;&lt;/span&gt;and&lt;span&gt;&amp;nbsp;&lt;/span&gt;headB&amp;nbsp;to your program. If you correctly return the intersected node, then your solution will be&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;accepted&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;cycle이 없는 두 개의 linked list가 있고 두 리스트가 교차점이 있다면 그 교차점을 반환하고 없다면 null을 반환하는 문제&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런식으로 모두 다 순회해야 하는 알고리즘을 &lt;b&gt;Brute Force 알고리즘&lt;/b&gt;이라고 부르는 것 같다. 무식한 힘이라는 뜻..?&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;장점으로는 오차 없이 계산할 수 있는 게 장점이라고 한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음 생각한 방법&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. headA, headB 길이를 구하고 길이가 더 긴 리스트의 앞부분을 자르고 길이를 똑같이 만든 후 비교하기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1659453143983&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var getLength = function(head) {
    let length = 0;
    while (head.next) {
        head = head.next;
        length++;
    }
    return length;
}

var getIntersectionNode = function(headA, headB) {
    const lengthA = getLength(headA);
    const lengthB = getLength(headB);
    let long;
    let short;

    for (let i = 0; i &amp;lt; Math.abs(lengthA - lengthB); i++) {
        if (lengthA &amp;gt; lengthB) {
            headA = headA.next;
        } else {
            headB = headB.next;
        }
    }
    
    while (headA !== headB) {
        if (!headA.next) return null;
        
        headA = headA.next;
        headB = headB.next;
    }
    return headA;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;2. 각 리스트를 순회하고 null에 다다랐을 때 다른 리스트로 이어서 순회하여 각각 비교하기&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;742&quot; data-origin-height=&quot;241&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/czXE4F/btrIITqPDi2/qHxuceJTrQWk0kmZljqxf1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/czXE4F/btrIITqPDi2/qHxuceJTrQWk0kmZljqxf1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/czXE4F/btrIITqPDi2/qHxuceJTrQWk0kmZljqxf1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FczXE4F%2FbtrIITqPDi2%2FqHxuceJTrQWk0kmZljqxf1%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;742&quot; height=&quot;241&quot; data-origin-width=&quot;742&quot; data-origin-height=&quot;241&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;A : 4 -&amp;gt; 1 -&amp;gt; 8 -&amp;gt; 4 -&amp;gt; 5 (마지막) B로 바꿈 -&amp;gt; 5 -&amp;gt; 6 -&amp;gt; 1 -&amp;gt; 8 -&amp;gt; 4 -&amp;gt; 5&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;B : 5 -&amp;gt; 6 -&amp;gt; 1 -&amp;gt; 8 -&amp;gt; 4 -&amp;gt; 5 &lt;span&gt;(마지막) A로 바꿈&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;-&amp;gt; 4 -&amp;gt; 1 -&amp;gt; 8 -&amp;gt; 4 -&amp;gt; 5&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;pre id=&quot;code_1659454568693&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var getIntersectionNode = function(headA, headB) {
    if (!headA || !headB) return null;

    let a = headA;
    let b = headB;
    let numA = 0;
    let numB = 0;
    
    while (a !== b) {
        if (a.next === null) {
            if (numA &amp;gt; 1) return null;
            numA++;
            a = headB;
        } else {
            a = a.next;
        }
        if (b.next === null) {
            if (numB &amp;gt; 1) return null;
            numB++;
            b = headA;
        } else {
            b = b.next;
        }
    }
    
    return a;
};&lt;/code&gt;&lt;/pre&gt;</description>
      <category>알고리즘, 자료구조</category>
      <author>Alexim</author>
      <guid isPermaLink="true">https://alexim.tistory.com/34</guid>
      <comments>https://alexim.tistory.com/34#entry34comment</comments>
      <pubDate>Wed, 3 Aug 2022 00:36:35 +0900</pubDate>
    </item>
  </channel>
</rss>