반응형

1. 컴포넌트 기반 아키텍처

React는 UI를 독립적이고 재사용 가능한 컴포넌트로 나누어 개발할 수 있습니다. 이렇게 나누어진 컴포넌트는 서로 독립적으로 관리되며, 부모-자식 관계로 데이터를 주고받습니다.

예제: 컴포넌트 분리

const Button =({ label, onClick })=> {
  return (
    <button onClick={onClick}>
      {label}
    </button>
  );
}
function App() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <h1>Count: {count}</h1>
      <Button label="Increment" onClick={() => setCount(count + 1)} />
      <Button label="Decrement" onClick={() => setCount(count - 1)} />
    </div>
  );
}
  • App 컴포넌트는 Button 컴포넌트를 사용해 label, onClick props를 전달 후, 생성한다.
  • Button 컴포넌트는 서로 다른 버튼이지만 하나의 컴포넌트 코드로 재사용할 수 있다.

2. Virtual DOM을 활용한 고성능 렌더링

React는 Virtual DOM을 사용하여 변경 사항을 추적하고, 실제 DOM 조작을 최소화하여 성능을 최적화한다.

예제: Virtual DOM에서의 렌더링 비교

import React, { useState } from 'react';

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

  console.log('Rendered with count:', count); // Virtual DOM에서 변경 사항 확인

  return (
    <div>
      <h1>Count: {count}</h1>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}

export default Counter;

설명:

  • 상태 변경 시 Virtual DOM에서 새 상태를 반영한 컴포넌트를 생성하고, 이전 Virtual DOM과 비교.
  • 변경된 부분만 실제 DOM에 업데이트하므로 성능이 최적화.
  • 브라우저 콘솔에서 상태 변경 시마다 컴포넌트가 다시 렌더링되는 것을 확인 가.

3. 단방향 데이터 흐름

React는 상위 컴포넌트에서 하위 컴포넌트로만 데이터를 전달합니다. 이를 통해 데이터 흐름이 명확해지고 관리가 쉬워집니다.

예제: 부모-자식 간 데이터 전달

// Child.js: 하위 컴포넌트
import React from 'react';

function Child({ message }) {
  return <h2>{message}</h2>;
}

export default Child;

// App.js: 상위 컴포넌트
import React, { useState } from 'react';
import Child from './Child';

function App() {
  const [message, setMessage] = useState('Hello, React!');

  return (
    <div>
      <Child message={message} />
      <button onClick={() => setMessage('Data Flow Updated!')}>
        Update Message
      </button>
    </div>
  );
}

export default App;

설명:

  • App 컴포넌트가 Child 컴포넌트로 message를 전달한다.
  • 단방향 데이터 흐름으로 인해, 데이터는 항상 부모에서 자식으로만 흐릅니다.
  • Child 컴포넌트로 넘어온 message를 변경하고 싶다면, 부모의 setMessage 를 props로 받아와 실행하면된다.

React의 단점

단점 1: 초기 로딩 시간 해결 (코드 스플리팅)

React 애플리케이션은 초기 로딩 시간 증가 문제가 있지만, 코드 스플리팅을 통해 이를 해결할 수 있습니다.

예제: React의 코드 스플리팅

import React, { Suspense, lazy } from 'react';

const HeavyComponent = lazy(() => import('./HeavyComponent'));

function App() {
  return (
    <div>
      <h1>Welcome to My App</h1>
      <Suspense fallback={<div>Loading...</div>}>
        <HeavyComponent />
      </Suspense>
    </div>
  );
}

export default App;

설명:

  • lazy 를 통해 HeavyComponent는 사용될 때만 로드된다.
  • Suspense를 사용하여 로드 중인 상태를 처리할 수 있다.
  • 이를 통해 초기 로딩 시간을 줄이고 성능을 개선할 수 있다.

단점 2: SEO 문제 해결 1(ReactDOMServer)

리액트의 ReactDOMServer 라이브러리를 통해 SSR을 직접 구현.

import express from 'express';
import React from 'react';
import ReactDOMServer from 'react-dom/server';
import App from './App';

const app = express();

app.get('*', (req, res) => {
  const appHtml = ReactDOMServer.renderToString(<App />);
  const html = `
    <!DOCTYPE html>
    <html>
      <head><title>React SSR</title></head>
      <body>
        <div id="root">${appHtml}</div>
        <script src="/bundle.js"></script>
      </body>
    </html>
  `;
  res.send(html);
});

app.listen(3000, () => console.log('Server is running on http://localhost:3000'));
  • 서버에서 리액트 컴포넌트를 해석하는 라이브러리 ReactDOMServer 을 이용해 HTML 파일로 변경한다.

단점 2: SEO 문제 해결 2(Next.js 활용)

CSR 방식에서 발생하는 SEO 문제는 Next.js를 사용하여 서버 사이드 렌더링(SSR)을 도입함으로써 해결 가능합니다.

예제: Next.js에서 SSR 사용

// pages/index.js
import React from 'react';

export default function Home({ message }) {
  return (
    <div>
      <h1>{message}</h1>
    </div>
  );
}

export async function getServerSideProps() {
  return {
    props: {
      message: 'This page is rendered on the server!',
    },
  };
}

설명:

  • getServerSideProps를 사용해 서버에서 데이터를 가져와 페이지를 렌더링한다.
  • HTML 콘텐츠가 완전히 생성되어 클라이언트에 전달되므로 SEO와 초기 로딩 문제를 동시에 해결할 수 있다.

반응형

'Web > React' 카테고리의 다른 글

[React] useMemo, useEffect 에러 (인 줄 알았던 휴먼에러)  (0) 2025.03.23
[React] useRef, useMemo, useCallback  (1) 2024.12.13
React 번들링  (1) 2024.12.01
반응형

프론트엔드 개발자는 가끔 자바스크립트로 문제를 풀어야한다. 하지만, 애처롭게도 c++에는 내장 라이브러리로 존재하는 binary_search, lower_bound, upper_bound가 존재하지 않느다. 따라서, 우리는 이분탐색을 "직접" 만들어야한다. 이분탐색에 대해 알아보자

 

Binary Search

const binarySearch =(arr, target)=>{
    let left = 0;
    let right = arr.length - 1;

    while(left <= right){
        let mid = Math.floor((left+right)/2);

        if(arr[mid] === target){
            return mid;
        }else if(arr[mid] < target){
            left = mid + 1;
        }else{
            right = mid - 1;
        }
    }

    return -1;
}

 

Lower Bound

const lowerBound =(arr, target)=>{
    let left = 0;
    let right = arr.length - 1;

    while(left < right){
        let mid = Math.floor((left+right)/2);

        if(arr[mid] < target){
            left = mid + 1;
        }else{
            right = mid;
        }
    }
    return left;
}
  • lower bound 는 배열에서 타겟값 이상이 처음으로 나타나는 위치를 찾는다.
  • 이분탐색 하다가 target 값 이상인 left 값이 타겟값을 넘는 첫 위치다.

Upper  Bound

const upperBound =(arr, target)=>{
    let left = 0;
    let right = arr.length - 1;

    while(left < right){
        let mid = Math.floor((left+right)/2);

        if(arr[mid] <= target){
            left = mid + 1;
        }else{
            right = mid;
        }
    }
    return left;
}
  • upper bound 는 배열에서 타겟값보다 큰 값이 나타나는 첫 위치를 찾는다.
  • 타겟값을 초과하는 인덱스를 반환한다.

이분탐색 vs lower, upper

  • 이분탐색은 탐색값을 찾는것 이므로 while의 조건이 left<=right다.
  • lower, upper 는 탐색값의 바운더리를 찾는 것 이므로 while의 조건이 left < right다.
반응형

'Language > Javascript' 카테고리의 다른 글

코딩테스트를 위한 PriorityQueue  (1) 2024.10.31
[JS] 프로토타입  (0) 2024.09.29
반응형

프론트엔드 개발자는 가끔 자바스크립트로 문제를 풀어야한다. 하지만, 애처롭게도 흔하디 흔한 우선순위큐는 내장되어있지 않다. 따라서, 우리는 우선수위큐를 "직접" 만들어야한다. 우선순위큐에 대해 알아보자

우선순위 큐

생성자

constructor(){
    this.heap = [];
}
  • heap 배열을 초기화하는 생성자다.

삽입 enqueue

  enqueue(value){
    this.heap.push(value);
    this._heapifyUp();
  }
  • heap 배열에 value를 push하고 힙정렬을 진행한다.

삭제 dequeue

dequeue(){
    const min = this.heap[0];
    const end = this.heap.pop();

    if(this.heap.length > 0){
      this.heap[0] = end;
      this._heapifyDown();
    }

    return min;
}
  • 삭제하려는 값은 맨위의 최소값이므로 (현재 코드는 최소힙을 기준으로 작성) 0번째 인덱스와 마지막인덱스를 교환한다.
  • 다시 힙정렬을 진행한다.

heapifyUp() 위쪽으로 재정렬

_heapifyUp() {
    let index = this.heap.length -1;
    const element = this.heap[index];

    while(index > 0){
       //우선순위큐는 이진트리를 기반으로 하기때문에 
       //parentIndex 는 자식 노드의 인덱스에 절반과 비슷하다.
      const parentIndex = Math.floor((index - 1) /2 );
      const parent = this.heap[parentIndex];
        //부모보다 크기때문에 최소힙 성립
      if(element >= parent) break;
        //그렇지 않으면 부모와 자리바꾸기
      this.heap[index] = parent;
      index = parentIndex;
    }
    this.heap[index] = element;
 }
  • 값을 삽입하면 오름차순으로 정렬해야한다. (삽입한 값이 맨뒤에 있다.)
  • 삽입된 위치(index) 값부터 (heap 배열에 push 했으므로 맨끝값) 부모 노드를 탐색하면서 바꿀 값을 찾는다.

heapifyDown() 아래쪽으로 재정렬

_heapifyDown(){
    let index = 0;
    const length = this.heap.length;
    const element = this.heap[0];

    while(true){
    //자식 인덱스를 확인
      let leftChildIndex = 2 * index + 1;
      let rightChildIndex = 2 * index + 2;
      let swapIndex = null;
    //왼쪽자식부터 부모가 더 크다면 바꿔야할 인덱스로 판명
      if(leftChildIndex < length){
        if(this.heap[leftChildIndex] < element){
          swapIndex = leftChildIndex;
        }
      }
    //오른쪽자식
      if(rightChildIndex < length){
      //왼쪽을 안바꿔도되고(null), 오른쪽 자식의 값이 부모보다 작다면 바꿔야한다.
      //왼쪽을 바꿔도되고, 오른쪽 자식의 왼쪽 자식의 값보다 작다면 오른쪽 자식을 바꿔야한다.
        if(
          (swapIndex === null && this.heap[rightChildIndex] < element) ||
          (swapIndex !== null && this.heap[rightChildIndex] < this.heap[leftChildIndex])
        ){
          swapIndex = rightChildIndex;
        }
      }

    //바꿀게없다면 패스
      if(swapIndex === null) break;
    //부모와 자식을 바꾼다.
      this.heap[index] = this.heap[swapIndex];
      index = swapIndex;
    }

    this.heap[index] = element;
  }
  • dequeue 를 하게 되면 맨위에 값이 최대값으로 바뀌기 때문에 자식을 탐색하면서 정렬해야한다.

전체 코드

class PriorityQueue{
  constructor(){
    this.heap = [];
  }

  enqueue(value){
    this.heap.push(value);
    this._heapifyUp();
  }

  dequeue(){
    const min = this.heap[0];
    const end = this.heap.pop();

    if(this.heap.length > 0){
      this.heap[0] = end;
      this._heapifyDown();
    }

    return min;
  }

  _heapifyUp() {
    let index = this.heap.length -1;
    const element = this.heap[index];

    while(index > 0){
      const parentIndex = Math.floor((index - 1) /2 );
      const parent = this.heap[parentIndex];

      if(element >= parent) break;

      this.heap[index] = parent;
      index = parentIndex;
    }
    this.heap[index] = element;
  }

  _heapifyDown(){
    let index = 0;
    const length = this.heap.length;
    const element = this.heap[0];

    while(true){
      let leftChildIndex = 2 * index + 1;
      let rightChildIndex = 2 * index + 2;
      let swapIndex = null;

      if(leftChildIndex < length){
        if(this.heap[leftChildIndex] < element){
          swapIndex = leftChildIndex;
        }
      }

      if(rightChildIndex < length){
        if(
          (swapIndex === null && this.heap[rightChildIndex] < element) ||
          (swapIndex !== null && this.heap[rightChildIndex] < this.heap[leftChildIndex])
        ){
          swapIndex = rightChildIndex;
        }
      }

      if(swapIndex === null) break;

      this.heap[index] = this.heap[swapIndex];
      index = swapIndex;
    }

    this.heap[index] = element;
  }
}
반응형

'Language > Javascript' 카테고리의 다른 글

코딩테스트를 위한 이분탐색  (1) 2024.11.09
[JS] 프로토타입  (0) 2024.09.29
반응형

필기 전형

필기 전형에는 LG way fit, 코딩테스트를 본다. 

 

LG Way Fit

인적성 검사 결과를 1년이나 가지고 있는줄 몰랐다.. 작년 유플러스 시험볼때 가뜩이나 무참히 망쳤는데.. 이걸 다시 쓰다니 ㅠㅠ 코테를 엄청 잘보지 않는 이상 괜찮을까??

 

이번에 20문제에 20분으로 바뀌었다는데.. SKCT 보다 더 어려웠다는 후기가 들린다. 오히려 좋을지도??

코딩테스트

  1. Set 을 사용한 일반 구현 문제 (실5)
    1. 두가지 정수를 곱한 후 그 값이 곱한 두가지 값이 포함이 되어있는지? 에 대한 문제였다. 그냥 문자열로 바꾸고 set에 모든 경우의 수를 넣은 후 사이즈를 출력했다.
  2. 시뮬레이션 (실2)
    1. 관람차를 타는 문제. 몇 초동안 기구를 타고싶어하는 사람들과 그 사람들이 관람차 다 타고 내려왔을 때 시간을 구하는 문제.
    2. 삼성 시뮬레이션으로 단련된 나의 실력 덕분에 무난히 풀 수 있었다.
  3. DFS + dijkstra (골4)
    1. 노드간 간선을 만들고, 조건을 만족하는 노드를 찾은 후 그 위치에서 처음 위치로 가장 빠르게 돌아오는 최단시간
    2. 조건을 만족하는 노드 찾기 - dfs
    3. 찾은 노드에서 되돌아오기 - dijkstra

후기

전체적인 문제 난이도가 평이했다. 1,2 번 40분 정도 풀었고, 나머지 1시간 20분은 3번 문제에 투자했다. 평소에 다익스트라 알고리즘 자꾸 까먹어서 시험 보기 전날 몇문제 풀었는데 3번 문제가 나와서 너무 반가웠다.. 그래도 알고리즘을 정확히 기억 못해서 몇번 애먹었지만 dfs와 다익스트라를 결합하니 테스트케이스에 통과했다. 스몰케이스도 넣어가면서 정확성을 확인했는데 라지 케이스에서는 어떻게 될지 모르겠다.

 

예상결과 : 3솔

반응형

+ Recent posts