
이번 포스팅에서는 리액트의 핵심원리에 대해 정리!!
리액트는 사용자 인터페이스를 구축하는 자바스크립트 라이브러리
왜 리액트를 사용하는가
Javascript는 브라우저 내 DOM조작, 이를 통해 화면을 랜더링한다.
리액트는 컴포넌트 기반의 UI 라이브러리로 자바스크립트를 유용하게 이용할 수 있게 도와준다.
리액트는 응용프로그램을 작은 컴포넌트로 분리, 조합해서 사용(선언형 방식)
-> 유지보수와 관리 향상
복잡한 사용자 인터페이스를 구축하기에 용이하다
Routing
서드 파티 라이브러리 설치 (React-router)
Components & Building UIs
코드를 Component단위로 분리해 관리하면 재사용성, 가독성 향상
react vs reactDOM
-
react : UI라이브러리
-
reactDOM : 웹사이트에 출력을 도와주는 모델
-
React 주요 특징 중 하나는 Virtual DOM을 사용
-
DOM(Document Object Model) 이란?
객체로 문서 구조를 표현하는 방법으로 XML이나 HTML로 작성한다. 웹 브라우저는 DOM을 활용하여 자바스크립트와 css적용
=> ReactDOM은 브라우저에 대한 리액트 어댑터
페이지가 리로드 되는 과정
- 데이터를 업데이트하면 전체 UI를 Virtual DOM에 리랜더링 한다.
- 이전 Virtual DOM에 있던 내용과 비교
- 바뀐 부분만 실제 DOM에 적용
주요 특징
- 리액트는 단방향 데이터 플로우를 가지고 있다.
- 데이터는 항상 일정한 장소에 위치하고, 그 장소에서만 변경 가능!
- 선언적 접근 방법(state정의 -> 상태 처리)
- reactDOM은 컴포넌트를 출력(Render)하고, Component는 항상 render, return 해야 함
- react app은 하나의 component만 rendering (App Component)
public/index.html <- 여기에 src/index.js 가 붙여주는 방식
=> Single Page Application
Tip!
- import시 js파일은 확장자 생략 가능, css파일은 생략 불가능
JSX(JavaScript XML)
- return으로 반환되는 Component / JSX는 반드시 root요소를 가진다.
- css 이름을 적용할 때 - classname으로 이름 지정
React Naming
- 소문자로 시작하는 요소는 내장된 html요소 -> Component는 대문자로 시작
Components
- 자바스크립트 표현식 작성 시 JSX내부에서 {}로 감싸면 된다.
- 부모 컴포넌트로 부터 자식 컴포넌트로 값을 전달시 props로 사용
- 여러개의 컴포넌트를 하나의 컴포넌트로 조합해 사용 -> 합성(Composition)
- Wrapper Component - 여러 컴포넌트를 감싸는 방식
- props.children 자식 엘리먼트를 출력에 전달 가능
Working with Events, state & props
- 리액트는 모든 기본 이벤트를 on으로 시작하는 props로 나타낸다
- 모든 이벤트 핸들러는 props값으로 함수 필요
- 이벤트는 모두 DOM 기본 동작에 기반
- react 이벤트 종류
onChange vs onInput
onChange은 모든 입력 입력타입에 같은 이벤트 사용 가능
State
리액트는 원하는 state 설정 => state에 맞게 화면 rendering
- State는 컴포넌트 객체 별로 나뉘어져서 따로 관리된다.
useState
// useState에서 반환되는 값 1) 상태명, 2) 1에서 정한 상태를 변경하는 함수
const [name, setName] = useState(props.name)
State Update
이전 상태에 따라 상태를 업데이트 할 때 아래 처럼 callback 함수로 구현
const titleChangeHandler = event => {
setUserInput(prevState => {
return { ...prevState, title: event.target.value }
})
}
Lifting State Up
props로 함수를 넘겨 전달 (자식 -> 부모 컴포넌트로 값 전달)
stateless component
데이터 출력만을 위한 컴포넌트(해당 컴포넌트에서 관리하는 state 없음)
Working with Dynamic Contents
react 컴포넌트 별로 key값을 지정할 수 있음
-> 이렇게 지정하면 업데이트 할 때 특정 위치에 정확히 삽입 가능
-> key가 없으면 값을 추가하는 위치를 정확히 인지하지 못해서 rerendering이 일어남 -> 성능상 이슈
-> 목록 리스트가 존재하면 key값을 주는게 좋다
Rendering List
array 객체의 map함수 이용 동적으로 contents 추가
const itemfilter = props.items.filter((item) => {
return item.date.getFullYear().toString() === selectedDate;
});
...
return (
<div>
{
itemfilter.map((item) => <ExpenseItem key={item.id} title={item.title} amount={item.amount} date={item.date} />);
}
</div>
)
filter함수를 추가해 조건에 따라 contents 반환 할 수 있다.
Conditional Content
{} 안에 3항 연산자를 사용해 조견별 component 출력이 가능하다
Styling Components
Component에 스타일을 적용하는 방법은 4가지
1) 인라인 요소로 css 추가
html태그의 style속성을 동적으로 줘서 css변경 가능
let barFillHeight = '20%'
;<div
className="bar"
style={{ height: barFillHeight, backgroundColor: 'red' }}
></div>
위 방식대로 style을 주면 인라인 방식이라 코드 가독성이 떨어짐
2) .css파일로 분리
className을 동적으로 변경해서 css 적용 가능
-> 같은 class name을 사용하는 경우 문제
3) Styled Components
서드 파티 라이브러리, 고유한 범위를 가진 스타일로 미리 스타일이 지정된 컴포넌트로 지정 가능
const FormControl = styled.div`
margin: 0.5rem 0;
& label {
font-weight: bold;
display: block;
margin-bottom: 0.5rem;
color: ${props => (props.invalid ? 'red' : 'black')};
}s
`
- styled를 import해 객체를 만들어 사능
- HTML의 모든 태그가 정의되어 있음
- props를 전달해 동적으로 변환 가능
- 미디어 쿼리 적용 가능
4) CSS Module
react css module 사용
import styles from "./Button.module.css";
...
const Button = (props) => {
return (
<button type={props.type} className={styles.button} onClick={props.onClick}>
{props.children}
</button>
);
};
- 컴포넌트 이름클래스 이름해시 값으로 동적으로 클래스명이 생긴다.
babel-plugin-react-css-modules
Fragments, Portals & Refs
Fragments
리액트는 HTML태그를 트리 구조로 생성하기 때문에 루트 태그가 반드시 필요
빈 div태그로 감싸는 방법 -> 많은 태그들이 생기면서 성능상에도 좋지 않을 수 있음
=> <React.Fragment> 사용
-
- Wrapper 태그 생성
const Wrapper = props => {
return props.chilren
}
-
- React.Fragment 사용 - 빈 Wrapper 렌더링
<React.Fragment>
</React.Fragment>
<>
</>
Portals & Refs
Portals
메인 DOM 외부에 앨리먼트 일부를 그리기 위한 기능 (앨리먼트를 다른 돔으로 옮겨 CSS 상속 구조에 영향 받지 않음)
ex) 모달, 사이드 드로워
import ReactDOM from "react-dom";
...
return
<React.Fargment>
// createPortal 함수 사용
// 1. 렌더링 되는 리액트 노드 (JSX 주의)
// 2. 렌더링 되어야 하는 실제 DOM 컨테이너 (실제 HTML DOM요소 - Browser API 사용)
ReactDOM.createPortal(<Backdrop />, document.getElementById('backdrop-root'))
</React.Fargment>
Refs
다른 DOM요소에 접근해 사용 가능
input같은 경우 키 입력마다 state를 변경하는 것은 비 효율적
-> useRef사용
const inputData = useRef()
- 모든 훅과 마찬가지로 함수형 컴포넌트에만 사용 가능
- 사용하고 싶은 태그로 가서 ref 속성 추가
- 어떤 HTML요소라도 하나에 연결 가능
- 반환값으로 객체 전달 -> {변수}.current.value 값 사용
- 입력된 값을 초기화 하고 싶은 경우 유용
Refs값을 재설정 하는 방법
-
Ref 변수를 직접 변경
-
stateHandler함수로 state 변경
단순히 값을 변경하는 것으로 Ref 변수를 직접 변경하는 것을 추천
제어 컴포넌트 vs 비제어 컴포넌트
React에 의해 값이 제어되는 입력 폼 엘리먼트 “제어 컴포넌트 (controlled component)“ ex) input, textarea, select
// 제어 가능한 컴포넌트 -> 항상 최신값으로 유지
<input type="text" value={title || ''} onChange={titleChangeHandler} />
// 비 제어 컴포넌트 -> 필드에서 값을 트리거해 값 사용
<input id="age" type="number" ref={ageInputRef} />
제어 가능한 컴포넌트 -> 항상 최신값으로 유지
비 제어 컴포넌트 -> 필드에서 값을 트리거해 값 사용
기능 | 제어 컴포넌트 | 비제어 컴포넌트 |
---|---|---|
일회성 정보 제출 | O | O |
제출 시 값 검증 | O | O |
실시간 필드 값 검사 | O | X |
조건부로 제출 버튼 비 활성화 | O | X |
실시간 입력 형식 적용 | O | X |
동적 입력 | O | X |
Tip!!
npm error 날 경우
$ npm cache clean --force
$ rm -rf node_modules package-lock.json
$ npm install
객체에 Number 저장
간혹가다 숫자로 객체를 생성하려다가 문자열로 생성되는 경우가 있는데
+를 붙여줘 형변환이 일어나게 저장하면 문제 해결 가능
const data = {
name : name,
age : +age
date : date
}
함수에 언더스코어(_)를 붙여서 만듬
-> 이유는, 리액트는 자체 기능이 많기 때문에 리액트 자체기능과 구분하기 위해서