1) require: node의 모듈 시스템
//NumberBaseball.jsx
module.exports = NumberBaseball;
//client.jsx
const NumberBaseball = require('./NumberBaseball');
NumberBaseball class가 module.exports 담겨서 다른파일에서 require로 불러오기
2) import: ES2015(ES6) 모듈 시스템
export const hello = 'hello'; // 가져올 때 import { hello }
export default NumberBaseball; // 가져올 때 import NumberBaseball
import React, { Component } from 'react';
//따라서 React는 export default, Component는 export const Component
node로 webpack을 돌리면 import 사용 시 에러가 나지만 babel이 import를 require로 바꿔줌
(node에서는 require, react에서는 import와 export 사용)
<ul>
{['사과', '바나나', '포도', '귤', '감', '배', '밤',].map((v) => {
return (
<li>{v}</li>
);
})}
</ul>
<ul>
{[
{ fruit: '사과', taste: '달다' },
{ fruit: '바나나', taste: '맛없다' },
{ fruit: '포도', taste: '새콤하다' },
{ fruit: '귤', taste: '시다' },
{ fruit: '감', taste: '떫다' },
{ fruit: '배', taste: '맛있다' },
{ fruit: '밤', taste: '맛있다' },
].map((v, i) => { //두번째는 인덱스
return (
<li key={v.fruit + v.taste}><b>{v.fruit}</b> - {v.taste}</li>
);
})}
</ul>
화살표 함수 사용 시 return 생략 가능. 중괄호가 없으면 return을 뜻함
.map((v, i) =>
<li key={v.fruit + v.taste}><b>{v.fruit}</b> - {v.taste}</li>
)
v
, i
를 사용하기 위해 연결해주는 props 필요import React, { Component } from 'react';
class Try extends Component {
render() {
return(
<li>
<b>{this.props.value.fruit}</b> - {this.props.index}
<div>컨텐츠</div>
<div>컨텐츠1</div>
<div>컨텐츠2</div>
<div>컨텐츠3</div>
</li>
);
}
}
export default Try;
import Try from './Try';
...
fruits = [
{ fruit: '사과', taste: '달다' },
{ fruit: '바나나', taste: '맛없다' },
{ fruit: '포도', taste: '새콤하다' },
{ fruit: '귤', taste: '시다' },
{ fruit: '감', taste: '떫다' },
{ fruit: '배', taste: '맛있다' },
{ fruit: '밤', taste: '맛있다' },
];
render() {
return (
<>
...
<ul>
{this.fruits.map((v, i) => {
return (
<Try key={v.fruit + v.taste} value={v} index={i} />
);
})}
</ul>
</>
);
}
{/* jsx 주석 */}
render()
밖에서 화살표 함수를 쓰지 않으면 this가 undefined가 되어 연결해주는 bind()
함수를 써야함.
화살표 함수를 사용하면 자동으로 바인딩
push()
사용 시 뭐가 바뀌었는지 감지 x, 예전 state와 현재 state가 다르면 renderimport React, { Component } from 'react';
import Try from './Try';
function getNumbers() { //숫자 4개를 겹치지 않고 랜덤하게 뽑는 함수
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: [],
};
onSubmitForm = (e) => {
const { result, value, tries, answer } = this.state;
e.preventDefault();
if (value === answer.join('')) { //답이 맞는 지 비교
this.setState((prevState) => {
return {
result: '홈런!',
tries: [...prevState.tries, { try: value, result: '홈런!' }],
}
});
alert('게임을 다시 시작합니다!');
this.setState({
value: '',
answer: getNumbers(),
tries: [],
});
} else { // 답 틀렸으면
const answerArray = value.split('').map((v) => parseInt(v));
let strike = 0;
let ball = 0;
if (tries.length >= 9) { // 10번 이상 틀렸을 때
this.setState({
result: `10번 넘게 틀려서 실패! 답은 ${answer.join(',')}였습니다!`,
});
alert('게임을 다시 시작합니다!');
this.setState({
value: '',
answer: getNumbers(),
tries: [],
});
} else {
for (let i = 0; i < 4; i += 1) {
if (answerArray[i] === answer[i]) {
strike += 1;
} else if (answer.includes(answerArray[i])) {
ball += 1;
}
}
this.setState((prevState) => {
return {
tries: [...prevState.tries, { try: value, result: `${strike} 스트라이크, ${ball} 볼입니다` }],
value: '',
};
});
}
}
};
onChangeInput = (e) => {
console.log(this.state.answer);
this.setState({
value: e.target.value,
});
};
render() {
const { result, value, tries } = this.state;
return (
<>
<h1>{result}</h1>
<form onSubmit={this.onSubmitForm}>
<input maxLength={4} value={value} onChange={this.onChangeInput} />
</form>
<div>시도: {tries.length}</div>
<ul>
{tries.map((v, i) => {
return (
<Try key={`${i + 1}차 시도: `} tryInfo={v} />
);
})}
</ul>
</>
);
}
}
export default NumberBaseball;
import React, { Component } from 'react';
class Try extends Component {
render() {
const { tryInfo } = this.props; // 구조 분해 문법
return (
<li>
<div>{tryInfo.try}</div>
<div>{tryInfo.result}</div>
</li>
);
}
}
export default Try;
import React, { useState } from 'react';
import Try from './Try';
function 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 = () => {
const [result, setResult] = useState('');
const [value, setValue] = useState('');
const [answer, setAnswer] = useState(getNumbers());
const [tries, setTries] = useState([]);
const onSubmitForm = (e) => {
e.preventDefault();
if (value === answer.join('')) {
setResult('홈런!');
setTries((prevTries) => { // 이전 tries 배열로 새 tries 배열을 만들기 때문에 함수형으로 만들기
return [...prevTries, { try: value, result: '홈런!' }]
});
alert('게임을 다시 시작합니다!');
setValue('');
setAnswer(getNumbers());
setTries([]);
} 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([]);
} else {
console.log(answer.join(''));
for (let i = 0; i < 4; i += 1) {
if (answerArray[i] === answer[i]) {
strike += 1;
} else if (answer.includes(answerArray[i])) {
ball += 1;
}
}
setTries((prevTries) => [...prevTries, { try: value, result: `${strike} 스트라이크, ${ball} 볼입니다` }]);
setValue('');
}
}
};
const onChangeInput = (e) => {
setValue(e.target.value);
};
return (
<>
<h1>{result}</h1>
<form onSubmit={onSubmitForm}>
<input maxLength={4} value={value} onChange={onChangeInput} />
</form>
<div>시도: {tries.length}</div>
<ul>
{tries.map((v, i) => {
return (
<Try key={`${i + 1}차 시도: `} tryInfo={v} />
);
})}
</ul>
</>
);
};
export default NumberBaseball;
import React from 'react';
const Try = ({tryInfo}) => {
return (
<li>
<div>{tryInfo.try}</div>
<div>{tryInfo.result}</div>
</li>
);
};
export default Try;
shouldComponentUpdate()
의 return 값이 true면 랜더링, false 랜더링 하지 않게 구현shouldComponentUpdate()
에서 true, false 할 것인지를 state가 바뀌었는지 안 바뀌었는지 판단 후 자동으로 구현한 컴포넌트
import React, { PureComponent } from 'react';
class Test extends PureComponent { ...
❗ 단 state엔 복잡한 객체구조는 안 쓰는 게 좋음
Hooks에서 사용하는 리랜더링 방지 함수
const React = require('react');
const { memo } = React;
const Try = memo(({ tryInfo }) => {...
this.inputRef.current.focus();
로 접근 가능import React, { Component, createRef } from 'react';
...
InputRef = createRef();
함수형 방식은 세밀한 작업을 하고싶을 때 사용
render()
안에 this.setState()
사용 시 무한반복이 되므로 사용 Xconst Try = memo(({ tryInfo }) => {
const [result, setResult] = useState(tryInfo.result);
const onClick = () => {
setResult('1');
}
return (
<li>
<div>{tryInfo.try}</div>
<div onClick={onClick}>{tryInfo.result}</div>
</li>
);
});