리액트 정리
[React] 웹게임 3. 숫자야구 // ref 리액트에서 DOM에 직접적인 접근을 할 때 본문
컴포넌트의 메소드에서 컴포넌트의 태그에 직접 접근
리액트 개발을 하다보면 DOM 에 직접적인 접근을 해야 할 때가 있습니다. 그럴 때는 ref 라는것을 사용합니다. 그런데 정확히 어떠한 상황에 DOM 에 직접적인 접근이 필요할까요? 필요한 상황은 다음과 같습니다.
- input / textarea 등에 포커스를 해야 할때
- 특정 DOM 의 크기를 가져와야 할 때
- 특정 DOM 에서 스크롤 위치를 가져오거나 설정을 해야 할 때
- 외부 라이브러리 (플레이어, 차트, 캐로절 등) 을 사용 할 때
https://www.zerocho.com/category/React/post/57833e23db96321500e401fe
Q. Reference 접근 할때 에서 ref={(ref) => { this.hide = ref; }} 대신 자바스크립트 DOM 접근 방식인 getElementById 를 사용하면 어떤 문제가 있나요?
-> 리엑트의 메서드를 쓸 수가 없게됩니다
1. Class
- 스트럭쳐
import React, { Component, createRef } from "react";
class NumberBaseball extends Component {
...
this.inputRef.current.focus();
...
inputRef = createRef();
render()
return (
<>
<input ref={this.inputRef}/>
</>
)
}
- 전체코드
import React, { Component, createRef } from "react";
import Try from "./Try";
const getNumbers = () => {
// 숫자 네개를 랜덤하게 뽑는 함수.
const candidate = [1, 2, 3, 4, 5, 6, 7, 8, 9];
const array = [];
for (let i = 0; i < 4; i += 1) {
const chosen = candidate.splice(Math.floor(Math.random() * (9 - i)), 1)[0];
array.push(chosen);
}
return array;
};
class NumberBaseball extends Component {
state = {
result: "",
value: "",
answer: getNumbers(),
tries: [] // 리액트에서는 push 쓰면 안돼요
};
onSubmitForm = e => {
e.preventDefault();
if (this.state.value === this.state.answer.join("")) {
this.setState(prevState => {
return {
result: "홈런!",
tries: [
...prevState.tries,
{ try: this.state.value, result: "홈런!" }
]
};
});
alert("게임을 다시 시작합니다!");
this.setState({
value: "",
answer: getNumbers(),
tries: []
});
this.inputRef.current.focus();
} else {
// 답 틀렸으면
const answerArray = this.state.value.split("").map(v => parseInt(v));
let strike = 0;
let ball = 0;
if (this.state.tries.length >= 9) {
// 10번 이상 틀렸을 때.
this.setState({
result: `10번 넘게 틀려서 실패! 답은
${this.state.answer.join(",")} 였습니다!`
});
alert("게임을 다시 시작합니다!");
this.setState({
// 게임 초기화
value: "",
answer: getNumbers(),
tries: []
});
this.inputRef.current.focus();
} else {
for (let i = 0; i < 4; i += 1) {
// 몇 볼 몇 스트라이크인지 알려주기
if (answerArray[i] === this.state.answer[i]) {
strike += 1;
} else if (this.state.answer.includes(answerArray[i])) {
ball += 1;
}
}
this.setState((prevState) => {
return {
tries: [
...prevState.tries,
{
try: this.state.value,
result: `${strike} 스트라이크, ${ball} 볼입니다`
}
],
value: ""
};
});
this.inputRef.current.focus();
}
}
console.log(this.state.value);
};
onChangeInput = e => {
this.setState({
value: e.target.value
});
};
inputRef = createRef();
render() {
return (
<>
<h1>{this.state.result} </h1>
<form onSubmit={this.onSubmitForm}>
<input
ref={this.inputRef}
maxLength={4}
value={this.state.value}
onChange={this.onChangeInput}
/>
<button>Submit</button>
</form>
<div>시도: {this.state.tries.length} </div>
<ul>
{this.state.tries.map((v, i) => {
return (
// v 는 매번 새로 넣어주는 객체 {try: this.state.value, result:`${strike} 스트라이트, ${ball} 볼입니다`}이것
<Try key={`${i + 1}차 시도: `} tryInfo={v} index={i} />
);
})}
</ul>
</>
);
}
}
export default NumberBaseball;
2. Hooks
- 스트럭쳐
import React, { useState, useRef, memo } from 'react';
inputEl.current.focus();
ref={inputEl}
- 전체코드
import React, { useState, useRef, memo } from 'react';
import Try from "./Try";
const getNumbers = () => { // 숫자 네개를 랜덤하게 뽑는 함수.
const candidate = [1,2,3,4,5,6,7,8,9];
const array = [];
for (let i = 0; i < 4; i += 1) {
const chosen = candidate.splice(Math.floor(Math.random() * (9 - i)), 1)[0];
array.push(chosen);
}
return array;
}
const NumberBaseball = memo(() => {
const [answer, setAnswer] = useState(getNumbers());
const [value, setValue] = useState("");
const [result, setResult] = useState("");
const [tries, setTries] = useState([]);
const inputEl = useRef(null);
const onSubmitForm = (e) => {
e.preventDefault();
if(value === answer.join('')) {
setTries(prevState =>
[...prevState,
{
try: value,
result: "홈런!"
}
]);
setResult("홈런!");
alert("게임을 다시 시작합니다.");
setValue("");
setAnswer(getNumbers());
setTries([]);
inputEl.current.focus()
} else {
const answerArray = value.split("").map(v => parseInt(v));
let strike = 0;
let ball = 0;
if(tries.length >= 9) {
setResult(`10번 넘게 틀려서 실패. 답은 ${answer.join(",")} 였습니다!`);
alert("게임을 다시 시작합니다. ");
setValue("");
setAnswer(getNumbers());
setTries([]);
inputEl.current.focus();
} else {
for (let i = 0; i < 4; i += 1) {
if (answerArray[i] === answer[i]) {
console.log("strike", answerArray[i], answer[i]);
strike += 1;
} else if (answer.includes(answerArray[i])) {
console.log("ball", answerArray[i], answer.indexOf(answerArray[i]));
ball += 1;
}
}
setTries(prevState => [
...prevState,
{
try: value,
result: `${strike} 스트라이크, ${ball} 볼입니다`
}
]);
setValue("");
inputEl.current.focus();
}
}
};
return (
<>
<h1>{result}</h1>
<form onSubmit={onSubmitForm}>
<input
ref={inputEl}
maxLength={4}
value={value}
onChange={e => setValue(e.target.value)}
/>
<button>입력!</button>
</form>
<div>시도: {tries.length}</div>
<ul>
{tries.map((v, i) => (
<Try key={`${i + 1}차 시도 : ${v.try}`} tryInfo={v} />
))}
</ul>
</>
);
});
export default NumberBaseball;
'리액트 > 웹게임' 카테고리의 다른 글
[React] 웹게임 4. 반응속도 체크 // setTimeout (0) | 2020.02.01 |
---|---|
[React] 웹게임 기타 알고있을 것 (0) | 2020.01.31 |
[React] 웹게임 3. 숫자야구 // 최적화(hooks) - memo (0) | 2020.01.31 |
[React] 웹게임 3. 숫자야구 // 최적화(class) - shouldComponentUpdate & PureComponent (0) | 2020.01.31 |
[React] 웹게임 3. 숫자야구 // 함수형 setState인 prevState (0) | 2020.01.31 |