본문 바로가기

카테고리 없음

[우아한테크러닝] 3주차 과정

[2021.06.15] 다섯번째 과정

컴포넌트에 관련하여 더욱 자세한 이야기를 나누었다. 리액트의 컴포넌트는 일반적인 컴포넌트로 보기에는 부족하다는 김민태님의 의견이다. 사실 컴포넌트에 대해서는 대강적인 컨셉만 이해하고 있었으나 용어와 구분에 대해 면밀히 생각해보진 못했다는 점이 스스로를 되돌아보게 되었다.

컴포넌트에 대한 고찰

컴포넌트는 독립적이며, 재사용이 용이하여야 한다. 당연한 이야기이다. 리액트의 컴포넌트랑 비교해보자. 리액트의 컴포넌트는 독립적인가? 물론 사용에 따라 잘 분리하면 독립적일 수 있을 것이며 재사용성도 훌륭하게 해낸다. 그렇지만 '리액트 내부'에 한정되어있다. 외부에서 사용할 수도 있겠지만 그렇다면 어떠한 인터페이스를 갖추어야 할 것이다. 이 부분에 대해서 컴포너트라고 부르기에는 여러 부족한 점이 있다. 그렇다면 진짜 컴포넌트는 어떤 것이 있을까?

일례로 기본적인 HTML 태그 요소들이 있을 것이다. 이 표준 HTML 요소는 어떠한 프로토콜 규약을 통하여 같은 출력을 보장한다. 그렇기에 컴포넌트는 프로토콜이 존재하여야 한다. 또한 리액트에도 적용이 되는데, 리액트를 컴포넌트처럼 사용하려면 가이드라인, 규격을 만드는 것이 좋다. 자신만의 규격을 지정하는 것도 좋지만 왠만하면 이미 존재하는 일반적인 규격을 채택하는 것도 좋은 전략이다.

https://en.wikipedia.org/wiki/Web_Components

 

Web Components - Wikipedia

Web Components are a set of features that provide a standard component model for the Web[1] allowing for encapsulation and interoperability of individual HTML elements. Primary technologies used to create them include:[2] Custom Elements: APIs to define ne

en.wikipedia.org

리액트 ?

리액트에 너무 열광하는 것은 좋지 않다. 리액트를 다양한 시각으로 볼 줄 알아야 한다. 리액트에 너무 의존하게 된다면 OOP적으로 접근하기에 무리가 있다. 리액트에서도 함수형 프로그래밍을 추천하는 하는데 여기서 OOP라니.. 또한 리액트+ Typescript는 타입스크립트의 깊은 부분들을 사용하는데에 제한이 있다. 그저 컨셉만 사용하는 정도?

 

도서 추천 :

  • You Don't Know Js 시리즈 추천.

 

[2021.06.18] 여섯번째 과정

리덕스 만들기로 했다

개발하면서 가장 어려운게 뭘까? ⇒ 변하는게 있고, 안변하는게 있다.

HTML은 선언형 언어이며 예측 가능하다. 그렇지만 JS는 예측이 되지 않는 상태에 놓여져있다. 그렇기에 예측하기 어렵다

함수형 프로그래밍 언어 ⇒ 변수 없이 상수로만 짜는 것.

JS는 함수형 프로그래밍 언어가 아니다.

변하는 것 ⇒ 상태, example ⇒ 혈액형은 상태가 아니고, 기분은 상태이다.

상태를 어떻게 다루지? ⇒ 테스트를 많이한다. 혹은 상태가 바뀐것을 모두에게 알려준다.

리덕스는 컨셉 하나로 먹고사는 신기한놈. 아주 적은 소스코드로 만들어 냄.

리덕스는 스토어라고 하는 녀석으로 전역 상수를 만듦

중요한 코드는 위치가 바뀔 수 있지만 사라질 수는 없다.

스위치문은 별로 안좋다 ⇒ 왜지?

if문도 안좋다 ⇒ 왜지?

if문, switch을 없애야 한다.

클로저가 무엇인가? ⇒ 가장 아쉬운 답 : 내부 변수를 숨기려고 사용한다. 이것은 부수 효과이다. 명확한 답은 아니다.

합격을 부르는 답 ⇒ 함수형 프로그래밍의 기본적인 답 : 함수를 생성해주는 역할을 한다.

JS는 기본적으로 깊은 복사를 지원하지 않은다.

깊은 복사 치팅법 ⇒JSON으로 만들고 다시 파싱, 재귀하는 방법. 뭐든간에 비용이 많이 발생함.

그런데, 리듀서는 원본 객체를 리턴해주었기에 객체가 변환될 수 있다. 복사된 객체를 리턴해주지 않은 이유는 책임의 문제이다. 깊은 복사는 비용이 크기에 복사를 해서 주기에는 부담스럽기도 하고, 그것을 보장하진 않지만 매뉴얼에는 복사해서 사용하라고 함.

함수의 스코프는 호출될 때 생긴다 ! 생성될 때 생기는게 아니다.

리액트는 가상 돔을 지원하는 라이브러리다. 그리고 돔은 태생이 너무 다루기 까다롭기에 가상돔을 만든 것이다. 그래서 리액트는 JSX를 만들어서 제공하였다.

virtual돔은 하나의 객체이다. 리얼돔이 바뀌는 부분만 바꿔준다.

리얼돔은 작은 상태를 바꾸면 전체가 바뀌어야되는데, React는 작은 상태를 바꾸고 전체가 바뀌는 것의 성능을 가상돔(JSX)로서 보장해준다.

switch는 연관관계가 없지만 강제로 붙여놓는다. 그렇기에 복잡해보인다. 그렇기에 switch나 if를 식으로 바꾸려 한다.

리덕스는 완전한 동기 코드이다. 그렇기에 비동기로 가져온 값으로 리덕스를 갱신할 수 없다. 리듀서는 순수함수이다.

커링 기법으로 리덕스 미들웨어를 끼워넣어서 비동기를 할 수 있다.

props는 불변이다. 상속과 같은 느낌. state는 변경할 수 있다.

혈액형은 props.

성격은 state.

function createStore(reducer){
  let state;
  let handler = [];
    // 내부적으로 볼 때는 store보다는 state가 더 낫다. 네이밍 센스 !
  reducer(state, { type: '@@__init__@@' });

  return {
    dispatch : (action) =>{
        state = reducer(state, action);
        // state = reducer({...state}, action);
        handler.forEach(h=>{
          h();
        })
    },

    subscribe : (listener)=>{
      handler.push(listener);
    },

    getState: () => state,
  }
};

const InitState = {
  type: '',
  counter: 0, 
  profile: {
    id: '',
    imageURL: '',
  },
}
function reducer(state = InitState, action) {
  switch(action.type){
    case "counter":
      return {
        ...state,
        counter: action.counter,
      };
      // state.counter = action.counter;
      // return state;

    case "action":
      return {
        ...state,
        type: action.action,
      }
      // state.type = action.action;
      // return state;

    default:
      return { ...state};
}

const store = createStore(reducer);

store.subscribe(()=>{
  console.log('바꼇나염?~', store.getState());
})


function actionCreator(type, data) {
  return {
    type: type,
    ...data,
  }
}

const counter = counter =>{
  store.dispatch(actionCreator("counter", {counter}));  
}

function foo(){
  counter();  
  // 상태는 무조건 디스패치를 통해서 바꿀 수 있다.
}
function zoo() {
  store.dispatch(actionCreator("action", {action: "fetch"}));
}
// 어떠한 인터페이스를 

foo();
zoo();

const action = {
  'A' : () =>{

  },
  'B' : () =>{

  },
}

switch(A){
  case('A'):
    break;
  case('B'):
    break;
}
// 둘이 같음. 위의 함수형을 선호.

function makePerson(lastName){
  let name = `이 ${lastName}`;

  // Do something...
  return function(hello){
    return `${hello} ${name}`;
  }
}

const lee = makePerson('기주');
const kim = makePerson('민태');

console.log(
  lee('안녕~'),
  kim('안녕하세요.'),
  makePerson('안녕안녕')('종한아'),
)

function makePerson2(lastName, hello){
  return `${hello} 김 ${name}`;
}

console.log(
  makePerson2('안녕하세요.', '민태')
)

const func = x => y => z => x + y + z;
// 커리 함수.

// 둘의 형태가 다르다. 첫번째 방식은 함수를 생성하고 한번 더 호출해야 한다.
// 첫번째 함수 호출을 지연시켜서, 새로운 형태를 주입할 수 있는 이득을 준다.
// 코드 자체의 표현력을 상승 시킨다.
// 분리시키는 것을 '커링'이라고 함. 

// 클로저는 물리적으로는 지연함수, 논리적으로 표현력 상승

// closure