react app 퀵스타트
npx create-react-app my-app //my-app 디렉토리에 React 프로젝트 생성
cd my-app
npm start //프로젝트 실행
JSX를 쓰는 이유
JSX는 컴파일링 되면서 최적화되므로 빠르다.
Type-safe (어떠한 연산도 정의되지 않은 결과를 내놓지 않는 것. 즉, 예측 불가능한 결과를 나타내지 않는 것) 하며
컴파일링 과정에서 에러를 감지 할 수 있다.
HTML에 익숙하다면, JSX를 사용하여 더 쉽고 빠르게 템플릿을 작성 할 수 있다.
JSX를 사용하지 않고 React를 사용할 수 있으나
React.createElement()등의 메서드를 사용해야하고, 쓰는 경우보다 번거롭다.
createElement()를 사용한 예시 위아래 결과는 같다.
const element = (
<h1 className="greeting">
Hello, world!
</h1>
);
또는
const element = React.createElement(
'h1',
{className: 'greeting'},
'Hello, world!'
);
JSX 규칙
1.반드시 하나의 엘리먼트로 감싸야 한다.
<div className='root'>안에 다담기</div>
2.JS코드를 적용할 땐 {}안에 작성한다.
3.JSX내부에서 if문을 사용할 수 없다. IIFE나 삼항연산자를 사용해야한다.
4.엘리먼트의 클래스 이름을 적용할 때, className을 사용한다.
*어트리뷰트에 JavaScript 표현식을 삽입할 때 중괄호 주변에 따옴표를 입력하지 말자.
따옴표(문자열 값에 사용) 또는 중괄호(표현식에 사용) 중 하나만 사용하고, 동일한 어트리뷰트에 두 가지를 동시에 사용하면 안 된다.
const element = <img src={user.avatarUrl}></img>;
이렇게 써야 한다)
let user={avatarUrl: 'url'};
const element = <img src={...user}></img>;
또는 이렇게)
**React는 매우 유연하지만 한 가지 엄격한 규칙이 있습니다.
React 컴포넌트는 자신의 props를 다룰 때 반드시 순수 함수처럼 동작해야 합니다.
순수함수란 function(a,b)=>a+b 처럼 입력값을 바꾸려하지 않고 항상 동일한 입력값에 대해 동일한 결과를 반환하기 때문.
return을 a+b+c;로하면 외부의 요인으로
출력값이 바뀌므로 순수함수가 아니게 된다.
return하기 전에 인자로 받은 a, b의 값이 함수내에서 변화되어 출력값에 영향을 줄 경우도
순수함수가 아니다.
*모든 엘리먼트들은 유일해야 한다.
엘리먼트를 배열에 넣고 map()을 사용할 때 반드시 key={number} 이런 형식으로 유일한 key 값을 넣어주어야 한다.
그렇지 않으면 에러가 발생한다.
key prop은 사용하지 않지만 기본적으로 react 내부에서 사용하는 것이라서 뜨는 것이다.
*데이터는 기본적으로 위에서 아래로 흐른다.
부모에서 자식으로. (top-down)
*같은 레벨에 있는 형제 컴포넌트끼리는 상호작용을 할 수 없다!
예를들어 '부모'아래에 '자식1'과 '자식2'가 존재한다고 했을 때,
자식1의 상태가 변경되었을 때, 자식1에서 자식2의 상태를 변경시킬 수 없다.
자식1의 상태가 변경되었을 때 자식2의 상태도 변경시키려면
부모에서 자식들의 상태들을 관리해야하고,
자식1에서 부모에게 상태를 변경시켜달라는 요청이 왔을 때(부모의 setState()를 호출시켰을 때)
부모에서 상태를 변경하고, 변경된 상태를 다시 자식들에게 보내주는 것으로 구현할 수 있다.
공통된 부모에서 상태관리를 하고 이벤트 발생시 부모의 setState()를 호출하는 방법은
아래 링크에서 자세하게 확인할 수 있다.
State 끌어올리기
함수형 컴포넌트
리턴문에 엘리먼트들을 감싸는 가장 바깥의 큰 엘리먼트를 써준다.
function SingleTweet(tweet){
return <li className="tweet" key={tweet.uuid}>
<div className="id">{tweet.name}</div>
<div>{tweet.text}</div>
<div>{tweet.date}</div>
</li>
}
클릭 이벤트 처리
const VideoListEntry = (props) => {
function handleClick(){ //이벤트 핸들링 메서드
props.handleChange({
id:{
videoId:props.video.id.videoId
},
snippet:{
title: props.video.snippet.title,
description: props.video.snippet.description,
thumbnails:{
default:{
url:'https://www.youtube.com/embed/'+props.video.id.videoId
}
},
},
})
}
return <div className="video-list-entry">
<div className="media-left media-middle">
<img className="media-object" src={props.video.snippet.thumbnails.default.url} alt="" />
</div>
<div className="video-list-entry-title" onClick={handleClick}>{props.video.snippet.title}</div> <!-- 이벤트핸들링메서드 등록 -->
</div>
};
클래스 컴포넌트
React.Component 객체를 상속받아야 하고, 그 메서드를 사용해야 한다. (lifecycle이 제대로 돌아가기 위함)
함수형 컴포넌트에서 return 에 해당하는 부분이 render() 메서드가 된다.
class Twittler extends React.Component {
constructor(props){
super(props);
this.state = {
tweets: [],
value: '',
id:''
};
}
render(){
return <div>
<img src={logo} className="App-logo" alt="logo" />
<div>작성자<input id="new-tweet-id" onChange={this.handelIdChange}/></div>
</div>
}
클릭 이벤트 처리
this를 바인딩해주지 않으면 엘리먼트를 클릭했을 때 핸들링 메서드 내에서 this는 window 객체나 undefined가 할당되기 때문에
의도대로 작동하지 못한다. window 객체나 undefined에 내가 작성한 이벤트핸들링 메서드를 찾을 수 없다고 에러가 난다.
class Twittler extends React.Component {
constructor(props){
super(props);
this.state = {
tweets: [],
value: '',
id:''
};
this.handleSubmit = this.handleSubmit.bind(this); //생성자에 이벤트 핸들링 메서드에 this 바인딩
}
handleSubmit(){ //이벤트 핸들링 메서드
let newtweets = this.state.tweets.concat(
[{uuid: this.state.tweets.length,
name: this.state.id,
text: this.state.value,
date: (new Date()).toLocaleTimeString()
}]);
this.setState({tweets: newtweets, value:''})
document.querySelector("#new-tweet-content").value='';
}
render(){
return <div>
<img src={logo} className="App-logo" alt="logo" />
<div>작성자<input id="new-tweet-id" onChange={this.handelIdChange}/></div>
<div id="writing-area">
<textarea id="new-tweet-content" onChange={this.handelChange} onKeyPress={this.handleKeyPress} ></textarea>
<button id="submit-new-tweet" onClick={this.handleSubmit}>새 글 쓰기</button> //이벤트 핸들링메서드를 엘리먼트에 등록.
</div>
</div>
}
}
props
HTML 엘리먼트나, 리액트 컴포넌트를 사용할 때 props라는 키워드를 사용해서 해당 객체의 프로퍼티를 사용할 수 있다.
예를들어
<div name="jjanddak">짱닥</div>
라는 엘리먼트가 있을 때,
prop.name === 'jjanddak'이 된다.
태그 내부의 텍스트(textContent)는 prop.children === '짱닥' 이다.
하지만 객체자체를 props로 넘길 순 없다.
const element = <img src={name:'kim'}></img>; // X
state vs props
props는 외부에서 지정한 속성.
state는 내부에서 지정한 속성. ex) vertical-align: middle;
state
state는 클래스 컴포넌트에서 사용할 수 있는 상태값(프로퍼티)로 컴포넌트 내부에 저장해서 변경한다.
변경할 때는 this.state = someState; 이런식으로 직접 할당해선 안되고
반드시 setState() 메서드를 사용해서 변경해주어야 한다.
setState()메서드를 사용하는 이유는 React 컴포넌트의 Lifecycle 안에서 상태를 변경시키기 위함이다.
클래스 컴포넌트 내부에 메서드를 만들고, 메서드 안에서 setState()를 사용할 때,
setState() 아랫줄에 console.log(this.state)를 띄워보면 state가 setState() 호출후에 바로 변경되지 않는것을 확인할 수 있다.
setState()의 특징
- this.state를 할당할 수 있는 곳은 constuctor 뿐이다
- this.setState의 전달 인자로는 객체나 함수 둘 다 사용할 수 있다
- this.setState를 사용하는 함수 내에서 상태는 즉시 갱신되지 않는다
- this.setState를 사용하지 않으면 컴포넌트는 새로운 값을 렌더링하지 않는다
- this.setState를 사용하는 이유는 lifecycle과 밀접하게 관련이 있다
아래 링크에서 상태값 변화를 확인해볼 수 있다.
codesandbox.io/s/using-components-methods-z1yow?file=/src/App.js
Lifecycle
컴포넌트에서 비동기 요청을 수행해야할 때가 있는데
비동기 요청은 constructor나 render()에서 호출할 수가 없다.
*비동기 요청은 componentDidMount(), componentDidUpdate() 메서드 내에서 호출하여 사용한다. *(React.Component의 메서드임) **
componentDidMount()는 컴포넌트가 생성되었을 때 호출된다.
componentDidUpdate()는 컴포넌트의 상태값이 변화해서 setState()메서드가 호출되면 호출된다.
onClick 메서드 내에서 setState를 사용할 때 호출 순서는 이렇다.
1.onClick에 등록된 메서드가 호출 됨.
2.onClick 내에서 setState를 사용해서 상태가 Update 되면
3.componentDidUpdate()가 호출된다.
아래 링크에서 component~() 메서드들이 언제 작동되는지 확인해볼 수 있다. (콘솔창을 잘 보자)
codesandbox.io/s/using-components-methods-z1yow?file=/src/App.js
'JavaScript' 카테고리의 다른 글
알고리즘 풀이 노션링크 (0) | 2021.03.08 |
---|---|
Common JS (+이벤트루프) (0) | 2020.11.22 |
module.exports vs exports (0) | 2020.11.16 |
arr.every() (부분집합 구하기) (0) | 2020.11.14 |
간단한 트리 DFS 깊이우선탐색 구현 (0) | 2020.11.10 |
댓글