[우아한 테크러닝] 4일차) React & 비동기

2020. 9. 12. 22:10React/우아한 테크러닝

우아한 테크러닝 4일차


간단한 예제 만들기

 

컴포넌트 아키텍쳐


언제 쪼갤지에 대한 고민 -> 고민하다가 점점 비대해져서 버그생길까봐 못 쪼갬
언제 또갤지 고민될 때 쪼개라

 

class component

function

class ClassApp extends React.Component {
  constructor(props) {
    super(props);
    
    // 만들어지는 인스턴스 객체를 this로 참조하게 됨
    this.state = {
      displayOrder: 'ASC'
    }
  
    // 그래서 바인딩을 해 줬다
    this.onToggleDisplayOrder = this.onToggleDisplayOrder.bind(this);
  }
  
  onToggleDisplayOrder() {
    // 불릴 때의 this는 인스턴스가 아닌 다른 친구가 됨
    this.setState({
      displayOrder: displayOrder === "ASC" ? "DESC" : "ASC"
    });
  }
  
  render () {
    return (
      <div onClick={this.onToggleDisplayOrder}>여기여기</div>
    );
  }
}

 

 

arrow function

class ClassApp extends React.Component {
  constructor(props) {
    super(props);
  
    // 만들어지는 인스턴스 객체를 this로 참조하게 됨
    this.state = {
      displayOrder: 'ASC'
    }
  }
  
  toggleDisplayOrder = () => {
    // 렉시컬 컨텍스트를 사용 -> this가 고정되므로 자동으로 binding이 됨
    this.setState({
      displayOrder: displayOrder === "ASC" ? "DESC" : "ASC"
    });
  }
  
  render () {
    return (
      <div onClick={this.onToggleDisplayOrder}>여기여기</div>
    );
  }
}

 

 

function component

import React from "react";

const SessionItem = ({ title }) => (<li>{title}</li>);

const App = (props) => {
  const [displayOrder, toggleDisplayOrder] = React.useState("ASC");
  const { sessionList } = props.store;
  const orderedSessionList = sessionList.map((session, i) => ({
    ...session,
    order: i
  }));
  
  const onToggleDisplayOrder = () => {
    toggleDisplayOrder(displayOrder === "ASC" ? "DESC" : "ASC");
  };
  
  return (
    <div>
      <header>
        <h1>React and TypeScipt</h1>
      </header>
      <p>전체 세션 갯수: 4개 {displayOrder}</p>
      <button  onClick={onToggleDisplayOrder}>재정렬</button>
      <ul>
        {orderedSessionList.map((session) => (
          <SessionItem title={session.title} />
        ))}
      </ul>
    </div>
  );
};
  
export default App;

 

Class vs Hook

상태 가질때마다 class 변환이 구찮다
혹은 자잘한 state를 전부 리덕스 전역 store로 올렸다
-> 그래서 함수 컴포에서도 상태를 만들 수 있게 했다 hooks

class 컴포는 같은 state를 다루는 메소드가 분리되어 있고
hook은 응집성 (같은 state를 다루는 메소드가 한번에 뭉쳐 있다)

또, class는 부가적인 코드 (this, prototype, 실행 컨텍스트…) 를 많이 알아야 하고
hook은 function 과 기본 컨셉만 이해하면 된다

코드량이 적고 간편하다

 

 

 

제네레이터와 비동기


어떻게 해야 비동기 코드를 동기적으로 보기 쉽게 쓸 수 있을까?

 

지연 호출

const  x  =  10;
const  y  =  x  *  10;
  
// 위의 코드들은 동시에 실행되지 못함
// x값이 획실해지기 전에는 y 연산을 실행하지 못함
// x에 변수적으로 디펜던시가 걸려 있기 때문에
  
const a = () => 10;
const b = a() * 10;
  
// a값이 확정되는 순간을 실제 값이 필요한 순간으로 지연시킴
// lazy: 지연 호출

 

Promise

const p = new Promise(function (resolve, reject) {
// 이 함수가 리턴되어도 resolve를 지연 호출시킬 수 있음
  setTimeout(() => {
    resolve("1");
  }, 1000);
});
  
p.then(function (r) {
console.log(r);
});

 

제네레이터 함수

컨셉

function* make() {
  return 1;
}
  
const i = make();
console.log(i);  // 제네레이터 객체를 리턴
  
// 제네레이터는 코루틴의 구현체
  
// 함수
function xyz(x) {
  // 무언가를 실행
  return 0;
}
  
function abc(x) {
  // 무언가를 실행
  // 리턴이 없다면 프로시저
}
  
// 함수인데 리턴을 여러번 할 수 있도록 하면??
// 다시 호출되면 마지막 호출된 시점부터 다시 시작 => 코루틴

 

 

예시

function* makeNumber() {
  let num = 1;
  
  while (true) {
    yield num++;  // 제네레이터 함수 안의 리턴 yield
  }
}
  
const i = makeNumber();  // 실제로 실행되지는 않고 실행될 준비만
  
console.log(i.next());

// 실제 실행되려면 next 호출 -> yield 만날 때까지 호출
// 값 대신 객체를 줌 => done이라는 플래그를 함께 받아옴 => 다음에 실행할 코드가 있는지?
// Object {value: 1, done: false}
  
console.log(i.next());  // Object {value: 2, done: false}
console.log(i.next());  // Object {value: 3, done: false}
console.log(i.next());  // Object {value: 4, done: false}

제네레이터의 yield를 사용하면 함수를 끝내는 것 X 다음 호출을 대기
return을 사용하면 함수 자체를 나가서 끝내버려서 done: true가 된다

 

 

내부의 상태를 유지합니다

function* makeNumber() {
  let num = 1;
  
  while (true) {
    const x = yield num++;
    console.log(x);
  }
}
  
const i = makeNumber();
  
i.next();
i.next('a');  // 함수 안쪽 바깥쪽 커뮤니케이션 가능
  
// 내부의 상태를 계속 유지 가능합니다

 

 

Promise와 함께 사용하기

function* makeNumber() {
  let num = 1;
  
  while (true) {
    const x = yield num++;
    console.log(x);
  }
}
  
const delay = (ms) => new Promise((res) => setTimeout(res, ms));
  
// 비동기이지만 동기 코드처럼 보입니다

function* main() {
  console.log("시작");
  yield delay(3000);
  console.log("3초 뒤입니다");
}
  
const it = main();
  
const { value } = it.next();  // value로 Promise 객체가 옴
  
value.then(() => {
  it.next();
});
  
// 이걸 이용해서 만든 것이 리덕스 saga

 

async / await

const delay = (ms) => new Promise((res  => setTimeout(res, ms));
  
// 제네레이터와 모양이 비슷합니다
async function main2() {
  console.log("시작");
  await delay(3000);
  console.log("3초 뒤입니다");
}
  
main2();
  
// async는 Promise에 최적화가 되어 있지만, yield는 뒤에 아무거나 와도 됨
// 더 다양한 범위에서 커버가 가능합니다
// async 함수도 내부적으로는 제네레이터로 되어 있습니다