오픈소스 훔쳐보기

kyj2471·2021년 11월 12일
18

오픈소스를 보다가 사용하기 유용해보이는 코드를 직접 run.js를 통해 확인 하면서 유용해 보이는 코드를 따로 정리했습니다.

참고한 오픈소스

GitHub - withspectrum/spectrum: Simple, powerful online communities.

폴더구조

spectrum/
├── api        # API server
├── docs
├── hyperion   # Rendering server
├── public     # Public files used on the frontend
├── shared     # Shared JavaScript code
├── src        # Frontend SPA

🧤 usePrevious - custom hooks

import { useRef, useEffect } from 'react';

function usePrevious(value) {
  const ref = useRef();
  useEffect(() => {
    ref.current = value;
  });
  return ref.current;
}

export default usePrevious;

해당 컴퍼넌트는 이전값을 기억하는 커스텀 훅이다.

[usage]

import { useState } from "react";
import usePrevious from "./usePrevious";
import "./App.css";

function App() {
  const [value, setValue] = useState(0);
  const lastValue = usePrevious(value);
  return (
    <div className="App">
      <div>
        현재값 {value} - 전의값 {lastValue}
      </div>
      <button onClick={() => setValue(value + 1)}>increment</button>
    </div>
  );
}

export default App;

[test-result]

🧤 scroll event - document.getElementById(id) / useLayoutEffect


import { useState, useEffect } from 'react';

export const useAppScroller = () => {
  const [ref, setRef] = useState(null);

  useEffect(() => {
    if (!ref) setRef(document.getElementById('main'));
  });

  const scrollToTop = () => {
    const elem = ref || document.getElementById('main');
    if (elem) return (elem.scrollTop = 0);
  };

  const scrollToBottom = () => {
    const elem = ref || document.getElementById('main');
    if (elem) return (elem.scrollTop = elem.scrollHeight - elem.clientHeight);
  };

  const scrollTo = (pos: number) => {
    const elem = ref || document.getElementById('main');
    if (elem) return (elem.scrollTop = pos);
  };

  return { scrollToTop, scrollTo, scrollToBottom, ref };
};

하나의 컴퍼넌트에서 프로젝트에서 사용되는 스크롤 이벤트를 핸들링하는 컴퍼넌트이다.

document.getElementById() 메서드는 id를 매개변수로 받아 해당 id와 일치하는 DOM요소를 리턴한다.

여기서 id는 대소문자를 구분하며 id가 없다면 null값을 반환한다.

DOM

[usage]

const { scrollToBottom, scrollToTop, scrollTo, ref } = useAppScroller();
  const lastTab = usePrevious(tab);
  const lastScroll = ref ? ref.scrollTop : null;
  useLayoutEffect(() => {
    if (lastTab && lastTab !== tab && lastScroll) {
      sessionStorage.setItem(`last-scroll-${lastTab}`, lastScroll.toString());
    }
    const stored =
      sessionStorage && sessionStorage.getItem(`last-scroll-${tab}`);
    if (tab === 'chat') {
      scrollToBottom();
    } else if (stored && history.action === 'POP') {
      scrollTo(Number(stored));
    } else {
      scrollToTop();
    }
  }, [tab]);

위의 예시에서 처럼 특정 이벤트를 통하여 원하는 스크롤로 이동할 수 있다.

여기서 useEffect가 아닌 useLayoutEffect를 사용한다.

import React, { useLayoutEffect } from 'react';

[useLayoutEffect]

useLayoutEffect는 리액트에서 제공하는 훅이다. 이 훅을 인텔리전스로 자동완성을하면 아래와같다.

useLayoutEffect(() => {
  effect
  return () => {
    cleanup
  };
}, [input])

우리가 보는 useEffect와 동일하다. 이둘의 차이는 이펙트함수의 호출 시기다.

useEffect를 사용하면 DOM의 레이아웃 배치 및 페인트가 끝난 후 함수를 호출한다. 이와 다르게 useLayoutEffect는 브라우저가 화면에 DOM을 그리기 전에 이펙트 함수를 수행한다.

정리하면 useLayoutEffect에 속한 이펙트 함수는 DOM이 업데이트되면 동기적으로 실행이 되고 이 과정은 브라우저가 화면에 렌더링 되기 이전 실해오딘다. 그렇기에 사용자는 업데이트 되기전 화면을 보지 않는다.

이런 이유로 useEffect를 사용했을 때 특유의 깜빡이는 현상을 피할 수 있다.

어떤 경우 각각의 훅을 사용하냐에 대해 생각하면

useEfffect ⇒ 돔 변형을 하지 않는 대부분 경우

useLayoutEffect ⇒ 사용자에게 노출되는 돔을 변형시킬 때

🧤 useDebounce -

import { useState, useEffect } from 'react';

function useDebounce(value: string, delay: number) {
  const [debouncedValue, setDebouncedValue] = useState(value);

  useEffect(() => {
    const handler = setTimeout(() => {
      setDebouncedValue(value);
    }, delay);

    return () => {
      clearTimeout(handler);
    };
  }, [value]);

  return debouncedValue;
}

export default useDebounce;

어떤 이벤트에 의해 계속된 스테이트 값이 변화하게된다면 계속된 렌더링이 일어난다. 이런 불필요한 렌더링을 방지하기 위해 사용한다. 디바운스를 사용하면 특정 시간이 지난후 한번의 이벤트만 실행되게된다.

만약 인풋에서 계속된 value값이 업데이트가 되는 상황에서 스테이트값의 변화로 계속되는 불필요한 렌더링이 발생하게 된다. 이떄 콜백함수 반환값으로 clearTimeout함수를 넣어 콜백이 실행되기전 timer를 클리어한다.

[debounce참고]

🧤 sort by date - javascript-sort

function sortByDate(
  array,
  key,
  order 
) {
  return array.sort(function(a, b) {
    var x = new Date(a[key]).getTime();
    var y = new Date(b[key]).getTime();
    var val = order === 'desc' ? y - x : x - y;
    return val;
  });
}

위의 함수를 통하여 우리는 날짜를 오름차순, 내림차순에 대해 쉽게 계산할 수 있는 함수다.

[javascript-sort()내장함수 정리]

sort 자바스크립트 내장함수는 배열안의 element를 정렬하는 함수이다. 정렬된 값은 원 배열이 정렬된다(복사본이 아닙니다.)

기본적 구문은 array.sort( compareFunction )이렇게된다.

compareFunction이 0보다 작으면 a를b보다 낮은 것으로 a가 먼저 출력되게된다.

반대로 큰경우 b를 a보다 낮은 인덱스로 출력한다.

[example ]

const numberArr = [1,79,31,12,50]

numberArr.sort()
numberArr.sort(function(a,b){
  return a-b //오름차순
  return b-a //내림차순
})
const people = [
  {name:'tony', age:29},
  {name:'chloe', age:27},
  {name:'van', age:40}
]

people.sort(function(a,b){
  if(a.age > b.age){
    return 1
  }
  if(a.age < b.age){
    return -1
  }
  return 0;
})

people.sort(function(a,b){
//대소문자를 무시합니다.
  const firstName = a.name.toUpperCase()
  const secondName = a.name.toUpperCase()
  
  if(firstName > secondName){
    return 1
  }
  if(firstName < secondName){
    return -1
  }
  return 0
})

result:
[
  { name: 'chloe', age: 27 },
  { name: 'tony', age: 29 },
  { name: 'van', age: 40 }
]

[usage]

messages = sortByDate(arrayOfDate, 'timestamp', 'asc');

[test]

🧤 원하는 수만큼의 문자열 substring, substr

function truncate(str, length) {
  if (str.length <= length) {
    return str;
  }
  var subString = str.substr(0, length);
  if (subString.indexOf(' ') < 0) return subString + '…'; 
  return (
    subString.substr(0, subString.lastIndexOf(' ')).replace(/\n/, ' ') + '…'
  );
}

1번쨰 리턴문은 문자내에 띄워쓰기가 없는 경우다. 아래 두번째 리턴문은 띄워쓰기가 있는 경우의 리턴값이다.

[usage]

{truncate(thread.content.title, 80)}
  • substr()

substr(start,length)로 설정하며 length값은 가져올 길이고 생략이 가능하다.

length값이 음수가 들어오면 가져올값이 없다 판단해 빈값을 반환한다.

  • substring(start, end)

시작인덱스부터 end앞까지 반환되며 end값이 없으면 문자열의 끝까지 반환된다.

매개변수 하나가 음수이면 시작위치가 0이되고 둘다 음수면 반환값이 없다.

profile
[ frontend-developer ]

1개의 댓글

comment-user-thumbnail
2021년 11월 20일

잘보고 갑니다 !

답글 달기