-> 삼항 연산자 (조건부 연산자)로 !!
-> if는 따로 안 써줌
: 일정 시간 후 코드를 비동기적으로 실행
-> 타이머를 사용했으면 클리어도 꼭 해줘야 함! 클리어하기 위해선, setTimeout의 반환값을 가지고 clearTimeout을 호출해야 합니다.
** class hook으로 변환 방법
: class이름, state들 const로 use 사용해서 변경-> return -> 각 함수들 const로 화살표 함수로 표현 -> this.state 없애줌 (setResult..etc) hook 사용하기!
-> 예전 state를 참고할 때!! prevState아니고!!!
import React, { Component } from 'react';
class ResponseCheck extends Component {
state = {
state: 'waiting',
message: '클릭해서 시작하세요.',
result: [],
};
timeout;
startTime;
endTime;
onClickScreen = () => {
const { state } = this.state;
if (state === 'waiting') {
timeout.current = setTimeout(() => {
this.setState({
state: 'now',
message: '지금 클릭',
});
this.startTime = new Date();
}, Math.floor(Math.random() * 1000) + 2000); // 2초~3초 랜덤
this.setState({
state: 'ready',
message: '초록색이 되면 클릭하세요.',
});
} else if (state === 'ready') { // 성급하게 클릭
clearTimeout(this.timeout);
this.setState({
state: 'waiting',
message: '너무 성급하시군요! 초록색이 된 후에 클릭하세요.',
});
} else if (state === 'now') { // 반응속도 체크
endTime.current = new Date();
this.setState((prevState) => {
return {
state: 'waiting',
message: '클릭해서 시작하세요.',
result: [...prevState.result, this.endTime, this.startTime],
};
});
}
};
onReset = () => {
this.setState({
result: [],
});
};
renderAverage = () => {
const {result} = this.state;
return result.length === 0
? null
: <>
<div>평균 시간: {result.reduce((a, c) => a + c) / result.length}ms</div>
<button onClick={this.onReset}>리셋</button>
</>
};
render() {
const { state, message } = this.state;
return (
<>
<div
id="screen"
className={state}
onClick={this.onClickScreen}
>
{message}
</div>
{this.renderAverage()}
</>
)
}
}
export default ResponseCheck;
import React, { useState, useRef, useCallback, useMemo } from 'react';
const ResponseCheck = () => {
const [state, setState] = useState('waiting');
const [message, setMessage] = useState('클릭해서 시작하세요.');
const [result, setResult] = useState([]);
const timeout = useRef(null);
const startTime = useRef(0);
const endTime = useRef(0);
const onClickScreen = useCallback(() => {
if (state === 'waiting') {
timeout.current = setTimeout(() => {
setState('now');
setMessage('지금 클릭');
startTime.current = new Date();
}, Math.floor(Math.random() * 1000) + 2000); // 2초~3초 랜덤
setState('ready');
setMessage('초록색이 되면 클릭하세요.');
} else if (state === 'ready') { // 성급하게 클릭
clearTimeout(timeout.current);
setState('waiting');
setMessage('너무 성급하시군요! 초록색이 된 후에 클릭하세요.');
} else if (state === 'now') { // 반응속도 체크
endTime.current = new Date();
setState('waiting');
setMessage('클릭해서 시작하세요.');
setResult((prevResult) => {
return [...prevResult, endTime.current - startTime.current];
});
}
}, [state]);
const onReset = useCallback(() => {
setResult([]);
}, []);
const renderAverage = () => {
return result.length === 0
? null
: <>
<div>평균 시간: {result.reduce((a, c) => a + c) / result.length}ms</div>
<button onClick={onReset}>리셋</button>
</>
};
return (
<>
<div
id="screen"
className={state}
onClick={onClickScreen}
>
{message}
</div>
{renderAverage()}
</>
);
};
export default ResponseCheck;
setTimeout hook로 바꾸는 방법: ref로!!!
-> endtime.current 이런식으로, ref를 사용해 current로 접근해주면 된다!!
컴포넌트 마운트 시 기본값을 가지고 생성, 변경 가능-보통 유저 이벤트 통해서 변경, 바뀌면 return 부분다시 렌더링 (return 실행)
1. 직접 state 값 변경: constructor에서만 가능 (렌더링x)
2. setState()를 사용해서 state가 변경 (렌더링)
바뀌어도 렌더링 안됨 (return 실행 안됨)
--> 바뀌어도 렌더링 되지 않게 하고 싶으면 (화면에 영향 주고 싶지 않으면), ref에 넣어!! (useRef는 화면에 영향주지 않음)
!!ref는 무조건 current로 접근!!
---> 즉 state는 변경 시 즉시 렌더링이 되어야하는 값들을 다룰 때 사용, ref는 렌더링을 발생시키지 않아도 되는 값을 다룰 때 사용.
-> 코드가 복잡해져서 그렇게 잘 쓰지 않음
(조건문은 삼항연산자, 반복문은 map으로 사용!!)
-> 사용하는 경우에는, 즉시 실행 화살표 함수 만들어주기!!
*배열을 return 하는 경우: key를 넣어줘야 함
⭕ 정리:
리액트 조건문은 삼항연산자로!! props는 부모 컴포넌트로부터 값을 전달 받음, ref는 dom에 이름 지정해주는 것 렌더링 안되는 값 다룰때, state는 setState로 값 변경 가능한데, 그럴 때마다 렌더링되므로 렌더링 필요한 값 다룰 때 사용. setTimeout은 반응 속도를 체크해주기 위한 함수이다. clear도 꼭 해주어야 한다는 것!!!