드디어 프론트엔드 개발의 꽃이라는 React를 배운 첫 날.
처음 배우는 개념치고는 아직까진 재미있다. 리액트는 앞으로도 계속, 자주 사용하게 될 기능인 만큼 제대로 이해하는 것을 목표로 삼았다. 오늘 알아봤던 state 개념과 내일 학습할 LifeCycle 등 리액트의 전반적인 작동원리를 머릿속에 체계적으로 정리할 수 있게 하는 것이 이번 주말까지의 목표!😎
React.createElement
를 이용해서 개발하면 된다.{}
)로 감싸주어야 한다.function App() {
const username = 'ㅇㅅㅇ';
return (
<div>{username}</div>
)
}
import
를 이용해 컴포넌트를 불러오고, 파일의 하단에서 export defalult
구문을 사용해 컴포넌트를 내보내는 방식으로 사용한다.// TweetList.js
import React from 'react';
function TweetList() {
return (
{/*내용 생략*/}
)
}
export default TweetList; // TweetList 컴포넌트를 내보낸다.
// App.js
import TweetList from './components/TweetList'; // TweetList 컴포넌트를 불러온다
function App() {
return (
<TweetList />
)
}
export default App; // App 컴포넌트를 내보낸다.
<React.Fragment>...</React.Fragment>
또는 <>...</>
와 같이 표기할 수 있다. (후자의 경우 아직까지 지원하는 브라우저가 제한되어 있으므로 범용적인 사용을 위해서는 첫번째 방식으로 작성하는 것을 권장한다.)<Tweet>나의 새 트윗</Tweet>
이라는 컴포넌트 사용 방법이 있다고 가정할 때, 컴포넌트 내에서 나의 새 트윗이라는 문자열은 어떻게 접근할 수 있나요?props.children
을 이용하면 컴포넌트 태그 사이에 넣은 값을 조회할 수 있다.// App.js
return (
<Tweet>나의 새 트윗</Tweet>
);
// Tweet.js
function Tweet({ children }) {
return (
<div>{children}</div>
);
}
const tweet = <Tweet writer="김코딩">
{
if (nowLearning) {
return '리액트'
} else {
return '배틀그라운드'
}
}는 늘 짜릿하네요
</Tweet>
const tweet = <Tweet writer="김코딩">
{ nowLearning ? '리액트' : '배틀그라운드' }는 늘 짜릿하네요
</Tweet>
map()
을 사용한다. map()은 배열안에 있는 각 원소를 변환하여 새로운 배열을 만들어주는 함수이다. 우리는 이 함수를 이용해 데이터 배열을 리액트 엘리먼트로 이루어진 배열로 변환해주는 방식으로 배열을 렌더링한다.// TweetList.js
/* 배열의 원소 한개에 해당하는 컴포넌트 */
function SingleTweet({ data }) {
const { username, message } = data;
return (
<div>
<span>{username}</span>
<p>{message}</p>
</div>
);
}
/* 배열 전체를 렌더링해주는 컴포넌트 */
function TweetList( { datas } ) {
return (
<div>
{
datas.map(
data => (<SingleTweet data={data} key={data.id} />)
)
}
</div>
)
}
왜 이런 경고가 발생하는 걸까요?
key
라는 props를 설정해주지 않았기 때문에 발생하는 것이다.key
라는 props 를 설정해야한다. key
값은 각 원소들마다 가지고 있는 고유값으로 설정한다. (보통 배열 안의 각 원소의 고유 id값이 key
값이 된다.) 리액트에서 key
라는 props를 설정해주라고 경고 메시지까지 띄워가며 강제하는 이유는 각 고유 원소에 key 가 있어야만 배열이 업데이트 될 때 효율적으로 렌더링 될 수 있기 때문이다. 고유한 key를 가질 경우, 수정되지 않는 기존의 값은 그대로 두고 원하는 곳에 내용을 삽입하거나 삭제하는 방식으로 업데이트가 이루어진다. (만약에 배열안에 중복되는 key 가 있을 때에는 렌더링시에 오류메시지가 콘솔에 나타나게 되며, 업데이트가 제대로 이루어지지 않는다.)props
는 부모 컴포넌트가 자식 컴포넌트에게 주는 값이다. 자식 컴포넌트에서는 부모 컴포넌트로부터 props
를 받아올 뿐, 받아온 props
를 직접 수정할 수 는 없다. props
는 immutable하다.state
는 컴포넌트 내부에서 선언하며 내부에서 값을 변경할 수 있다. 때문에 동적인 데이터를 다룰 때 state
를 사용한다.this.setState
라는 함수를 사용한다. state = {
id: 0,
name: 'Heeseung',
age: 20,
}
setState
는, 객체로 전달되는 값만 업데이트 해준다.state
값이 있을 때 this.setState({ age: 21 });
을 하게 된다면, id와 name은 그대로 남고, age 값만 업데이트 된다.state = {
id: 0,
name: 'Heeseung',
age: {
koreanAge: 21,
commonAge: 19,
},
}
setState
는 객체의 깊이가 깊어지면 확인하지 못한다. 때문에 깊이가 한 단계 이상일 경우 Spread syntax를 사용해주어야 한다.state.age.commonAge
만 20으로 바꾸고 싶다면 다음과 같이 작성해주어야 한다.this.setState({
id: 0,
name: 'Heeseung',
age: {
...this.state.age,
commonAge: 19,
},
});
+) 210325 추가
this.setState
의 전달 인자로는 객체나 함수 둘 다 사용할 수 있다.this.setState
를 사용하는 함수 내에서 상태는 즉시 갱신되지 않는다.render
method 내에서 setState
method를 실행시킨다면 Stack overflow 에러가 발생한다.this.setState
를 사용하지 않으면 컴포넌트는 새로운 값을 렌더링하지 않는다.state
에 있는 값을 바꾸기 위해서는, this.setState
를 무조건 거쳐야 한다. 직접 this.state를 할당하거나, this.state의 키값을 수정할 경우 리액트는 컴포넌트를 업데이트 시키지 않는다. 때문에 컴포넌트를 업데이트 시키려면 this.setState를 사용해야 한다.<button onClick={onClick}>클릭</button>
이벤트 이름을 설정할 때 camelCase로 설정해주어야 한다.
(onclick ❌ ➡ onClick ⭕, onchange ❌ ➡ onChange ⭕ 등)
이벤트에 전달해주는 값은 함수이어야 한다.
(만약 onClick={this.handleIncrease()}
와 같이 함수 실행을 전달해 줄 경우, 렌더링을 할 때마다 해당 함수가 호출되는 불상사가 벌어진다.)
bind()
함수를 사용해야 한다.const onRemove = (id) => {
setDatas(datas.filter(data => data.id !== id));
};
// 화살표 함수 사용 방법
<button onClick={ () => onRemove(id) }>삭제</button>
// bind() 사용 방법
<button onClick={ onRemove.bind(this, id) }>삭제</button>
this.handleClick = this.handleClick.bind(this);
// 또는
<button onClick={this.handleClick.bind(this)}>
this.setState
의 this
는 더 이상 컴포넌트 인스턴스를 가르키지 않는다.* 때문에 this
가 컴포넌트 인스턴스를 가리키도록 이벤트 핸들러 함수에 bind
를 사용해서 해당 함수에서 가르킬 this
를 설정해주는 것이다.* 이벤트 핸들러를 this binding 없이 호출할 때에, 에러가 나는 이유
: this는
undefined
혹은, window 객체이기 때문에setState
함수가 존재하지 않는다.