들어가기 앞서 간단한 용어 정리^^,~,,
- JSON: JavaScript Object Notation의 축약어로 데이터를 저장하거나 전송할 때 많이 사용되는 경량의 DATA 교환 형식 ➡️ 데이터를 텍스트 형식으로 저장하고, XML의 대안으로 고안되었다. (종료태그여부, 구문 길이, 속도 등)
- XML: 사람과 기계가 읽을 수 있는 형식으로 문서를 인코딩하기 위한 규칙 집합을 정의하는 마크업 언어로, 데이터를 텍스트 형식으로 저장한다.
➡️ JSON 표현식이 사람과 기계 모두 이해하기 쉽고 용량이 작아서 최근에는 JSON이 XML을 대체해서 데이터 전송에 많이 사용된다.- html: 웹페이지 및 웹 응용 프로그램의 구조를 만들기 위한 표준 마크업 언어
- 바벨: 자바스크립트의 최신 문법 및 사양을 지원하지 않는 브라우저도 쓸 수 있게끔 변환해주는 transcompiler
최대한 성능을 아끼고 편안한 사용자 경험을 제공하면서 구현하고자 개발되었다.
리액트는 프레임워크가 아닌 라이브러리이다. ➡️ 웹/앱의 뷰를 개발하는 라이브러리로 기타 기능은 직접 구현해야 한다.
다른 개발자들이 만든 라이브러리 라우팅 ➡️ 리액트 라우터, Ajax ➡️ Axion, 상태 관리 ➡️ 리덕스 등을 사용하여 빈자리를 채운다.
자신의 취향대로 스택을 설정할 수 있다는 장점이 있지만, 여러 라이브러리를 접해야한다는 단점도 존재한다.
👩🏻💻 DOM(Document Objenct Model)이란?
- 객체로 문서 구조를 표현하는 방법 (HTML or XML)
DOM을 수많은 플랫폼과 웹브라우저에서 사용할 때, "동적 UI에 최적화 되어 있지 않다"는 취약한 단점이 존재한다.
규모가 큰 웹 애플리케이션에서 DOM에 직접 접근하여 변화를 주면 성능 이슈가 발생한다.
➡️ 이벤트가 발생할 때마다 Virtual DOM을 만들고, 다시 그릴 때마다 실제 DOM과 비교하여 전후 상태를 비교한 뒤 변경이 필요한 최소한의 변경사항만 실제 DOM에 반영하여 앱의 효율성과 속도를 개선한다. (Diff 알고리즘)
단, Virtual DOM을 이용한다고 해서 사용하지 않을 때와 비교해서 무조건 빠른 건 아니다. (작업이 매우 단순할 경우에는 오히려 리액트를 사용하지 않는 게 나은 경우도 존재한다!)
➡️ 리액트와 Virtual DOM은 업데이트 처리의 간결성을 제공한다.
컴포넌트를 선언하는 방법에는 두 가지가 있다.
- 클래스형 컴포넌트
- 함수형 컴포넌트
import React, {Component} from 'react';
class App extends Component {
render() {
const name = 'react';
return <div className="react">{name}</div>
}
}
현재는 잘 사용하지 않는다.
import React from 'react';
import './App.css';
function App() {
const name = 'react';
return <div className = "react">{name}</div>
}
export default App;
화살표함수
로 정의한다.클래스형:
함수형:
Hook
을 통해 해결+) Hook이 등장한 이후부터는 함수형 컴포넌트에서도 state, lifeCycle의 대부분의 기능구현이 가능해졌으므로 일반적으로 사용되는 [함수형 컴포넌트 + Hook]을 중심으로 학습해야한다.
state
constructor(props) {
super(props);
this.state = { // 초기 값 설정
monsters: [],
userInput: "",
}
};
class Monsters extneds Component {
state = {
monsters: [],
userInput: "",
}
};
this.state = { monsters: [], userInput: "", }; // 객체 형식
onClick = {()=>{
this.setState({number:number+1});
}}
const [현재상태, 함수] = useState(''); // [현재상태, 상태를 바꾸는 함수]
import React, { useState } from 'react';
const Counter = () => {
const [value, setValue] = useState(0); // 현재 0
return (
<div>
<p>
현재 카운터 값은 <b>{value}</b> 입니다.
</p>
<button onClick={() => setValue(value + 1)}>+1</button>
<button onClick={() => setValue(value - 1)}>-1</button>
</div>
);
};
useState는 반환값 두 개를 찾는다. (현재상태, 함수 ➡️ 여기서는 value, setValue이다.)
state 변수(value)와 해당 변수를 갱신할 수 있는 함수(setValue)를 반환 ➡️ 위의 코드에서는 0, value+-1이므로 클릭 될 때마다 state에 +-1이 수행되어 변수를 갱신한다.
Props
컴포넌트 자체 props를 수정해서는 안 된다. (수정은 state)
➡️ 자식 컴포넌트에서 전달받은 props는 변경이 불가능하고, props를 전달해준 최상위 부모 컴포넌트만 props를 변경할 수 있다.
class MyComponent extends Component {
render() {
const {name, favoriteNumber, children} = this.props;
return (
<div>
안녕하세요, 제 이름은 {name}입니다. <br/>
children 값은 {children} 입니다. <br/>
제가 좋아하는 숫자는 {favoriteNumber} 입니다.
</div>
);
}
}
// App.js
import React from 'react';
import MyComponent from './MyComponent';
function App() {
return (
<MyComponent name="React"/> // name 부분이 props를 설정하는 부분이다.
);
}
export default App;
// MyComponent.js
import React from 'react';
const MyComponent = (props) => {
return <div>테스트 페이지, {props.name}</div>; // name 받아온다.
};
export default MyComponent;
"테스트 페이지, React"가 출력된다.
const MyComponent = ({name, children}) => {
return (
<div>
안녕하세요 제 이름은 {name}입니다. <br/>
children 값은 {children} 입니다. <br/>
</div>
);
};
props와 state 비교
- props와 state 모두 컴포넌트에서 사용 혹은 렌더링할 데이터를 담고 있다.
- props는 부모 컴포넌트에서 설정한다. ➡️ 컴포넌트 자신이 변경할 수 없다.
- state는 컴포넌트 자신이 직접 가지고 있는 값이고, 그 값의 변경도 내부에서 가능하다.
LifeCycle
LifeCycle API
컴포넌트가 DOM 위에 생성될 때 [컴포넌트가 처음 화면에 렌더링]
컴포넌트가 DOM 위에 사라지기 전 [컴포넌트가 화면에 지워짐]
데이터가 변경되어 상태를 업데이트 한 후 [데이터가 변경될 때]
React 컴포넌트 rendering 할 때 나오는 메소드 순서
constructor
componentWillMount (레거시기능?)
render
componenetDidMount
React 상태 값 변경시 나오는 메소드
componentDidUpdate
컴포넌트 제거시 나오는 메소드
componentWillUnmount
LifeCycle API 메소드는 클래스형 컴포넌트에서만 사용이 가능하다. 함수형 컴포넌트에서는 useEffect Hook이 그 역할을 대신한다.
useEffect(() => {
console.log('btn create');
});
해당 코드를 작성한 뒤 리액트 페이지를 새로고침하면 컴포넌트 생성 개수만큼 콘솔이 호출된다.
useEffect(() => {
console.log('btn create');
}, []);
useEffect(() => {
console.log('btn create');
}, [name]);
리액트에서 어떤 컴포넌트는 UI를 표현
하고자 하고, 또 어떤 컴포넌트는 동작하는 로직
을 담고 있는 등 다양한 역할을 하는 컴포넌트로 이루어져 있다.
컴포넌트는 재사용할 수 있는 최소 UI단위이지만 웹에 따라 수행하려고 하는 역할이 복잡하고 다양하다.
➡️ 복잡한 코드를 비슷한 기능을 하는 코드끼리 별도로 관리해야 한다. (관심사의 분리
)
CRA(Create React App) 프로젝트 생성을 하면 해당 파일들이 만들어진다.
node_modules
해당 기능을 브라우저에서 사용하기 위해 번들러
를 사용한다.
번들러?
번들러란 필요한 의존성을 추적하여 해당하는 의존성들을 그룹핑해주는 도구를 말한다.
번들러를 사용하면 import(혹은 require)로 모듈을 불러왔을 때 불러온 모듈을 모두 합쳐 하나의 파일을 생성한다. 번들러에는 webpack, Parcel, browserify 등이 존재하며 리액트에서는 주로 webpack을 이용한다.
webpack을 사용한다면 svg, css파일도 불러올 수 있다.
public
favicon: 로고이미지
index.html: 뼈대가 되는 html 파일
manifest.json: 모바일에서 저장하는 웹 어플리케이션을 만들 때 필요 (웹/앱의 정보가 담겨져있다)
robots.txt: 크롤링을 위해 이용되는 파일
src
.gitignore
package.json
README.md
yarn.lock
자세한 건 CRA 프로젝트 파일 생성 게시글에서...
➡️ 둘 다 자바스크립트 런타임 환경인 Node.js의 패키지 관리자
단 몇 줄의 command로 모듈을 설치하고 활용할 수 있고, 이 모듈들이 업데이트 되었는지를 체크해주는 등 JavaScript로 진행하는 프로젝트를 굉장히 편하게 진행할 수 있도록 도와준다.
npm은 패키지를한 번에 하나씩 순차적으로 설치하는 반면, yarn은 여러 패키지를 동시에 가져오고 설치하므로 yarn이 더 빠르다.
npm은 자동으로 패키지에 포함된 다른 패키지의 코드를 실행한다 ➡️ 이는 편리하지만 안정성을 위협한다.
yarn은 yarn.lock 또는 package.json 파일에 있는 파일만을 설치하며, yarn.lock은 모든 디바이스에 같은 패키지를 설치하는 것을 방지하기 때문에 버전의 차이로 인해 생기는 버그를 방지할 수 있다.
자바스크립트 확장 문법으로 xml과 비슷한 형태이다.
코드가 번들링되는 과정에서 바벨을 사용하여 일반 자바스크립트 형태로 변환한다.
JSX의 특징
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css➡️
import App from './App';
ReactDom.render( // 컴포넌트를 페이지에 렌더링하는 역할. react-dom을 불러와서 사용
<React.StrictMode> // 리액트의 레거시 기능(정상적이지 않은)을 사용하지 못하게 함
<App/>
</React.StrictMode>,
document.getElementById('root')
);
import React from 'react';
function App() {
const name = '리액트';
return <div>{name == '리액트' && <h1>리액트입니다.</h1>}</div>;
export default App;