리액트(React)는 페이스북에서 개발한 오픈 소스 자바스크립트 라이브러리로, 사용자 인터페이스를 만들기 위해 주로 사용된다.
리액트는 선언적이고 효율적인 사용자 인터페이스를 만들기 위해 설계되었다. 이를 위해 가상 DOM(Virtual DOM)을 사용하여 UI 업데이트를 최적화하고, 컴포넌트 기반 아키텍처를 통해 코드의 재사용성과 유지보수성을 높일 수 있다.
가장 큰 특징 중 하나는 JSX라는 문법을 사용하여 JavaScript 코드 안에 마크업을 작성할 수 있다는 것이다.
--> JSX는 JavaScript의 확장 문법 으로, HTML과 유사한 구문을 사용하여 UI를 선언적으로 표현할 수 있게 해준다.
const element = <h1>Hello, world!</h1>;
이 코드를 살펴보자
이건 HTML일까 JS일까? 도대체 뭘까?
--> JSX라 하며 JavaScript를 확장한 문법을 나타낸다.
React에서는 본질적으로 렌더링 로직이 UI 로직(이벤트가 처리되는 방식, 시간에 따라 state가 변하는 방식, 화면에 표시하기 위해 데이터가 준비되는 방식 등)과 연결된다는 사실이다.
const name = '서연';
const element = <h1>Hello {name}</h1>
--> name이라는 변수를 선언한 후 중괄호로 감싸 JSX 안에 사용
JSX의 중괄호 안에는 유효한 모든 JavaScript 표현식을 넣을 수 있다.
예를 들어 2 + 2, user.firstName 또는 formatName(user) 등
아래 예시에서는 JavaScript 함수 호출의 결과인 formatName(user)을 <h1> 엘리먼트에 포함해 보았다.
function formatName(user) {
return user.firstName + ' ' + user.lastName;
}
const user = {
firstName: 'Harper',
lastName: 'Perez'
};
const element = <h1> Hello, {formatName(user)}! </h1>;
컴파일이 끝나면, JSX 표현식이 정규 JavaScript 함수 호출이 되고 JavaScript 객체로 인식한다.
즉, JSX를 if 구문 및 for loop 안에 사용하고, 변수에 할당하고, 인자로서 받아들이고, 함수로부터 반환할 수 있다.
function getGreeting(user) {
if (user) {
return <h1>Hello, {formatName(user)}!</h1>;
}
return <h1>Hello, Stranger.</h1>;
}
자자. 사실 이렇게 공부한다고 해서 제대로 이해할 수 있는 것도 아니고,
기본적인 구구단을 리액트로 만들어 보면서 리액트의 기능들을 하나 하나 적용해보자

이러한 간단한 구구단 테스트를 할 수 있는 구구단을 만들어 본다고 가정해보자.
여기서 변하는 부분을 먼저 찾아보자
이렇게 세 개로 나타낼 수 있을 것 이다.
리액트에서는 이렇게 변하는 부분을 state에 넣고 보관한다.
리액트에서는 컴포넌트의 변하는 부분을 상태(state)에 저장하여 관리한다. 각각의 변하는 부분을 상태로 정의하고, 이를 컴포넌트에서 사용하여 동적으로 업데이트할 수 있다.
class GuGuDan extends React.Component {
state = {
first: Math.ceil(Math.random() * 9),
second: Math.ceil(Math.random() * 9),
value: ' ',
result: ' '
}
}
class GuGuDan extends React.Component : GuGuDan 클래스를 선언하여 리액트의 기본 클래스 컴포넌트인 React.Component를 확장한다. 이것은 리액트 클래스 컴포넌트를 생성하는 기본적인 방법이다.
state = { first: Math.ceil(Math.random() * 9), second: Math.ceil(Math.random() * 9), value: ' ', result: ' ' }: GuGuDan 컴포넌트의 초기 상태를 정의한다. 여기서 first와 second는 랜덤으로 생성된 1에서 9 사이의 숫자이다. value는 사용자의 입력값을 저장하는 상태이며, 초기값은 빈 문자열을 나타낸다. result는 사용자의 정답 여부를 나타내는 상태이며, 초기값은 빈 문자열이다.
이처럼 변화하는 데이터나 상태를 state에 저장하여 관리한다. 이렇게 함으로써 컴포넌트가 동적으로 동작하고 상태 변화에 따라 화면이 업데이트될 수 있다.
리액트 애플리케이션을 화면에 표시할 때, render() 메서드를 정의한 리액트 컴포넌트를 사용하고, ReactDOM.render() 함수를 사용하여 이를 실제 DOM에 렌더링해야 한다.
1. render() 메서드
render() {
return (
<React.Fragment>
<div>{this.state.first} 곱하기 {this.state.second}는? </div>
<form>
<input type='number' value={this.state.value} />
<button> 입력 </button>
</form>
<div>{this.state.result}</div>
</React.Fragment>
)
}
<React.Fragment>: 이는 빈 태그로서, 여러 요소를 그룹화하고 부모 요소 없이 여러 요소를 반환할 수 있게 해준다. 이 경우에는 불필요한 div 요소를 생성하지 않고 여러 요소를 그룹화하기 위해 사용된다.
<div>{this.state.first} 곱하기 {this.state.second}는? </div> : 이 부분은 현재 상태인 first와 second를 이용하여 구구단 문제를 출력한다. first와 second는 랜덤으로 생성된 숫자이며, 이를 활용하여 구구단 문제가 생성된다.
<input type='number' value={this.state.value} />: 사용자가 숫자를 입력할 수 있는 입력 필드이다. value 속성은 상태인 value와 연결되어 있으며, 사용자가 입력한 값을 나타낸다.
<button> 입력 </button> : 사용자가 입력을 완료하기 위한 버튼이다. 이 버튼을 클릭하면 입력한 값이 제출되어 처리된다.
<div>{this.state.result}</div>: 이 부분은 구구단 테스트의 결과를 출력한다. 사용자가 입력한 값과 정답을 비교하여 결과가 여기에 표시된다.
2. ReactDOM.render() 함수
<script type="text/babel">
ReactDOM.render(<GuGuDan />, document.getElementById('root'))
</script>
첫 번째 매개변수: 렌더링할 리액트 엘리먼트이다. 여기서는 라는 리액트 컴포넌트를 렌더링한다.
--> 여기서 리액트 컴포넌트란? : 함수형 컴포넌트와 클래스형 컴포넌트로 나눌 수 있다. 이 중 은 클래스형 컴포넌트로 이다.
두 번째 매개변수: 실제 DOM에서 해당 리액트 엘리먼트를 렌더링할 대상이다. 여기서는 document.getElementById('root')를 사용하여 id가 'root'인 DOM 요소를 찾아 렌더링한다. 일반적으로 이러한 대상은 HTML 문서의 어떤 요소든 될 수 있다.
이 root는 요기 나타나있다.
--> 즉, 실제 HTML 문서에 있는 id가 'root'인 요소를 찾아서 그 안에 컴포넌트를 렌더링하는 역할을 한다고 이해하면 된다.
자 이제 화면에
요로코롬 렌더링까진 완료! 했다.
이제 기능 구현을 해야 한다.
값을 입력했을 때, 값이 정답인지 확인해야 하고,
정답일 때 -> 정답 : 정답값
오답일 때 -> 오답
이라고 화면에 렌더링도 시켜야 한다.
자 먼저, 입력 버튼을 눌렀을 때, 즉 값을 제출했을 때 실행할 함수를 정의해보자!
render() {
return (
<React.Fragment>
<div>{this.state.first} 곱하기 {this.state.second}는? </div>
<form 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: ''
});
}
}}>
<input type="number" value={this.state.value} onChange={(e) => {
this.setState({
value: e.target.value
});
}} />
<button type="submit">입력</button>
</form>
<div>{this.state.result}</div>
</React.Fragment>
);
}
여기서 살펴봐야할 부분은
onSubmit, onChange 부분이다.
<form>요소에서 발생하는 submit 이벤트에 대해서 e.preventDefault()를 호출하여 폼의 제출을 막고, 대신에 사용자가 입력한 값을 평가하고 결과를 표시하는 로직을 구현한다.
<form onSubmit={(e) => { ... }}>: 입력 폼을 나타내기 위한 <form> 요소이다. 폼 제출(submit) 이벤트가 발생할 때 실행될 함수를 정의한다.
<input type="number" value={this.state.value} onChange={(e) => { ... }} /> : 사용자가 숫자를 입력할 수 있는 입력 필드이다. value 속성은 상태인 value와 연결되어 있으며, onChange 이벤트 핸들러를 통해 입력 값이 변경될 때마다 상태를 업데이트한다.
<button type="submit">입력</button>: 사용자가 입력을 완료하기 위한 버튼입니다. type="submit"을 지정하여 폼을 제출하는 역할을 합니다.
{this.state.result}: 구구단 테스트의 결과를 출력합니다. 정답 또는 오답에 따라 상태에 저장된 결과가 표시됩니다. result는 onSubmit에서 정의한 result가 적용된다.
그런데 여기서 중요한 부분이 있다.
화면을 렌더링할 떄마다, 함수가 같이 렌더링되면, 속도도 늦어지고 불필요한 데이터도 낭비가 될 것이다.
이떄, 함수는 밖으로 꺼내는 것이 중요하다!
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({
result: '정답 : ' + this.state.value + '🅾️',
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 (
<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>
);
}
}
요로코롬 밖으로 꺼내서 함수를 정의해 보았다.
단 여기서 주의할 점은 --> 밖에 선언된 함수는 화살표 함수만 사용가능하다
function (){} 을 사용하게 되면, this가 가리키는 값이 달라지기 때문에
고냥 무조건 화살표 함수로 사용한다고 기억하고 있으면 된다 --> 사실 화살표 함수를 더 자주 사용해서 나는 개이득!
값을 입력하고 나면, input 박스에 포커스가 되도록 !

빨간 네모 박스를 잘 살펴보자!
onRefInput 메서드는 input 요소의 ref를 설정하기 위한 콜백 함수이다. 이 콜백 함수는 input 요소가 마운트될 때 호출되어 input 요소의 ref를 컴포넌트의 인스턴스 변수인 this.input에 할당한다.
onSubmit 메서드에서는 사용자가 정답을 맞췄을 때, this.input.focus()를 호출하여 입력 창에 포커스를 설정한다. 이를 통해 사용자는 바로 다시 새로운 문제를 풀 수 있게 된다.
ref 속성을 사용하여 input 요소에 onRefInput 콜백 함수를 전달하여 ref를 설정한다.


자바스크립트로 했을 때보다 코드는 훨씬 깔끔(?)한거 같긴한데
처음 리액트를 접하고 나니 머리는 멘붕이다
ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ
환장할 따름이다 .. 🤦♀️ 🤦♀️ 🤦♀️ 🤦♀️ 🤦♀️ 🤦♀️ 🤦♀️ 🤦♀️ 🤦♀️ 🤦♀️ 🤦♀️
살려주셈 .. ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ