function Clock(props) {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {props.date.toLocaleTimeString()}.</h2>
</div>
);
}
class Clock extends React.Component {
render(){
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.props.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
render 메서드는 업데이트가 발생할 때마다 호출
되지만, 같은 DOM 노드로 을 렌더링하는 경우 Clock 클래스의 단일 인스턴스
만 사용된다.
이것은 로컬 state
와 생명주기 메서드
와 같은 부가적인 기능을 사용할 수 있게 해준다.
단일 인스턴스만 사용 ?
인스턴스 ??
인스턴스는 일반적으로 실행 중인 임의의 프로세스, 클래스의 현재 생성된 오브젝트를 가리킨다.
객체(오브젝트)의 인스턴스는 데이터베이스나 SGA, 백그라운드 프로세스등 광범위한 컴퓨터시스템 자원의 접근에 할당된 물리 메모리의 일부를 가리킨다.
class Clock extends React.Component {
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
여기서 어떻게 props를 기본 constructor에 전달하지 ??? 🤔
클래스 컴포넌트는 항상 props로 기본 constructor를 호출해야 한다.
constructor(props) {
super(props);
this.state = {date: new Date()};
}
function tick() {
ReactDOM.render(
<Clock date={new Date()} />,
document.getElementById('root')
);
}
setInterval(tick, 1000);
👇🏻
ReactDOM.render(
<Clock />,
document.getElementById('root')
);
많은 컴포넌트가 있는 애플리케이션에서 컴포넌트가 삭제될 때 해당 컴포넌트가 사용 중이던 리소스를 확보하는 것이 중요하다.
마운팅
, componentDidMount()
:
componentDidMount() {
this.timerID = setInterval(
() => this.tick(),
1000
);
}
언마운팅
, componentWillUnmount()
: Clock에 의해 생성된 DOM이 삭제될 때마다 타이머를 해제 하는 것
componentWillUnmount() {
clearInterval(this.timerID);
}
왜 ?? 다시 렌더링하지 않기에!!
this.state.comment = 'Hello';
대신에 setState()를 사용하기!
// Correct
this.setState({comment: 'Hello'});
this.state를 지정할 수 있는 유일한 공간은 바로 constructor이다.
React는 성능을 위해 여러 setState() 호출을 단일 업데이트로 한꺼번에 처리할 수 있다.
// Wrong
this.setState({
counter: this.state.counter + this.props.increment,
});
// Correct
this.setState((state, props) => ({
counter: state.counter + props.increment
}));
객체보다는 함수를 인자로 사용하는 다른 형태의 setState()를 사용한다.
그 함수는 이전 state를 첫 번째 인자로 받아들일 것이고, 업데이트가 적용된 시점의 props를 두 번째 인자로 받아들일 것이다.
setState()를 호출할 때 React는 제공한 객체를 현재 state로 병합한다.
constructor(props) {
super(props);
this.state = {
posts: [],
comments: []
};
}
별도의 setState() 호출로 이러한 변수를 독립적으로 업데이트할 수 있다!
React에서는 false를 반환해도 기본 동작을 방지할 수 없다.
반드시 preventDefault를 명시적으로 호출해야 한다.
엘리먼트가 처음 렌더링될 때 리스너를 제공하면 된다.
콜백에 화살표함수 사용하면 됨!
class LoggingButton extends React.Component {
handleClick() {
console.log('this is:', this);
}
render() {
// 이 문법은 `this`가 handleClick 내에서 바인딩되도록 합니다.
return (
<button onClick={() => this.handleClick()}>
Click me
</button>
);
}
}
지난 프로젝트 시 생겼던 문제!
리액트에서 함수 연결 할 때는 호출을 하면 안되고 함수 선언을 넘겨야 한다!!
리액트 함수 파라미터 전달 구글링 -> 화살표 함수를 이용하여 원래 부르려던 함수를 감싸고, 해당 함수의 호출부에서 인자를 넘겨주기
const handleDeleteClick = (
params: number | null,
e: React.MouseEvent<HTMLButtonElement, MouseEvent>
) => {
console.log("삭제클릭");
console.log(params);
deleteAdList(params);
};
<Button onClick={(e) => {handleDeleteClick(dailyAd.id, e);}} </Button>
그러나! 여기에도 문제가 있다!!!
이 문법의 문제점은 LoggingButton이 렌더링될 때마다 다른 콜백이 생성된다는 것!!
대부분의 경우 문제가 되지 않으나, 문제 발생하는 경우 ?
엘리먼트를 저장하기 위해 변수를 사용할 수 있다.
출력의 다른 부분은 변하지 않은 채로 컴포넌트의 일부를 조건부로 렌더링 할 수 있다.
if (isLoggedIn) {
button = <LogoutButton onClick={this.handleLogoutClick} />;
} else {
button = <LoginButton onClick={this.handleLoginClick} />;
}
JSX 안에는 중괄호를 이용해서 표현식을 포함 할 수 있다.
그 안에 JavaScript의 논리 연산자 &&를 사용하면 쉽게 엘리먼트를 조건부로 넣을 수 있다.
{unreadMessages.length > 0 &&
<h2>
You have {unreadMessages.length} unread messages.
</h2>
}
true && expression
: 항상 expression
false && expression
: 항상 false
따라서 && 뒤의 엘리먼트는 조건이 true일때 출력이 된다.
조건이 false라면 React는 무시하고 건너뜀.
condition ? true: false
The user is <b>{isLoggedIn ? 'currently' : 'not'}</b> logged in.
렌더링 결과를 출력하는 대신 null을 반환하는 것으로 해결
map()에서 반환하는 새 배열 만들기!
엘리먼트 모음을 만들고 중괄호 {}를 이용하여 JSX에 포함 시킬 수 있다.
const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) =>
<li>{number}</li>
);
ReactDOM.render(
<ul>{listItems}</ul>,
document.getElementById('root')
);
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
<li>{number}</li>
);
return (
<ul>{listItems}</ul>
);
}
const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
<NumberList numbers={numbers} />,
document.getElementById('root')
);
이 코드를 실행하면 리스트의 각 항목에 key를 넣어야 한다는 경고가 표시된다.
주로 나오는 문제 ? key!!!
“key”는 엘리먼트 리스트를 만들 때 포함해야 하는 특수한 문자열 어트리뷰트이다.
왜 인덱스는 최후의 수단이지 ?
키는 주변 배열의 context에서만 의미가 있다.
예를 들어
ListItem 컴포넌트
를 추출 한 경우ListItem
안에 있는<li> 엘리먼트
가 아니라 배열의<ListItem /> 엘리먼트
가 key를 가져야 한다.
경험상 map() 함수 내부에 있는 엘리먼트에 key를 넣어 주는 게 좋다!
JSX를 사용하면 중괄호 안에 모든 표현식을 포함 시킬 수 있으므로 map() 함수의 결과를 인라인으로 처리할 수 있다.
function NumberList(props) {
const numbers = props.numbers;
return (
<ul>
{numbers.map((number) =>
<ListItem key={number.toString()}
value={number} />
)}
</ul>
);
}
map() 함수가 너무 중첩된다면 컴포넌트로 추출 하는 것이 좋다!!