React: 사용자 인터페이스를 만들기 위한 JavaScript 라이브러리
사용자 경험이 좋아진다. 웹에서 앱과 같은 사용자 경험을 만들어 준다.
(사용자 인터페이스 쉽게 만들기 위해 (single page application) )
데이터 화면 일치 (데이터 처리를 쉽게 하기 위해 )
재활용 가능한 웹 컴포넌트 (중복 피하기. 유지 보수가 쉬워짐)
상태 : 바뀌는 부분, 바뀔 수 있는 부분
1. 원시적인 React 코드 (like버튼 누르면 liked로 변경)
<!DOCTYPE html>
<html lang="en">
<head>
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
</head>
<body>
<div id="root"></div><!--결과: <div id="root"><button>Like</button></div>-->
<script>
const e = React.createElement; //태그 만드는거
class LikeButton extends React.Component{
constructor(props) {
super(props);
this.state = {
liked:false,
};
}
render(){
return e('button', { onClick: () => { this.setState({liked:true})} , type: 'submit'},
this.state.liked === true ? 'Liked' : 'Like'//버튼을 클릭하면 liked로 바뀜!
//상태가 바뀌면 화면이 저절로 바뀜
);
//<button type="submit">Like</button>
//버튼 태그를 만들겠다.
}
}
</script>
<script>
ReactDOM.render(e(LikeButton), document.querySelector('#root'));
//루트태그에다가 like 버튼을 그린다
</script>
</body>
</html>
2. Babel을 사용한 JSX 코드
자바스크립트 안에서 html 태그 문법을 쓰기위해 babel을 script로 넣어주고, type을 babel로 설정
=>JSX 라고 부름
<!DOCTYPE html>
<html lang="en">
<head>
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
<div id="root"></div><!--결과: <div id="root"><button>Like</button></div>-->
<script type="text/babel">
class LikeButton extends React.Component{
constructor(props) {
super(props);
this.state = {
liked:false,
};
}
render() {
return <button type="submit" onClick={() => {this.setState({liked: true})}}>
{this.state.liked ? 'Liked' : 'Like'}
</button>;
//JSX( JS+XML )
}
}
</script>
<script type="text/babel">
ReactDOM.render(<LikeButton />, document.querySelector('#root'));
//루트태그에다가 like 버튼을 그린다
</script>
</body>
</html>
3.구구단 게임 코드(JSX랑 JavaScript랑 섞어쓴거)
<body>
<div id="root"></div>
<script type="text/babel">
class GuGuDan extends React.Component {
constructor(props) {
super(props);
//바뀌는 거 설정
this.state = {
first: Math.ceil(Math.random()*9),
second: Math.ceil(Math.random()*9),
value: '',
result: '',
};
}
render(){
return(
<div>
<div>{this.state.first}곱하기{this.state.second}는?</div>
<form onSubmit={(e) => {
e.preventDefault();
if(parseInt(value) === this.state.first * this.state.second) {
this.setState({
result: '정답',
first: Math.ceil(Math.random() * 9),
second: Math.ceil(Math.random() * 9),
value: '',
});
}else{
this.setState({
result:'땡',
value:'',
});
}
}}>
<input type="number" value={this.state.value} onChange={(e) => this.setState({ value: e.target.value})}/>
//form 안에 숫자를 입력하기 위해 onChange (상태를 바꾸려면 setState)
<button>입력</button>
</form>
<div>{this.state.result}</div>
</div>
);
}
}
</script>
<script type="text/babel">
ReactDOM.render(<GuGuDan />, document.querySelector('#root'));
</script>
</body>
4.구구단 게임(JavaScript를 클래스의 메소드로)
function을 밖으로 뺄때는 무조건 화살표 함수로 표기해야함.
function을 붙여서 사용하면 this가 달라지게 되는 문제 발생.
<body>
<div id="root"></div>
<script type="text/babel">
class GuGuDan extends React.Component {
constructor(props) {
super(props);
//바뀌는 거 설정
this.state = {
first: Math.ceil(Math.random()*9),
second: Math.ceil(Math.random()*9),
value: '',
result: '',
};
}
onSubmit = (e) => {
e.preventDefault();
if (parseInt(this.state.value) === this.state.first * this.state.second) {
this.setState({
result: '정답',
first: Math.ceil(Math.random() * 9),
second: Math.ceil(Math.random() * 9),
value: '',
});
} else {
this.setState({
result: '땡',
value: '',
});
}
};
onChange=(e) => {
this.setState({ value: e.target.value})
};
render(){
return(
<div>
<div>{this.state.first}곱하기{this.state.second}는?</div>
<form onSubmit={this.onSubmit}>
<input type="number" value={this.state.value} onChange={this.onChange}/>
{/*form 안에 숫자를 입력하기 위해 onChange (상태를 바꾸려면 setState)*/}
<button>입력</button>
</form>
<div>{this.state.result}</div>
</div>
);
}
}
</script>
<script type="text/babel">
ReactDOM.render(<GuGuDan />, document.querySelector('#root'));
</script>
</body>
5-1. 쓸데없는 <div>
태그로 감싸야할까?
render(){
return(
<div>
<div>{this.state.first}곱하기{this.state.second}는?</div>
<form onSubmit={this.onSubmit}>
<input type="number" value={this.state.value} onChange={this.onChange}/>
{/*form 안에 숫자를 입력하기 위해 onChange (상태를 바꾸려면 setState)*/}
<button>입력</button>
</form>
<div>{this.state.result}</div>
</div>
);
}
5-2. 빈 태그로 <>
<div>
태그 없애기 가능해짐
babel tool을 설치해야지만 지원해서 React.Fragment로 대체
render(){
return(
<React.Fragment>
<div>{this.state.first}곱하기{this.state.second}는?</div>
<form onSubmit={this.onSubmit}>
<input type="number" value={this.state.value} onChange={this.onChange}/>
{/*form 안에 숫자를 입력하기 위해 onChange (상태를 바꾸려면 setState)*/}
<button>입력</button>
</form>
<div>{this.state.result}</div>
</React.Fragment>
);
}
6. constructor 없애는 법
class GuGuDan extends React.Component {
state = {
first: Math.ceil(Math.random()*9),
second: Math.ceil(Math.random()*9),
value: '',
result: '',
};
}
7. 예전 상태 값을 좀 더 구분해서 다음 상태 값에 사용할 수 있다.
수정 전)
onSubmit = (e) => {
e.preventDefault();
if (parseInt(this.state.value) === this.state.first * this.state.second) {
this.setState({
result: this.state.value+'은 정답',
first: Math.ceil(Math.random() * 9),
second: Math.ceil(Math.random() * 9),
value: '',
});
} else {
this.setState({
result: '땡',
value: '',
});
}
};
수정 후)
onSubmit = (e) => {
e.preventDefault();
if (parseInt(this.state.value) === this.state.first * this.state.second) {
this.setState((prevState) => {
return {
result: prevState.value + '은 정답',
first: Math.ceil(Math.random() * 9),
second: Math.ceil(Math.random() * 9),
value: '',
};
});
} else {
this.setState({
result: '땡',
value: '',
});
}
};
8.함수형 setState
setState안에 this.state가 들어가면 return을 해주는 함수를 쓰는 걸로!
카운터 예를 생각해보면
this.setState({
value: this.state.value +1,
});
this.setState({
value: this.state.value +1,
});
this.setState({
value: this.state.value +1,
});
setState는 비동기이기 때문에 전의 값보다 3이 증가하는게 아니라 1이 증가 될 수 도 있음.
따라서 return 해주는 함수를 쓰는 걸로
this.setState((prevState) => {
return {
value: prevState.value +1
};
});
this.setState((prevState) => {
return {
value: prevState.value +1
};
});
this.setState((prevState) => {
return {
value: prevState.value +1
};
});
9.input 창에 focus를 주고싶다!
ref 하고 함수를 넣어준다
class 안에 input 선언해준다
<input ref={(c)=>{this.input = c}}
this.input에다가 input 태그를 실제로 넣어줬기 때문에 document.querySelector('input').focus() 하는 것과 동일
정답과 땡 출력후 input에 focus
onSubmit = (e) => {
e.preventDefault();
if (parseInt(this.state.value) === this.state.first * this.state.second) {
this.setState((prevState) => {
return {
result: prevState.value + '은 정답',
first: Math.ceil(Math.random() * 9),
second: Math.ceil(Math.random() * 9),
value: '',
};
});
this.input.focus();
} else {
this.setState({
result: '땡',
value: '',
});
this.input.focus();
}
};
dom에 직접 접근하고 싶을때는 ref라는 것을 붙여서 접근하면 된다.
setState를 할때는 render함수가 다시 실행된다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>구구단</title>
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
class GuGuDan extends React.Component {
constructor(props) {
super(props);
//바뀌는 거 설정
this.state = {
first: Math.ceil(Math.random()*9),
second: Math.ceil(Math.random()*9),
value: '',
result: '',
};
}
onSubmit = (e) => {
e.preventDefault();
if (parseInt(this.state.value) === this.state.first * this.state.second) {
this.setState((prevState) => {
return {
result: prevState.value + '은 정답',
first: Math.ceil(Math.random() * 9),
second: Math.ceil(Math.random() * 9),
value: '',
};
});
this.input.focus();
} else {
this.setState({
result: '땡',
value: '',
});
this.input.focus();
}
};
onChange=(e) => {
this.setState({ value: e.target.value})
};
input;
onRefInput = (c) => {this.input = c};
render(){
return(
<React.Fragment>
<div>{this.state.first}곱하기{this.state.second}는?</div>
<form onSubmit={this.onSubmit}>
<input ref={this.onRefInput} type="number" value={this.state.value} onChange={this.onChange}/>
{/*form 안에 숫자를 입력하기 위해 onChange (상태를 바꾸려면 setState)*/}
<button>입력</button>
</form>
<div>{this.state.result}</div>
</React.Fragment>
);
}
}
</script>
<script type="text/babel">
ReactDOM.render(<GuGuDan />, document.querySelector('#root'));
</script>
</body>
</html>
class 형
class GuGuDan extends React.component{ ... }
함수 컴포넌트
setState랑 ref를 안쓸 때 사용했었음
const GuGuDan = () => { return <div> HELLO HOOKS </div>; }
함수 컴포넌트에서도 state랑 ref를 사용하게 해주세요~ => react hooks
처음 짠 구구단 클래스 코드 state
this.state = {
first: Math.ceil(Math.random()*9),
second: Math.ceil(Math.random()*9),
value: '',
result: '',
};
hooks 방식으로 변경
const GuGuDan = () => {
const [first,setFirst] = React.useState(Math.ceil(Math.random()*9));
const [second,setSecond] = React.useState(Math.ceil(Math.random()*9));
const [value, setValue] = React.useState('');
const [result, setResult] = React.useState('');
const inputRef = React.useRef(null);//ref 쓰는 법도 변경
const onChangeInput = (e) => {
setValue(e.target.value);
};
const onSubmitForm = (e) => {
e.preventDefault();
if (parseInt(value) === first * second) {
setResult('정답' + value);
setFirst(Math.ceil(Math.random() * 9));
setSecond(Math.ceil(Math.random() * 9));
setValue('');
inputRef.current.focus();
} else {
setResult('땡');
setValue('');
inputRef.current.focus();
}
};
return (
<React.Fragment>
<div> {first} 곱하기 {second}는? </div>
<form onSubmit={onSubmitForm}>
<input ref={inputRef} onChange={onChangInput} value={value}/>
<button>입력!</button>
</form>
<div id="result">{result}</div>
</React.Fragment>
);
}
setCounter((c) => c+1)