화면에서 바뀌는 부분을 State라고 한다.
class 안에 state = {};로 정의해주고, 중괄호 안에 바뀌는 부분들을 넣는다.
state는 setState로 우리가 수동으로 변경해줄 값만 넣어야 한다. 자동적으로 바뀌는 값 X
예시
class GuGuDan extends React.Component {
state = {
first: Math.ceil(Math.random() * 9),
second: Math.ceil(Math.random() * 9),
value: '',
result: '',
answer: ''
};
}
JavaScript에서 실험적인 코드를 사용할 수 있게 해 주는 컴파일러
최신문법을 사용해 코딩하되 배포시에 구버전으로 트랜스컴파일해서 출시할 수 있도록 한다.
사용 예시
<html>
<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>
<script type="text/babel">
// 컴포넌트 생성
class LikeButton extends React.Component {
constructor(props) {
super(props);
this.state = {
liked: false,
};
}
// 어떻게 화면에 표시할 것인지 결정하는 메소드
// <button>Like</button>이라는 태그를 만들겠다
render() {
return <button type="submit" onClick={() => { this.setState({liked: true})}}>
{this.state.liked ? 'Liked' : 'Like'}
</button>;
}
}
</script>
<script type="text/babel">
// LikeButton을 실제 Dom의 root 안에 붙이겠다
ReactDOM.render(<LikeButton/>, document.querySelector('#root'));
</script>
</body>
</html>
babel 스크립트를 넣어주고 타입을 text/babel로!
여기서 JSX(JavaScript+XML)가 나온다. 컨텐트 부분에 중괄호로 감싸서 JS 문법을 또 쓸 수 있다.
JSX의 좋은 점
ReactDOM.render(<div><LikeButton/><LikeButton/><LikeButton/><LikeButton/></div>, document.querySelector('#root'));
vs
ReactDOM.render(<div>
<button onClick={onclick}>Like</button>
<button onClick={onclick}>Like</button>
<button onClick={onclick}>Like</button>
<button onClick={onclick}>Like</button>
</div>, document.querySelector('#root');
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} />
<button>입력!</button>
</form>
<div>{this.state.answer}{this.state.result}</div>
</div>
);
}
return을 위해 모든 태그를 감싸는 div태그가 존재하는데, 개발자도구에서 보면 이 div가 의미없이 자리만 차지하고 있는 것이 보인다. 이 div를 지우고 return도 정상적으로 되도록 바꿔보자.
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} />
<button>입력!</button>
</form>
<div>{this.state.answer}{this.state.result}</div>
</React.Fragment>
);
}
return도 정상작동, 의미없이 자리만 차지하던 div도 제거된 모습이다.
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: '',
});
}
현재 setState를 보면, this.state.value는 현재의 값인데 result, first, second, value는 미래에 이렇게 바꿀거라는 미래의 값이다. 이 부분에 대한 구별 없이 코드를 작성하면 나중에 헷갈릴 위험이 있다.
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: '',
};
});
}
setState 안에 함수를 넣고 그 안에서 return을 시켜보자. 즉, 새로운 state를 리턴하는 것. prevState에는 바꾸기 전의 상태값이 들어있다. 그 값을 다음 상태값에 활용할 수 있다. 자주 쓰이는 방식이니 알아두기!
예전 state의 값으로 새로운 state를 만들 때는 함수형 setState를 사용하자!
각각 입력버튼을 누르기 전과 후의 모습이다.
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} />
<button type="submit">입력!</button>
</form>
<div>{this.state.result}</div>
</React.Fragment>
);
}
현재는 [입력!]버튼을 누르면 input에 focus가 풀리는 상황이다. 버튼을 눌러도 focus가 풀리지 않도록 바꿔보자.
input;
render(){
return (
<React.Fragment>
<div>{this.state.first}곱하기{this.state.second}는?</div>
<form onSubmit={this.onSubmit}>
<input ref={(c)=> { this.input = c; }} type="number" value={this.state.value} onChange={this.onChange} />
<button type="submit">입력!</button>
</form>
<div>{this.state.result}</div>
</React.Fragment>
);
}
DOM에 직접 접근하고 싶을 때는 ref 속성을 붙여서 접근하면 된다. 이 경우도 DOM에 직접 접근하는 것이므로 input 태그에 ref 속성을 붙이자. ref={(c)=> { this.input = c; }} 는 그냥 구문처럼 외울 것! 그리고 input은 클래스에 변수로 선언해준다. 변수명으로 쓰인 input은 임의로 이름을 변경해도 상관없다. (ex. hello)
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();
}
};
그러면 이렇게 input에 직접 접근할 수 있고, this.input.focus()로 이 input에 focus를 주면 끝!
각각 입력버튼을 누르기 직전과 직후의 모습이다. 입력버튼을 눌러도 입력창에 focus가 유지되고 있다.
render() 함수는 어느 시점에 실행될까? render() 에 console.log('렌더링');을 추가해 알아보았다.
setState가 실행될 때마다 render()도 재실행된다. 성능 최적화를 위해서는 꼭 알아둬야 할 부분!
따라서 render()에는 복잡한 함수를 최대한 넣지 않는 것이 좋다.
input;
render(){
return (
<React.Fragment>
<div>{this.state.first}곱하기{this.state.second}는?</div>
<form onSubmit={this.onSubmit}>
<input ref={(c)=> { this.input = c; }} type="number" value={this.state.value} onChange={this.onChange} />
<button type="submit">입력!</button>
</form>
<div>{this.state.result}</div>
</React.Fragment>
);
}
↓ ref속성도 밖으로 이렇게 빼주자.
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} />
<button type="submit">입력!</button>
</form>
<div>{this.state.result}</div>
</React.Fragment>
);
}
<html>
<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>
<script type="text/babel">
class GuGuDan extends React.Component {
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});
};
onRefInput = (c) => {
this.input = c;
}
input;
// 컨텐츠
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} />
<button type="submit">입력!</button>
</form>
<div>{this.state.result}</div>
</React.Fragment>
);
}
}
</script>
<script type="text/babel">
ReactDOM.render(<GuGuDan />, document.querySelector('#root'));
</script>
</body>
</html>