[React] 리액트 개념정리

먼지·2022년 11월 9일
0

React

목록 보기
4/8
post-thumbnail

드림코딩 리액트 개념 정리 강의 + 리액트 공부

리액트 개념

왜 리액트인가?

리액트란 "user interfaces"를 만들기 위한 자바스크립트 라이브러리로 페이스북에서 만듦
22년도엔 성능 개선 + SSR을 위한 컴포넌트들도 나옴

=> ui를 만들 수 있는 라이브러리로 웹, 모바일 앱을 손쉽게 만들 수 있게 해줌. 심플한 정적 사이트부터 복잡한 규모까지

배워두면 이런 것들을 만들 수 있음
React : 웹 애플리케이션
React Native : 크로스 플랫폼이 가능한 모바일앱
React + Electron : 데스크톱 애플리케이션

리액트로 무언가를 만든다?
SPA(Single Page Application)

  • 깜박임 없이 컴포넌트를 어떨 때 숨기고 보여주는 등 페이지 내에서 자유자재로 네비게이션 할 수 있는 것
    • Gatsby or Next.js => SSG/SSR 구현 가능

리액트만을 사용했을 땐
CSR(Client Side Rendering)

  • 사용자가 우링 웹앱에 접속했을 때 즉각적으로 HTML을 보는 것이 아닌 리액트 라이브러리도 함께 다운받아서 클라이언트 측에서 렌더링이 이루어지는 것

라이브러리와 프레임워크 차이점

리액트는 UI를 만드는 JS 라이브러리!

Framworks

통상적으로 프레임워크라 하면 우리가 무언가를 마늗는 데 필요한 그 모든 것들이 갖춰진, 제공되는 것으로 UI, Routing, HTTP Clients, State management 모든 것들이 다 들어있어서 뭐를 쓸지 고르거나 찾을 필요 없이 정해진 것만 써서 편함.

단점은 프레임워크에서 규정하고 권장하는 모든 것들을 다 공부해야 해서 꽤 오랜 시간이 걸리고 선택 옵션이 거의 없어서 자율성이 떨어짐.
=> 집을 짓기 위한 골격. 정해진 틀이 있고 그 안에서 원하는 것을 만들어가는 것

ex) Angular, Android, IOS

Vue는 프레임워크에 속하지만, HTTP Clients와 State management가 제공되지 않기 때문에 경량형 프레임워크라고 볼 수 있음

Libraries

큰 골격이나 규칙이 정해지지 않고 한 가지 좁은 문제를 해결하기 위한 작은 솔루션 단위.

리액트를 만들며 네트워크 통신이 필요하면 브라우저에서 제공되는 fetch나 다른 라이브러리를 사용하면 됨. 필요할 때마다 내가 원하는 것을 골라서 사용할 수 있는 자율성이 보장되고 상대적으로 작고 진입장벽이 낮음

ex) React.js (UI관련문제해결)

페이스북에서 리액틀르 계속 점진적으로 발전시키고 강력한 커뮤니티가 있어서 필요하거나 문제라 생각하는 것들이 개발돼서 사용할 수 있는 라이브러리가 많음. 리액트로 뼈대를 만들고 여기저기서 필요한 것들을 가져와 사용!

리액트 철학

What's React?

A JavaScript library for building user interfaces
=> Renders UI and responds to(reacts to) events

두가지 키워드 -> ui, events
=> components

ui를 컴포넌트들 단위로 보여주고 이벤트에 반응하도록 만들어나가는 라이브러리

웹앱을 잘 만들어 나가려면 웹 페이지를 "박스 단위"로 바라보는 안경이 필요! 박스(=컴포넌트) 단위로 분석해 나가고 각각의 박스 안에서도 각각의 작은 박스로 나뉘게 바라보고 사고하고 구현해나가는 것이 중요 => 리액트에서도 박스 단위의 컴포넌트들로 만들기 때문

컴포넌트란 어려운 말로?
A highly conhesive building block for UIs loosely coupled with other components.
응집도가 정말 높은 UI 블록으로 다른 컴포넌트들과 연결돼있지 않는 독립적인 최고의 응집도를 유지하고 있는 빌딩 블록

좋아요 버튼의 컴포넌트가 있다면?
이 버튼은 독립적으로 잘 고립돼잇음 다른 UI가 변경 업데이트되어도 이 버튼은 이 상태 그대로 유지 가능. 내가 원하는 곳에서 이 버튼을 계속 사용할 수 있어서 재사용성이 높음

리액트로 웹 애플리케이션을 만든다는 것은 재사용 가능하고 독립적인 UI 컴포넌트들을 계속해서 만들어나가는 것

html에서 큰 박스를 먼저 만들고 작은 박스들을 채워나가는 것처럼 리액트엔 단 하나의 Root 요소가 있음. 그 안에 여러 박스(컴포넌트)들로 나누어서 재사용 가능한 것들을 컴포넌트 단위로 만듦

재사용 가능한 작은 단위의 컴포넌트를 만들어서 각각의 페이지에서 필요한 컴포넌트들을 가지고 와서 조립해 나가는 것으로, 리액트에선 컴포넌트를 잘 만드는 것이 핵심 포인트! 그리고 추구하는 방향성은 다른 컴포넌트들과는 연결(커플링) 되어있지 않은 하지만 내부에선 서로의 밀집도 응집도가 높은 컴포넌트들로 만들어 나가야 함

정리

리액트란
컴포넌트들의 집합체로
이 컴포넌트들을 잘 만드는 것이다
좋은 컴포넌트는 독립적이며 재사용성이 높아야 한다

컴포넌트 나누는 기준?

어떤 단위로 컴포넌트를 만들어야 하나?

  • 재사용성
    DRY (Don't Repeat Yourself)
    코드를 작성할 때는 항상 반복하지 말고 재사용 가능한 로직이나 코드들은 재사용 해야 한다.
  • 단일책임
    SR (Single Responsibility)
    Article 이란 컴포넌트 안에 중간중간 요소들은 다른 웹페이지에서 재사용할 일이 없더라도 한 컴포넌트 안에서 너무 많은 UI나 로직을 가지거나 다양한 일을 한다면 조금 더 작은 단위로. 한 UI에선 하나의 도메인을 담당해서 보여줄 수 있도록 잘게 잘게 만드는 것

너무너무 세부적으로 나누다기 보단 한 컴포넌트 안에서 너무 많은 일을 처리하고 보여준다면 재사용하지 않더라도 하나의 책임을 가질 수 있도록 분리할 수 없을까? 생각하고 나눠나가기

리액트의 동작 원리

고급 내용들 (Deep Dive)

리액트란 컴포넌트들의 집합체고 함수형으로 작성할 수 있고
내부 상태를 나타내는 State, 외부로 부터 전달받은 상태 Props
가지고 있는 데이터나 정적인 UI를 나타내는 render(return 하는 jsx)가 있다.
상태가 변경될 때마다 re-render(함수형 컴포넌트를 재호출) 된다.
내부적으로 가상돔을 가지고 있어서 실제로 변경된 부분만 화면에 업데이트 된다.
효율적으로 ui를 업데이트

마우스 따라 가기

기본 내용들

CSR (클라이언트 사이드 렌더링)

useState 유의할 점

만약 버튼을 클릭할 때 setState를 5번 호출하면?! 1만 증가함.
이건 자바스크립트의 클로저와 연관이 있는데, 이 콜백함수(onClick)가 전달될 때 찰칵하고 현재 상태를 스냅샷 됨. 그랬을 때 외부 변수인 count 값이 찰칵하고 저장이 돼서 count: 0 이라 저장을 함.

이 캡처된 모든 환경을 lexical environment라고 하는데 이게 콜백함수에 전달돼서 setCount를 호출하면 count 값이 1로 설정이 되고 두세번째 모두 다 count가 0이라 결국 1로 설정됨

export default function Counter() {
  const [count, setCount] = useState(0);
  const onClick = () => {
    setCount(count + 1); // 0 + 1
    setCount(count + 1); // 0 + 1
    setCount(count + 1); // 0 + 1
    setCount(count + 1); // 0 + 1
    setCount(count + 1); // 0 + 1
  };
  return (
    <div>
      <span>{count}</span>
      <button onClick={onClick}>Add+</button>  
    </div>
  );
}

원하는 대로 동작하게 하려면, setState에 이전 상태값을 인자로 전달하면 그걸 가지고 무언가 값을 업데이트할 수 있는 콜백함수를 전달

export default function Counter() {
  const [count, setCount] = useState(0);
  const onClick = () => {
    setCount((prev) => prev + 1); // 0 + 1
    setCount((prev) => prev + 1); // 1 + 1
    setCount((prev) => prev + 1); // 2 + 1
    setCount((prev) => prev + 1); // 3 + 1
    setCount((prev) => prev + 1); // 4 + 1
  };
  return (
    <div>
      <span>{count}</span>
      <button onClick={onClick}>Add+</button>  
    </div>
  );
}

리액트에서 상태를 사용할 때는 리액트에서 제공하는 useState hook을 사용하는데, 상태를 업데이트할 때는 기존에 스냅샷 된 오래된 outdated 된 예전 값 상태에 의존하기 보다 setState 전달되는 이전 상태를 사용하는 것이 더 안전함.

컴포넌트들끼리 공통적으로 필요한 데이터는 제일 부모에 컴포넌트에, 개별적으로 필요한 state는 내부 컴포넌트에서 사용

useEffect

생애주기

그냥 상대경로를 쓰면 public에 있는 데이터에 접근할 수 있음

fetch('data/products.json')
  .then(res => res.json())
  .then(data => ...);

상태를 업데이트하면 리액트는 상태가 변경된 컴포넌트 함수를 다시 호출함. 무한 루프에 빠지지 않으려면 컴포넌트가 보여질 때 딱 첫 번째만 네트워크 통신을 통해 데이터를 받아오고 그 뒤로는 요청하지 않게 만들려면 useEffect를 사용

첫 번째 인자는 콜백 함수
두 번째 인자는 dependency array

텅 빈 배열을 두 번째 인자로 넣으면 컴포넌트가 처음 렌더링 될 때만 등록된 콜백 함수가 호출됨

컴포넌트가 보일 때. 다시 보일 때 "처음"

근데 컴포넌트가 없어질 때 무언가(메모리, 소켓 네트워크 통신을 close)를 정리해야 한다면 return 함수를 전달하면 됨.

export default function App() {
  const [products, setProducts] = useState([]);
  useEffect(() => {
    fetch('data/products.json')
      .then(res => res.json())
      .then(data => setProducts(data));
    
    // cleanup function
    // 컴포넌트가 화면에서 사라질 때(=unmount) 호출되는 함수
    return () => { ... }
  }, []);
}

제대로 사용하기

아무런 dependency를 전달하지 않으면 컴포넌트가 처음 마운트 됐을 때만 호출되는데, 특정한 값이 변경될 때 다시 네트워크를 요청해야 한다면?

checked 값이 변경될 때마다 useEffect가 전체적으로 다시 호출됨. 그리고 새로 호출될 때마다 정리하는 함수도 호출됨

export default function App() {
  const [products, setProducts] = useState([]);
  const [checked, setChecked] = useState(false);
  useEffect(() => {
    fetch(`data/${checked ? 'sale_' : ''}/products.json`)
      .then(res => res.json())
      .then(data => setProducts(data));
    
    return () => { ... }
  }, [checked]);
}
profile
꾸준히 자유롭게 즐겁게

0개의 댓글