리액트 기초
1. React란
2. JSX
3. Component
4. Event Handling
5. ref:DOM
6. Component Iterator
7. Life_Cycle
8. Functional Component
List
1.React Feature
O React 는 UI를 만드는 Javascript 라이브러리입니다.
O 페이스북이 자사 서비스의 UI를 효율적으로 만들기 위해 탄생한
라이브러리로 화면에 보이는 버튼이나 텍스트 상자 등을 쉽게 만들수 있는 코드묶음입니다.
Component
UI(또는 View)를 여러 구성요소(Component)를 쪼개서 만듭니다.
버튼, 입력창, 표, 등등 여러 화면에 사용되고 요소들을 만든뒤, 이를
조합해서 화면을 구성하게 됩니다.
컴포넌트는 재사용이 가능한 API로 수많은 기능들을 내장하고 있습니다.
컴포넌트 하나에서 해당 컴포넌트의 생김새와 작동 방식을 정의합니다.
class SearchBar extends React.Comopnent {
render(){
return (
<form>
<input/>
<button type="submit">확인</button>
</form>
);
}
}
class Table extends React.Component{
render(){
return (
<table>
<tr>
<th>제목<th>
<th>Category</th>
</tr>
<tr>
<td>Hello</td>
<td>Message</td>
</tr>
</table>
);
}
}
<body>
<form>
<input/>
<button type="submit">확인</button>
</form>
<table>
<tr>
<th>제목<th>
<th>Category</th>
</tr>
<tr>
<td>Hello</td>
<td>Message</td>
</tr>
</table>
<body>
Virtual DOM
문서 객체 모델(The Document Object Model, DOM) 은 HTML, XML 문서의 프로그래밍 interface이다.
DOM 은 html, xtml, xml 등을 tree구조로 인식하고, 데이터를 Object로 관리합니다. 이렇게 함으로써 DOM은 Javascrupt같은 언어가 html과 상호작용하여 화면을 동적으로 구성할 수 있게끔 해줍니다.
Html 코드작성 > 브라우저 실행 > DOM > 브라우저 표시
Javascript는 DOM을 조작할수 있습니다.
Javascript는 DOM을 조작하여 눈에 보이는 값을 변경하는 등 웹을 동적으로 구성하게 됩니다. 하지만 이렇게 DOM을 조작하는 것은 많은 자원이 소요되며, 너무 조작을 많이 하면 어플리케이션 속도가 떨어지게 됩니다.
브라우저가 HTML 을 전달받으면, 브라우저의 렌더 엔진이 이를 파싱하고 DOM 노드로 이뤄진 TREE를 만듭니다.
그리고, 외부 CSS 파일과 각 엘리먼트의 inline 스타일을 파싱합니다.
Virtual DOM 그림
전전페이지 코드 React.Component 즉 리액트에 컴포넌트들을 등록을 하면 리액트가 현재의 DOM 과 변화하는 부분만 고쳐준다는 이야기이다.
One-Way Data Binding
View는 데이터를 보여주거나, 데이터를 받기위해 사용되는데, 보통 두가지 방법이있습니다.
Subtitle
Parent-Child Component
각 Component 마다 보유한 state는 다른 Component에 영향을 줄 수 있습니다.
2.JSX
JSX
Javascript + XML을 합쳐서 탄생한 기존 자바스크립트의 확장 문법입니다.
개발자가 자바스크립트 내부에 마크업 코드를 작성해 줄 수 있게 해줍니다.
ReactDOM.render(
<h1>Hi Study, Beom</h1>,
document.getElementById('root')
);
const element = <h1>Hello, Beom</h1>;
ReactDOM.render(
element,
document.getElementById('root')
);
JSX는 자바스크립트의 확장 문법으로 작성한 코드는 나중에 코드가 번들링되면서 Babel-loader를 사용하여 자바스크립트로 변환합니다.
이점이 중요한 이유는 결국 컴포넌트를 불러 조립처럼 끼우게 해줄수있는(내부에서 마크업이 가능하기에) 중요한 요점이기도 합니다.
import App from '.App';
React.render(
<App />, document.getElementById('root'));
registerServiceWorker());
Title Text
개발자 경험(developer experience, DX) 개선:
표현력이 뛰어나 코드를 읽기 쉽다.
XML과 문법이 유사하여 중첩된 선언형 구조를 더 잘 나타낸다.
팀의 생산성 향상:
전문 개발자 외에도 개발 지식이 있는 팀원이 있다면 직접 코드를 수정할 수도 있다. JSX는 HTML과 비슷하여 이들에게도 친숙하기 때문이다.
문법 오류와 코드량 감소:
작성해야 할 코드가 줄어들며, 이는 곧 실수나 반복으로 인한 스트레스를 줄여준다.
3.Component
Using props
아까전 본 그림이다.
Props는 프로퍼티의 축약 단어이다 초반에 소개한 그림을 보면 알겠지만 부모컴포넌트는 Props에 정보를 담아 자식 컴포넌트에게
전달할수 있다. 후에 배우겠지만 자식컴포넌트는 부모에게 값을 전달하기위해서 Callback Function을 사용하여 값을 전달하여야한다.
App이 <PostList/>라는 컴포넌트를 가져오려고 한다.
가져와 쓰기위해 해당파일을 import하였으며 렌더링을 통한후에 PostList컴포넌트가 포함된 화면을 볼수있다
import React, { Component } from 'react';
import PostList from './posts/PostList';
class App extends Component {
render() {
return (
<div>
<PostList/>
</div>
);
}
}
export default App;
<PostList/> 의 원폰파일내용이다. PostData는 json파일을 임포트한 객체이며 이를 map을통하여 iterator하려고한다.
맵을통하며 차례대로 iterator할것이며(item) 그에 해당하는 키(index)도 같이 추출할것이다.
그리고 이 함수의 결과를 <PostDetail />컴포넌트에 보내는데... post 와 key라는 이름으로 자식이 정보를 가질수 있게 도와줄것이다.
import React, { Component } from 'react';
import PostData from '../data/posts.json';
import PostDetail from './PostDetail';
class PostList extends Component {
render() {
return (
<div>
<h1>Hello There</h1>
{PostData.map((item, index) => {
return <PostDetail
post={item}
key={index} />
})}
</div>
);
}
}
export default PostList;
post 와 key라는 이름에 값을담아주었으니 지금 PostDetail에서는 값을받아 해결할수 있어야한다.
여기서 맨위에 그림을 보면 알수 있다.
값을 담은 그릇은 props에 담겨있으니 이를 꺼내 자식컴포넌트는 받아 먹으면 된다.
mport React, { Component } from 'react';
class PostDetail extends Component {
render() {
const {post} = this.props
// const post = this.props.post
//둘다 같은 의미이다.
return (
<div>
<h1>{post.title}</h1>
<p>{post.content}</p>
</div>
);
}
}
export default PostDetail;
출력화면이 되겠다.
Callbacks using Props
방금전 그림을 생각하면 this.props를 이용하여 부모가 던지는 값을 자식이 받아 먹을수 있었다.
하지만 자식이 부모한테 값을 주는것은 Callback function 을 이용하기로 하였었다.
다음과 같이 사용하였다.
달라진 구문이 있다면 자식이 dataCallback을 쓸수 있게 <PostDetail 에 담아 주었고 그 콜백함수는
위에 handleDataCallback 이라는 함수를 담아 준다는 내용이다.
import React, { Component } from 'react';
import PostData from '../data/posts.json';
import PostDetail from './PostDetail';
class PostList extends Component {
handleDataCallback(txtMsg){
alert(txtMsg)
console.log(this)
}
render() {
return (
<div>
<h1>Hello There</h1>
{PostData.map((item, index) => {
return <PostDetail
post={item}
key={index}
dataCallback={this.handleDataCallback}
/>
})}
</div>
);
}
}
export default PostList;
this.props를 통해 dataCallback 함수를 가져왔다. 그리고 그 함수의 파라미터로 나는 ("hello 내이름")을 넣었다.
즉 dataCallback("hello beom")은 부모컴포넌트에서 밑에와 같이 실행이 될것이다.
handleDataCallback("hello beom"){
alert("hello beom")
console.log(this)
}
import React, { Component } from 'react';
class PostDetail extends Component {
constructor(props){
super(props)
this.titleWasClicked = this.titleWasClicked.bind(this)
}
titleWasClicked(e){
e.preventDefault()
const {dataCallback} = this.props
dataCallback("hello beom")
}
render() {
const {post} = this.props
return (
<div>
<h1 onClick={this.titleWasClicked}>{post.title}</h1>
<p>{post.content}</p>
</div>
);
}
}
export default PostDetail;
props는 부모 컴포넌트가 설정하며, 컴포넌트 자신은 해당 props를 읽기 전용으로만 사용할수 있습니다.
컴포넌트 내부에서 읽고 또 업데이트할 수 있는 값을 사용하려면 state를 써야합니다.
이것은 언제나 기본 값을 미리 설정해야 사용 할 수 있으며, this.setState() 메서드로만 값을 업데이트해야 합니다.
Convert Prop to a State
import React, { Component } from 'react';
class PostDetail extends Component {
constructor(props){
super(props)
this.titleWasClicked = this.titleWasClicked.bind(this)
this.state ={
showContent: true,
postItem : null
}
}
titleWasClicked(e){
e.preventDefault()
const {dataCallback} = this.props
const newPostItem ={
title: "This is my awsome new title",
content : this.props.post.content
}
this.setState({
postItem : newPostItem
})
}
componentDidMount(){
const {post} = this.props
this.setState({
postItem : post
})
}
render() {
const {postItem} = this.state
const {showContent} = this.state
return (
<div>
{postItem !== null ?
<div>
<h1 onClick={this.titleWasClicked}>{postItem.title}</h1>
<p>{postItem.content}</p>
</div>
:''}
</div>
);
}
}
export default PostDetail;
4.Event Handling
유저가 웹 브라우저에서 DOM 요소들과 상호 작용하는 것을 이벤트(event)라고 합니다.
이벤트를 사용할때 주의사항 입니다.
1. 이벤트 이름은 camelCase로 작성합니다
ex) onclick -> onClick // onkeyup -> onKeyUp
2. 이벤트에 실행할 자바스크립트 코드를 전달하는 것이 아니라 함수 형태의 값을 전달합니다.
화살표 함수문법으로 전달해도 되고, 렌더링 부분 외부에 미리 만들어서 전달해도됩니다.
3. DOM요소에만 이벤트를 설정할수 있습니다.
div, button, form 등 DOM요소에는 이벤트를 설정할수 있지만 우리가 만든 컴포넌트에는 이벤트를 자체적으로 설정할수 없습니다.
<MyComponent onClick={doSomething}/>
//doSomething인 함수를 실행 하는것이아니라, 그냥 이름이 onClick인 props를 MyComponent에게전달해줄뿐이다.
<div onClick={this.props.onClick}>
{/*(...)*/}
</div>
//컴포넌트에 자체적으로 이벤트를 설정할수는 없지만 전달받은 props를 컴포넌트 내부의 DOM 이벤트로 설정할수는 있다.
1.화살표 함수로 전달
import React, {Component} from 'react';
class EventPractice extends Component {
state = {
message:''
}
render() {
return (
<div>
<h1>이벤트연습</h1>
<input
type="text"
name="message"
placeholder="입력하세요"
value={this.state.message}
onChange={
(e) => {
this.setState({
message: e.target.value
})
}
}
>
</div>
)
}
}
2.전달함수 분리
import React, {Component} from 'react';
class EventPractice extends Component {
state = {
message:''
}
handleChange(e) {
this.setState({
message:e.target.value
});
}
render() {
return (
<div>
<h1>이벤트연습</h1>
<input
type="text"
name="message"
placeholder="입력하세요"
value={this.state.message}
onChange={this.handleChange}
>
</div>
)
}
}
6.Component Iterators
Arrow function
화살표 함수 표현은 일반 함수 표현보다 간결하게 함수를 표현할 수 있습니다.
또한, this, arguments, super, new.target을 바인딩하지 않습니다.
화살표 함수는 익명 함수이기 때문에, 메소드가 아닌 함수에 사용하는 것이 적절합니다. 또한 익명 함수이기 때문에 생성자로 사용할 수 없습니다.
기본문법
(param1, param2, …, paramN) => { statements }
(param1, param2, …, paramN) => expression
// 다음과 동일함: => { return expression; }
// 매개변수가 하나뿐인 경우 괄호는 선택사항:
(singleParam) => { statements }
singleParam => { statements }
// 매개변수가 없는 함수는 괄호가 필요:
() => { statements }
고급문법
// 객체 리터럴 식을 반환하는 본문(body)을 괄호 속에 넣음:
params => ({foo: bar})
// 나머지 매개변수 및 기본 매개변수가 지원됨
(param1, param2, ...rest) => { statements }
(param1 = defaultValue1, param2, …, paramN = defaultValueN) => { statements }
// 매개변수 목록 내 구조분해도 지원됨
var f = ([a, b] = [1, 2], {x: c} = {x: a + b}) => a + b + c;
f(); // 6
1. 짧아진 함수
var materials = [
"yun chul seo",
"bora jang",
"kiho",
"Beomy"
];
var materialsLength1 = materials.map(function(material){
return material.length
});
var materialsLength2 = materials.map((material)=>{
return material.length
});
var materialsLength3 = materials.map(material=> material.length);
2. Binding
function Person() {
// Person() 생성자는 `this`를 자신의 인스턴스로 정의.
console.log(this);
setTimeout(function growUp() {
// 비엄격 모드에서, growUp() 함수는 `this`를
// 전역 객체로 정의하고, 이는 Person() 생성자에
// 정의된 `this`와 다름.
console.log(this);
}, 1000);
}
var p = new Person();
Person의 this객체와 growUp의 this객체는 서로 다른 객체입니다.
이러한 문제를 해결하기 위해 함수를 .bind(this) 로 묶어버립니다.
function Person() {
console.log(this);
setTimeout(() => { console.log(this) }, 1000);
}
var p = new Person();
화살표 함수는 this를 생성하지 않습니다.
var numbers = [1, 2, 3, 4, 5];
var processed = numbers.map(function(num){
return num*num;
});
JavaScript – Array.prototype.map
Component
let numbers = [1, 2, 3, 4, 5];
let result = numbers.map((num) => {return num*num});
7.Life Cycle
Mount
DOM이 생성되고 웹 브라우저상에 나타나는 것을 마운트(Mount)라고 합니다.
DOM이 생성되고 웹 브라우저상에 나타나는 것을 마운트(Mount)라고 합니다.
react 공식 홈 에서는 DOM 에 처음으로 렌더링 될때 라고 되어있습니다.
constructor : 컴포넌트를 새로 만들 때마다 호출되는 클래스 생성자 메서드
getDerivedStateFromProps : props에 있는 값을 state에 동기화 하는 메서드입니다.
render : 우리가 준비한 UI를 렌더링하는 메서드입니다.
componentDidMount : 컴포넌트가 웹 브라우저상에 나타난 후 호출하는 메서드 입니다.
componentDidUpdate : 컴포넌트의 업데이트 작업이 끝난 후 호출하는 메서드입니다.
이 메소드는 새로운 객체가 생성될 때 마다 호출됩니다. super(props)은 부모 클래스의 생성자를 호출하며 this.props 로 접근이 가능합니다. 또한, 콜백으로 전달될 함수들을 바인딩 할 때도 사용됩니다. this.setState() 또는 Ajax 요청을 사용하시면 안됩니다.
(componentDidMount()에서 사용)
constructor
이 메소드가 호출되면 this.props와 this.state가 분석되며 리액트 엘리먼트를 리턴합니다. render() 메소드는 state를 변경하면 안되며 브라우저와 직접적으로 상호작용하면 안됩니다. 브라우저와 연동하려면 componentDidMount()안에서 하면 됩니다. shouldComponentUpdate()가 false를 리턴할 경우 발생하지 않습니다.
render()
이 메소드는 전체 라이프사이클에서 한 번만 호출됩니다. 데이터와 관련된 로직을 실행하기에 적합합니다. componentDidupdate()는 prevProps, prevState, snapshot을 파라미터로 가질 수 있습니다. 이 외에도 componentWillUnmount(), componentDidCatch()가 있습니다.
componentDidMount()
리액트 버전 16.4에서 새로운 라이프 사이클 2개가 소개되었습니다. getDerivedStateFromProps, getSnapshotBeforeUpdate 이며 기존에 사용하던componentWillMount, componentWillUpdate, componentWillReceiveProps 는 점차 지원이 중단되어 버전 17에서는 완전히 삭제될 예정이라고 합니다.
웹쪽은 항상 변동되는 API나 라이브러리 정보등을 고려해야하는 부분이 이런부분이 아닐까 싶습니다.
import React, { Component } from 'react';
class LifeCycleSample extends Component {
state = {
number: 0
}
constructor(props) {
super(props);
console.log('constructor');
}
componentWillMount() {
console.log('componentWillMount (deprecated)');
}
componentDidMount() {
console.log('componentDidMount');
}
shouldComponentUpdate(nextProps, nextState) {
// 5 의 배수라면 리렌더링 하지 않음
console.log('shouldComponentUpdate');
if (nextState.number % 5 === 0) return false;
return true;
}
componentWillUpdate(nextProps, nextState) {
console.log('componentWillUpdate');
}
componentDidUpdate(prevProps, prevState) {
console.log('componentDidUpdate');
}
handleIncrease = () => {
const { number } = this.state;
this.setState({
number: number + 1
});
}
handleDecrease = () => {
this.setState(
({ number }) => ({
number: number - 1
})
);
}
render() {
console.log('render');
return (
<div>
<h1>카운터</h1>
<div>값: {this.state.number}</div>
<button onClick={this.handleIncrease}>+</button>
<button onClick={this.handleDecrease}>-</button>
</div>
);
}
}
export default LifeCycleSample;
8.Functional Component
라이프사이클 API와 state를 사용할 필요가 없고, 오로지 props를 전달받아 뷰를 렌더링하는 역할만 한다면 컴포넌트를 더 같단하게 선언할수 있습니다.
import React {Component} from 'react';
class EventPractice extends Component {
render() {
return (
<div>
Hello {this.props.name}
</div>
)
}
}
export default Hello;
import React {Component} from 'react';
function Hello(props) {
return (
<div>Hello {props.name}</div>
)
}
export default Hello;
리액트 프로젝트에서 state를 사용하는 컴포넌트 개수를 최소화하면 좋다.
따라서 컴포넌트 만들때는 대부분 함수형으로 작성하여 state를 사용하는 컴포넌트 개수를 줄이는 방향으로 향하며,
state나 라이프사이클 API를 꼭 써야할때만 클래스 형태로 변환하여 컴포넌트를 작성하면 된다.
import React from 'react';
const Hello = ({name}) => {
return (
<div> Hello {name}</div>
)
}
/*
또는 이런 식으로 {}를 생략할 수도 있다.
const Hello = ({name}) => (
<div> Hello {name}</div>
)
*/
export default Hello;
리액트 기초
By Beom lee
리액트 기초
- 195