Today I Learned ... react.js
🙋♂️ React.js Lecture
🙋 My Dev Blog
React Lecture CH 4
1 - 리액트 조건문
2 - setTimeout (반응속도게임)
3 - 성능체크
4 - 반응속도게임 (Hooks)
5 - return 내부에 for, if 사용(제어문)-
import React, { Component } from 'react';
class ResponseCheck extends Component {
state = {
state: 'wating',
message: '클릭해서 시작하세요',
results: [],
};
onClickScreen = () => {};
render() {
return (
<>
<div
id="screen"
className={this.state.state}
onClick={this.onClickScreen}
>
{this.state.message}
</div>
<div>
평균 시간:{' '}
{this.state.results.reduce((prev, cur) => prev + cur) /
this.state.results.length}
ms
</div>
</>
);
}
}
export default ResponseCheck;
map
을 이용하고, if(조건문)대신 삼항 연산자
나 단축평가(&&)를 이용한다.results
가 빈 배열이라 reduce를 할수 없음)<div>
반환하게.undefined
, false
, null
은 태그가 없음을 의미함!-> 삼항 연산자 이용
{this.state.results.length === 0 ? null : (
<div>
평균 시간:
{this.state.results.reduce((prev, cur) => prev + cur) /
this.state.results.length}
ms
</div>
)}
❗️ 참고
빈 배열 []는 Falsy value가 아니다.!![]
는 false지만, 조건식으로 사용시true
이다.
-> 따라서, 위에서는results.length === 0
을 조건으로 해야한다!
참고 - 2
- 삼항연산자 ( ? : ) 말고도 단축평가 (&&)도 사용 가능
- 좌항이 false면 false 리턴 / true면 우항의 값 리턴.
{this.state.results.length === 0 && ( <div> 평균 시간: {this.state.results.reduce((prev, cur) => prev + cur) / this.state.results.length} ms </div> )}
import React, { Component } from 'react';
class ResponseCheck extends Component {
state = {
state: 'wating',
message: '클릭해서 시작하세요',
results: [],
};
onClickScreen = () => {};
renderAverage = () => {
const { results } = this.state; // this.state.results는 너무 길어서 가독성 X - 구조분해로 줄여줌
return results.length === 0 ? null : (
<div>
평균 시간:
{results.reduce((prev, cur) => prev + cur) /
results.length}
ms
</div>
);
};
render() {
const { state, message } = this.state;
return (
<>
<div id="screen" className={state} onClick={this.onClickScreen}>
{message}
</div>
{this.renderAverage}
</>
);
}
}
export default ResponseCheck;
onClickScreen = () => {
const { state, message, results } = this.state;
if (state === 'wating') { // waiting 상태일때 클릭시
this.setState({
state: 'ready', // ready로 변경후, message 변경
message: '초록색이 되면 클릭하세요.',
});
setTimeout(() => { // 2-3초 후에 now로 변경 후, message 변경
this.setState({
state: 'now',
message: '지금 클릭',
});
}, Math.floor(Math.random() * 1000) + 2000); // 2sec-3sec 사이 랜덤으로
} else if (state === 'ready') {
// 너무 빠릅니다 라는 문구 뜨게
} else if (state === 'now') {
// 클릭시 시간 뜨게
}
};
import React, { Component } from 'react';
class ResponseCheck extends Component {
state = {
state: 'waiting',
message: '클릭해서 시작하세요',
results: [],
};
onClickScreen = () => {
const { state, message, results } = this.state;
if (state === 'waiting') {
this.setState({
state: 'ready',
message: '초록색이 되면 클릭하세요.',
});
setTimeout(() => {
this.setState({
state: 'now',
message: '지금 클릭',
});
}, Math.floor(Math.random() * 1000) + 2000); // 2sec-3sec 사이 랜덤으로
} else if (state === 'ready') {
this.setState({
state: 'waiting',
message: '너무 빠릅니다. 초록색이 된 후에 클릭하세요.',
});
} else if (state === 'now') {
this.setState({
state: 'waiting',
results: [], // 추후 수정 (result 추가하는것)
message: '클릭해서 시작하세요.',
});
}
};
renderAverage = () => {
const { results } = this.state;
return results.length === 0 ? null : (
<div>
평균 시간:
{results.reduce((prev, cur) => prev + cur) / results.length}
ms
</div>
);
};
render() {
const { state, message } = this.state;
return (
<>
<div id="screen" className={state} onClick={this.onClickScreen}>
{message}
</div>
{this.renderAverage}
</>
);
}
}
export default ResponseCheck;
state
가 'waiting'이 되지만,import React, { Component } from 'react';
class ResponseCheck extends Component {
state = {
state: 'waiting',
message: '클릭해서 시작하세요',
results: [],
};
timeout; // ❕ 1. this.timeout을 선언해줌 (그냥 함수 몸체에 선언하면 됨)
onClickScreen = () => {
const { state, message, results } = this.state;
if (state === 'waiting') {
this.setState({
state: 'ready',
message: '초록색이 되면 클릭하세요.',
});
this.timeout = setTimeout(() => { // ❕ 2. setTimeout함수를 this.timeout에 할당
this.setState({
state: 'now',
message: '지금 클릭',
});
}, Math.floor(Math.random() * 1000) + 2000);
} else if (state === 'ready') {
clearTimeout(this.timeout); // ❕ 3. clearTimeout() 해줌
this.setState({
state: 'waiting',
message: '너무 빠릅니다. 초록색이 된 후에 클릭하세요.',
});
} else if (state === 'now') {
this.setState({
state: 'waiting',
results: [...results], // 수정
message: '클릭해서 시작하세요.',
});
}
};
...
왜 미리
this.timeout
을 선언해두었는지?
- 만약 if문 안에서 timeout변수를 선언했다면 중복선언 불가이고,
클래스의 프로퍼티(this.timeout)로 사용하려면, 클래스 내부(=몸체)에서 선언해야함.
✅ 참고
- 여기서 시작시간과 종료시간도 변하는 값이지만,
렌더링이 일어날 필요는 없으므로 state가 아닌, 프로퍼티로 선언하기!- state가 바뀌면 다시 렌더링이 되지만, 프로퍼티는 바뀌어도 리렌더링 ❌
- 렌더링이 일어나야 하는 것은? -
state
로- 렌더링이 필요없는 변수는? - this.~~ (프로퍼티)로
import React, { Component } from 'react';
class ResponseCheck extends Component {
state = {
state: 'waiting',
message: '클릭해서 시작하세요',
results: [],
};
timeout;
startTime;
endTime;
onClickScreen = () => {
const { state, message, results } = this.state;
if (state === 'waiting') {
this.setState({
state: 'ready',
message: '초록색이 되면 클릭하세요.',
});
this.timeout = setTimeout(() => {
this.setState({
state: 'now',
message: '지금 클릭',
});
this.startTime = new Date();
}, Math.floor(Math.random() * 1000) + 2000); // 2sec-3sec 사이 랜덤으로
} else if (state === 'ready') {
clearTimeout(this.timeout);
this.setState({
state: 'waiting',
message: '너무 빠릅니다. 초록색이 된 후에 클릭하세요.',
});
} else if (state === 'now') {
this.endTime = new Date();
this.setState((prevState) => {
return {
state: 'waiting',
message: '클릭해서 시작하세요.',
results: [...prevState.results, this.endTime - this.startTime], // push말고 spread를 써야함. (원본 변경 X)
};
});
console.log(this.startTime, this.endTime, this.state.results);
}
};
renderAverage = () => {
const { results } = this.state;
return results.length === 0 ? null : (
<div>
평균 시간:
{results.reduce((prev, cur) => prev + cur) / results.length}
ms
</div>
);
};
render() {
const { state, message } = this.state;
return (
<>
<div id="screen" className={state} onClick={this.onClickScreen}>
{message}
</div>
{this.renderAverage()}
</>
);
}
}
export default ResponseCheck;
Error Breaking 🔨
- 처음에 JSX 부분에 {this.renderAverage} 라고만 작성했었는데,
- 함수이름 적기만 하니 함수 실행이 안된다.
- 고로, 리턴값이 없다.
- 반드시 호출부 ()와 함께 적어줘야 리턴값인 JSX가 나오게 된다.