1. 가장 근본적인 코드
<html>
<head> </head>
<body>
<div id="root"></div>
<script
crossorigin
src="https://unpkg.com/react@18/umd/react.development.js"
></script>
<script
crossorigin
src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"
></script>
<!--<script src="https://unpkg.com/react@18/umd/react.production.min.js" crossorigin></script>-->
<!--<script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js" crossorigin></script>-->
<script>
"use strict";
const e = React.createElement;
class LikeButton extends React.Component {
constructor(props) {
super(props); // 상속한 React.Component 의 constructor 를 LikeButton에도 적용하기 위해서.
this.state = { liked: false };
}
render() {
if (this.state.liked) {
return "You liked this.";
}
return e( // 자바스크립트로 버튼을 만드는 방법 완전히 이해하는데는 시간이 많이 걸려서 그냥 받아들이기로 했다.
"button",
{ onClick: () => this.setState({ liked: true }) },
"Like"
);
}
}
</script>
<script> // 흔히 index.js 에 있는 부분 id="root"에 만든 컴포넌트를 넣는다.
ReactDOM.createRoot(document.querySelector("#root")).render(
e(LikeButton)
);
</script>
</body>
</html>
2. Babel + JSX
<html>
<head>
</head>
<body>
<div id="root"></div>
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<!--<script src="https://unpkg.com/react@18/umd/react.production.min.js" crossorigin></script>-->
<!--<script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js" crossorigin></script>-->
<script type="text/babel">
'use strict';
class LikeButton extends React.Component {
constructor(props) {
super(props);
this.state = {liked: false};
}
render() {
if (this.state.liked) {
return 'You liked this.';
}
return (
<button onClick={() => this.setState({liked: true})}>
Like
</button>
);
}
}
</script>
<script type="text/babel">
// ReactDOM.render(<LikeButton />, document.querySelector('#root'); // React 17 버전 코드
ReactDOM.createRoot(document.querySelector('#root')).render(<LikeButton/>); // React 18 버전 코드
</script>
</body>
</html>
위 코드를 보면 다음처럼 바벨 cdn 을 추가해준 모습이다.
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
왜 바벨을 추가해줬어야했을까? 그 이유는 자바스크립트 코드에서 JSX 문법을 해석할 수 없기 때문이다.
즉 해석을 하려면 바벨이 필요하다.
cdn 으로 바벨을 추가해주고 script의 type을 다음과 같이 설정해준다.
<script type="text/babel">
또한 ReactDOM 을 render 하는 부분에서 17버전과 18버전이 다른것이 있습니다.
다음 부분입니다.
// ReactDOM.render(<LikeButton />, document.querySelector('#root'); // React 17 버전 코드
ReactDOM.createRoot(document.querySelector('#root')).render(<LikeButton/>); // React 18 버전 코드
3. 리액트 불변성
pop, push, shift, unshift, splice => 배열을 직접적으로 수정.
concat, slice => 새로운 배열을 만들어냄.
리액트에서 객체는 함부로 바꾸어선 안됨(불변성)
복사해서 복사한 객체를 수정하던지 해야된다.
3. 클래스 컴포넌트 여러 예제
3-1. 바인딩으로 함수를 사용
...
class LikeButton extends React.Component {
constructor(props) {
super(props);
this.state = { liked: false };
this.onClickButton = this.onClickButton.bind(this);
}
onClickButton() {
this.setState({ liked: true });
}
render() {
if (this.state.liked) {
return "You liked this.";
}
return <button onClick={this.onClickButton}>Like</button>;
}
}
</script>
<script type="text/babel">
ReactDOM.createRoot(document.querySelector("#root")).render(
<LikeButton />
);
</script>
</body>
</html>
button onClick 에서 this.onClickButton 을 사용하기 위해서는 다음처럼 바인딩이 필요하다.
this.onClickButton = this.onClickButton.bind(this);
3-2. Constructor 를 안쓰는 방법
다음처럼 화살표 함수를 사용해서 constructor 를 쓰지 않고도 this.onClickButton을 사용할 수 있게 된다.
<script type="text/babel">
"use strict";
class LikeButton extends React.Component {
state = { liked: false };
onClickButton = () => {
this.setState({ liked: true });
};
render() {
if (this.state.liked) {
return "You liked this.";
}
return <button onClick={this.onClickButton}>Like</button>;
}
}
</script>
3-3. 함수 컴포넌트
함수 컴포넌트를 사용하면 this 를 사용하지 않아도 되어서 좋다.
<script type="text/babel">
"use strict";
function LikeButton() {
const [liked, setLiked] = React.useState(false); // 구조 분해
if (liked) {
return "You liked this";
}
return (
<button
onClick={() => {
setLiked(true);
}}
>
Like
</button>
);
}
</script>
4. 클래스 컴포넌트로 구구단 만들기
<script type="text/babel">
"use strict";
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: "",
};
this.onSubmit = this.onSubmit.bind(this);
this.onChange = this.onChange.bind(this);
}
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}
/>
<button type="submit">확인</button>
</form>
<div>{this.state.result}</div>
</div>
);
}
}
</script>
위 코드를 보면 다음처럼 함수가 선언되어있는데, 이렇게만 사용하게 되면 에러가 발생한다.
onChange(e) {
this.setState({ value: e.target.value });
}
constructor 에서 바인딩이 필요하다.
이러한 과정이 번거롭다면 3-2 화살표 함수 형태로 선언하거나, 3-3 함수 컴포넌트를 사용하면 문제를 해결할 수 있게된다.
constructor(props) {
...
this.onChange = this.onChange.bind(this);
}
또한 하나 상기시켜야할 것은 데이터를 바꿀때 form 태그를 사용한다는 것이다.
나는 form 태그를 잘 사용하지 않았는데, 최근 공부하는 코드마다 form 태그를 사용하기 때문에 이 점을 고쳐야할 것 같다.
<form onSubmit={this.onSubmit}>
<input
type="number"
value={this.state.value}
onChange={this.onChange}
/>
<button type="submit">확인</button>
</form>
5. Fragment 의 사용이유
흔히 컴포넌트를 render 할때 jsx 는 꼭 <div></div> 또는 <></> 로 감싸 주어야했는데 차이를 이제야 알게 되었다.
div 를 사용했을때
보면 div 태그로 감싸져 있는 것을 알 수 있다.
Fragment를 사용했을때
div 와 달리 불필요한 div 태그가 사라져있다. 이러한 차이가 있는데 css 적용할때 불필요한 div 가 있으면 거슬리기 때문에 Fragment를 사용하는 것이 좋을 것 같다.
6. 이전의 state 값과 혼동되지 않게 표현하는 방법
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: "",
});
}
};
위 코드에서 다음 코드를 보자.
prevState 를 활용하여, prevState.value 로 사용해서 this.state.value 로 접근하지 않아도 되어서 헷갈리지 않게된다.
this.setState((prevState) => {
return {
result: "정답: " + prevState.value,
first: Math.ceil(Math.random() * 9),
second: Math.ceil(Math.random() * 9),
value: "",
};
});
위처럼 setState를 함수형으로 표현해야할 때는 간단하게 다음처럼 생각하자.
setState 안에서 setState에 해당되는 state 값을 사용해야할때.
7. class 컴포넌트 ref
다음처럼 클래스 컴포넌트에서 ref 를 할당하여 focus를 줄 수 있다.
onSubmit = (e) => {
...
this.input.focus();
} else {
...
}
this.input.focus();
};
<input
ref={(c) => {
this.input = c;
}}
type="number"
value={this.state.value}
onChange={this.onChange}
/>
8. setState 의 주의점
setState 가 실행될때는 컴포넌트가 다시 렌더된다. 이때 컴포넌트에 10초되는 함수가 있을경우 성능이 매우 안좋아질 수 있으므로 setState는 리렌더를 발생시킨다는 것을 상기하자.
클래스컴포넌트는 render 부분만 리렌더되고, 함수 컴포넌트에서는 전체 코드가 다시 리렌더 된다.
9. 함수를 JSX 에서 빼야하는 이유
input 태그안에 ref 를 보도록하자 {(c) => {this.input = c}} 함수가 있다.
이러한 코드는 좋지 못하다. 그 이유로는 setState는 리렌더를 발생시킨다고 하였는데, 리렌더가 발생되면 {(c) => {this.input = c}} 함수는 계속 생성되는 것이다.
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>
);
}
참고자료
구구단 섹션
https://www.inflearn.com/course/web-game-react
'공부기록 > 웹 개발' 카테고리의 다른 글
Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object. (0) | 2022.08.25 |
---|---|
[웹 게임을 만들며 배우는 React] 2장 (0) | 2022.08.25 |
javascript super (0) | 2022.08.24 |
ios 스크롤 바운스 (0) | 2022.08.16 |
따라하며 배우는 리액트 A-Z 넷플릭스 (0) | 2022.08.16 |