![[인프런 워밍업 스터디 클럽 1기 프론트엔드] 2주차 발자국](https://cdn.inflearn.com/public/files/blogs/fd0daa5f-9b6c-4239-8246-af3beeb0b8df/fd.png)
[인프런 워밍업 스터디 클럽 1기 프론트엔드] 2주차 발자국
학습 내용
리액트란
Vue와 Angular는 프레임워크, 리액트는 라이브러리
리액트가 라이브러리인 이유?
리액트는 전적으로 UI를 렌더링하는 데 관여하기 때문.
가상 돔: 실제 돔을 메모리에 복사해준 것
기존 웹 앱의 경우 인터랙션이 발생할 때마다 렌더트리를 다시 생성하고 렌더링 과정을 다시 거치게 됨.
인터랙션이 많이 일어나는 웹의 경우 불필요하게 DOM을 조작하는 비용이 너무 커진다.
업데이트 전 후의 가상돔을 비교해 변경된 부분을 찾고(Diffing) 변경된 부분만 실제 돔에 적용한다.(reconciliation)
webpack
여러 파일의 자바스크립트 코드를 압축해 최적화할 수 있다.
⇒ 로딩에 대한 네트워크 비용 절감
모듈 단위의 개발이 가능, 가독성이 좋고 유지보수가 쉽다.
babel: 최신 자바스크립트 문법을 지원하지 않는 브라우저를 위해 최신 자바스크립트 문법을 구형 브라우저에서도 돌 수 있도록 변환시켜주는 라이브러리.
npx: 노드 패키지 실행을 도와주는 도구
SPA(Single Page Application)
리액트는 멀티페이지 어플리케이션이 아니라, 템플릿 하나를 이용해 동적으로 화면을 전환하는 SPA이다.
JSX(Javascript Syntax eXtension)
리액트에서 사용하는 자바스크립트의 확장 문법. 자바스크립트와 HTML 문법이 결합된 형태.
원래 리액트에서 화면을 그리는 방식: React.createElement API 를 사용해 element를 생성하고 이 element를 in-memory에 저장한다. 그리고 RenderDOM.render() 함수를 사용해 실제 웹 브라우저에 그려준다.
⇒불편하다!
JSX로 작성한 코드는 babel에 의해 createElement로 변환된다.
JSX Key 속성
가상 돔을 구축할 때 key를 이용해서 어떤 부분이 변경되었는지를 인식할 수 있다.
key로 index를 사용하는 것이 권장되지 않는 이유
⇒리스트 요소가 추가되거나 제거되면 해당 리스트들의 key값도 바뀌게 되는데 새로 맨 앞에 들어온 요소가 그 전에 있던 index를 key값으로 가져서 원하는 대로 동작하지 않을 수 있다.
React Hooks
바벨을 이용해서 클래스 컴포넌트와 함수형 컴포넌트를 변환시키면 함수형 컴포넌트가 월등히 코드량이 적다.
함수형 컴포넌트가 더 간결하고 성능도 좋다.
HOC(Higher Order Component) 컴포넌트 : 화면에서 재사용 가능한 로직만을 분리해서 component로 만들고, 재사용 불가능한 UI와 같은 다른 부분들은 parameter로 받아서 처리하는 방법.⇒컴포넌트를 인자로 받아서 새로운 리액트 컴포넌트를 리턴하는 함수
너무나 많은 HOC를 사용하면 wrapper가 너무 많아진다. React Hooks는 HOC 대신 Custom Hooks를 이용해 컴포넌트를 만들고 처리를 한다. 그로 인해 Wrapper가 많아지는 일을 방지할 수 있다.
생명주기를 위해 componentDidMount, componentDidUpdate, componentWillUnmount를 사용했던 클래스 컴포넌트와 달리 Hooks는 useEffect 하나로 간단하게 생명주기를 처리할 수 있다.
State와 Props
state: 컴포넌트 내부에서 데이터를 전달할 때 사용. 변경 가능. State가 변하면 리렌더링된다.
props: 부모 컴포넌트로부터 자식컴포넌트로 데이터를 전달할 때 사용. 변경 불가.
react-beautiful-dnd: 리액트에서 드래그앤드랍 기능을 편하게 구현할 수 있게 해주는 모듈
리액트에서 불변성이란
: 값이나 상태를 변경할 수 없는 것.
원시타입은 불변성을 가진다. 참조타입은 불변성이 지켜지지 않는다.
불변성을 지켜야 하는 이유는 참조 타입에서 객체나 배열의 값이 변할 때 원본 데이터가 변경되어 이 원본 데이터를 참조하고 있는 다른 객체에서 예상치 못한 오류가 발생할 수 있어서이다.
⇒프로그램의 복잡도 상승
리액트에서 화면을 업데이트할 땐 값을 이전 값과 비교해서 변경된 사항을 확인한 후 업데이트하는데, 불변성이 지켜지지 않을 경우 비교할 대상인 이전 값도 함께 변경되기 때문에 불변성이 지켜져야 한다.
불변성을 지키기 위해서는 값을 바꾸는 것이 아닌 새로운 배열을 생성해서 할당하는 방식으로 프로그래밍하면 된다.
useCallback을 이용한 함수 최적화
컴포넌트가 렌더링될 때 그 안에 있는 함수도 다시 생성되는데, 만약 함수가 자식컴포넌트에 props로 전달된다면 함수를 포함하고 있는 컴포넌트(부모 컴포넌트)가 리렌더링될 때마다 자식컴포넌트도 함수가 새롭게 만들어지기 때문에 계속 리렌더링하게 된다.
styled components: javascript 파일 안에서 CSS를 처리할 수 있게 도와주는 라이브러리
Iframe : HTML Inline Frame 요소로, inline frame의 약자.
효과적으로 다른 HTML 페이지를 현재 페이지에 포함시키는 중첩된 브라우저.
Iframe 요소를 이용하면 해당 웹 페이지 안에 어떠한 제한 없이 다른 페이지를 불러와서 삽입할 수 있다.
scrollLeft
Element.scrollLeft 속성은 요소의 콘텐츠가 왼쪽 가장자리에서 스크롤되는 픽셀 수를 가져오거나 설정한다.
학습 회고
이번 주차동안 수강했던 강의 내용엔 내가 이미 알고 있던 것도 있었지만 잘 몰랐던 지식도 새롭게 접할 수 있어 좋았다.
특히 리액트 강의의 섹션 3~4는 간단한 TODO 앱을 만들어보는 구현 파트와 여러 도구를 활용해 코드를 최적화하는 최적화 파트로 구성되어 있었는데, 어떻게 하면 내가 만든 앱의 성능을 최적화하고 수정하기 쉬운 코드로 만들 수 있을지를 고민해볼 수 있어서 좋았다.
인프런 워밍업 클럽의 강의는 내가 학습할 수 있는 주제를 끊임없이 던져주는 것 같다. 인프런 워밍업 클럽이 끝난 뒤 내게 남은 과제는 이렇게 모아둔 학습 주제들에 심층적으로 파고들어 탄탄한 지식의 기반을 쌓는 일일 것이다.
남은 한 주도 성실하게 임해서 잘 마무리 지을 수 있으면 좋겠다.
미션 해결 과정
이번 주부터 리액트 미션을 시작했다. 레포를 어떻게 관리할까 고민하다가, 하나의 Home 페이지를 만들고 3개의 버튼을 두어 버튼을 클릭하면 각 미션의 결과물이 나오도록 만들기로 했다.
이번 주에 완수한 미션은 ‘포켓몬 도감 앱’이다.
기본적으로 https://pokeapi.co/에서 제공해주는 api를 사용해 포켓몬 데이터를 불러오고 화면에 띄우는 방식으로 구현했다.
import axios from 'axios';
const PokedexInstance = axios.create({
baseURL: '<https://pokeapi.co/api/v2>',
});
export default PokedexInstance;
baseURL을 설정한 axios 객체를 만들고
import PokedexInstance from './axios';
const findPokemons = async (targetOffset) => {
try {
const queryParams = new URLSearchParams({
limit: '20',
offset: `${targetOffset}`,
});
const res = await PokedexInstance.get(`/pokemon?${queryParams.toString()}`);
const detailRes = await Promise.all(
res.data.results.map((result) => {
return PokedexInstance.get(result.url);
}),
);
return res.data.results.map((data, i) => {
data = detailRes[i].data;
return data;
});
} catch (e) {
console.error(e);
throw e;
}
};
포켓몬 목록을 불러오는 함수를 작성한다.
포켓몬 목록을 조회할 때는 각 포켓몬의 디테일한 정보가 없고, 포켓몬의 정보를 얻을 수 있는 api 주소가 제공된다.
그래서 다시 포켓몬별로 api를 일일이 호출해주어야 하는데, 이를 최적화하기 위해 Promise.all() 함수를 사용했다.
Promise.all()을 사용하면 여러 개의 로직을 수행할 때 비동기적으로 수행하여 총 수행 시간을 절약할 수 있다.
이 다음으로는 적절한 UI를 구성하고, 불러온 데이터를 화면에 띄우기만 하면 되었다.
미션 회고
원래도 포켓몬을 좋아해서 리액트 첫 미션으로 포켓몬 도감 앱을 선택했는데, 생각보다 볼륨이 커서 오래 걸렸다.
참고 영상에 나와있는 것과 유사하게 구현하려고 노력했는데, 포켓몬의 타입 별 색상을 맞추느라 삽질을 좀 했다. api에서 제공해주는 것이라 생각해서 계속 찾아보다가, 끝내 찾지 못해 하드코딩으로 색상을 적용해주었다. 아마 api로 제공되지 않는 정보인 것 같다.
리액트 앱을 만들긴 정말 오랜만인데, 이번 미션을 통해 내 코딩 습관을 조금 돌아보게 된 것 같다.
나는 보통 클린코드나 설계같은 걸 고려하지 않고 통으로 코드를 짜고, 기능 구현이 완료된 뒤에야 리팩토링을 하는 편이다. 작은 앱이라면 괜찮은데, 프로젝트의 규모가 커질수록 잘못된 설계로 인해 전체적인 코드 복잡도가 높아지고, 가독성도 나빠 좋지 못한 코드가 되는 것 같다.
다음 미션부터는 컴포넌트 단위로 쪼개고 상태를 어떻게 관리할지를 천천히 설계해봐야겠다.
댓글을 작성해보세요.