Front-End

되짚어 가기 본문

리액트

되짚어 가기

jeongsso 2023. 6. 1. 19:27

 

1. 비동기적 - 동기적

 

일을 하다보니 비동기 작업이라는 말을 많이 보게 된다.

비동기 작업에 대해 다시 한번 이해하고 넘어가자.

 

출처 : 벨로퍼트

 

동기적 작업 

요청이 끝날 때까지 기다리는 동안 중지 상태가 되기 때문에 다른 작업을 할 수 없다.

그 처음에 시작한 요청이 끝나야만 비로소 그 다음 작업을 할 수 있다.

계단형으로 차례로 순서를 기다려야한다

 

 

비동기적 작업

웹 애플리케이션이 멈추지 않기 때문에 동시에 여러 가지 요청을 처리할 수 있고,

기다리는 과정에서 다른 함수도 호출할 수 있다.

즉, 중지 상태가 되는 경우가 없어 작업이 즉시 처리한다.

 

 

 

서버 API를 호출할 때 외에도 함수로 하는 경우도 있는데,

setTimeout 함수다.

function printMe() {
  console.log('Hello World');
}

setTimeout(printMe, 3000);
console.log('대기중..');

이런 코드를 한 번 살펴보자.

 

일단, 코드가 위에부터 아래까지 전부 호출되고 

setTimeout(   , 3000) => 여기서 3초뒤에 첫 번째 인자를 실행하라는 의미로

3초뒤에 printMe가 호출된다.

 

코드가 3초 동안 멈추는 것이 아니라는 의미다.

 

printMe 함수 자체를 setTimeout 함수의 인자로 전달해줬는데,

이런 함수를 콜백 함수라고 한다. 

 

 

출력된 콘솔을 확인하면 아래와 같다.

대기중...
Hello World

 

 

 

 

2. 콜백함수 / Promise

프로미스 전에 원래 콜백함수를 썼었다고하는데,

콜백 지옥때문에 사용을 지양하고 있다고 합니다.

어떤 문제인지 알아보도록 하겠습니다.

 

한번 숫자 0에서 1초에 걸쳐서 10, 20, 30, 40 같은 형태로 여러번 순차적으로 출력하려면

콜백 함수를 중첩하여 구현할 수 있었습니다.

function increaseAndPrint(number, callback) {
  setTimeout(() => {
    const increased = number + 10;
    console.log(increased);
    if (callback) {
      callback(increased);
    }
  }, 1000);
}

increaseAndPrint(0, number => {
  increaseAndPrint(number, number => {
    increaseAndPrint(number, number => {
      increaseAndPrint(number, number => {
        increaseAndPrint(number, number => {
          console.log('끝!');
        });
      });
    });
  });
});

그냥 가볍게 보기만해도 복잡한게 보일겁니다.

이런 식의 코드를 콜백 지옥이라고 부릅니다.

 


반면에 Promise를 한번 봐봅시다.

Promise는 성공할 수도 있고, 실패할 수도 있습니다.

성공 시에는 resolve를

실패 시에는 rejevt를 호출해줍니다.

function increase(number){
	const promise = new Promise((resolve, reject)=>{
    	// resolve는 성공 reject는 실패
        setTimeout(()=>{
        	const result = number + 10;
            if(result > 50){
            // 50보다 높으면 에러 발생시키기
            const e = new Error('NumberTooBig');
            return reject(e);
            }
            resolve(result); // number 값에 + 10 후 성공처리
        }, 1000);
    });
    return promise;   
}

increase(0)
	.then(number=> {
    	// Promise에서 resolve된 값은 .then을 통해 받아올 수 있다.
    	console.log(number);
    	return increase(number); // Promise를 리턴하면
  	})
  	.then(number=> {
    	// 또 .then으로 처리 가능
    	console.log(number);
    	return increase(number); // Promise를 리턴하면
  	})
    .then(number=> {
    	console.log(number);
    	return increase(number); // Promise를 리턴하면
  	})
    .catch(e => {
    	// 도중에 에러가 발생한다면 .catch를 통해 알 수 있음
        console.log(e);
      });

resolve를 호출 할 때 특정 값을 파라미터로 넣어주면,

이 값을 작업이 끝나고서 사용할 수 있다.

 

작업이 끝나고서 또 다른 작업을 해야할 때는 Promise 뒤에 .then(...)을 붙여서 사용하면된다.

실패 상황에서는 reject를 사용하고 .catch를 통하여 수행할 작업을 설정할 수 있다.

 

 

위 코드를 다시 짧게 수정할 수 있다.

function increase(number){
	const promise = new Promise((resolve, reject)=>{
    	// resolve는 성공 reject는 실패
        setTimeout(()=>{
        	const result = number + 10;
            if(result > 50){
            // 50보다 높으면 에러 발생시키기
            const e = new Error('NumberTooBig');
            return reject(e);
            }
            resolve(result); // number 값에 + 10 후 성공처리
        }, 1000);
    });
    return promise;   
}

increase(0)
    .then(increase)
    .then(increase)
    .then(increase)
    .then(increase)
    .catch(e=>
    	console.log(e);
    });

처음에 썼던 것보다 훨씬 깔끔해진 것을 눈으로 확인할 수 있다.

 

 

 

 

3. async / await

Promise를 더욱 쉽게 사용할 수 있게하는 문법이다.

 

이 문법을 사용하려면 함수 앞 부분에 async 키워드를 추가하고,

 

Promise 앞 부분에 await 키워드를 사용한다.

이렇게 하면 Promise가 끝날 때까지 기다리고, 결과 값을 특정 변수에 담을 수 있다.

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

async function process() {
  console.log('안녕하세요!');
  await sleep(1000); // 1초쉬고
  console.log('반갑습니다!');
}

process();

 

 

async 함수에서 에러를 발생 시킬때에는 throw 를 사용하고, 에러를 잡아낼 때에는 try/catch 문을 사용합니다.

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

async function makeError() {
  await sleep(1000);
  const error = new Error();
  throw error;
}

async function process() {
  try {
    await makeError();
  } catch (e) {
    console.error(e);
  }
}

process();

 

 

 

 

 

4. axios 및 데이터 연동 

일단 axios는 현재 가장 많이 사용 되고 있는 자바스크립트 HTTP 클라이언트다.

 

axios의 특징은

HTTP 요청을 Promise 기반으로 처리한다는 점이다.

 


데이터를 불러와서 불러온 데이터를 나열하는 일이 많을 겁니다.

useEffect로 사용해서 하는 법을 볼건데,

이때 주의할 점은 useEffect에 등록하는 함수에는 async를 붙이면 안된다.

왜냐하면 useEffect에서 반환해야 하는 값은 뒷정리 함수이기 때문이다.

 

 

그리고 개발하면서 '아하!'하고 이해한 부분이 있다.

 

데이터를 불러와서 데이터 배열을 map 함수를 사용하여 컴포넌트 배열로 변환할 때 신경써야하는 부분이 있는데,

map 함수를 사용하기 전에 꼭 해당 값이 현재 null 값이 아닌지 확인해야한다.

 

이 작업을 하지 않으면,

아직 데이터가 없을 때 null에는 map 함수가 없기때문에 랜더링 과정에서 오류가 발생하기 때문에 주의해야한다.

 

 

 

'리액트' 카테고리의 다른 글

리덕스 미들웨어  (1) 2023.06.06
리덕스 / Context API  (2) 2023.06.02
리액트 라우터  (0) 2023.03.18
immer 불변성 유지하기  (1) 2023.03.14
컴포넌트 성승 최적화  (1) 2023.03.10
Comments