본문 바로가기
KDT TIL Note/React

[막시밀리언] 리액트 State 및 이벤트 다루기

by 메리뉴데이 2023. 2. 16.

리액트는 선언적 접근 방법을 따르는데, 

 

이는 우리가 원하는 목표 상태(UI)를 정의하고 

리액트가 그 상태에 도달하도록 처리한다는 것을 의미한다.

 

 

 

 

 

<button>의 DOM interface

 

 

 

https://developer.mozilla.org/en-US/docs/Web/API/HTMLButtonElement

 

HTMLButtonElement - Web APIs | MDN

The HTMLButtonElement interface provides properties and methods (beyond the regular HTMLElement interface it also has available to it by inheritance) for manipulating <button> elements.

developer.mozilla.org

 

 

문서를 보면 <button>요소를 다루는데 있어, HTMLButtonElement interface가 상속에 의해 속성들과 메서드들을 제공함을 말하고 있다.

 

 

위 그림에서 Element를 클릭해서 보면,

 

https://developer.mozilla.org/en-US/docs/Web/API/Element

 

Element - Web APIs | MDN

Element is the most general base class from which all element objects (i.e. objects that represent elements) in a Document inherit. It only has methods and properties common to all kinds of elements. More specific classes inherit from Element.

developer.mozilla.org

 

수많은 이벤트들이 있는 것을 보게 된다.

 

 

 

 

이 기본 이벤트들은 리액트에서 props와 동등한 것으로 내장된 html 요소에 추가해서 이벤트들을 수신(listen)할 수 있다.

리액트에서는 모든 기본 이벤트를 on으로 시작하는 props로 나타낸다. ex) onClick, onBlur, ...

 

이벤트 핸들러 props는 그 값으로 함수가 필요하고, 이 값으로 전달된 함수는 해당 이벤트가 발생했을 때 실행되어야 한다.

 

 

 

 

 

 

일반적으로 JSX 코드에 너무 많은 로직을 넣는 것이 좋은 생각이 아니므로, 

JSX를 return하기 전에 이 이벤트 리스너 함수를 정의한다. 

 

 

 

 

이벤트 리스너 함수 뒤에 실행 ()를 넣지 않고 작성하는 이유는, 

 

50강 6:42 

 

이 이벤트 리스너는 이벤트가 발생했을 때, 리액트가 호출할 것이다.

 

 

 

권장하는 이벤트 리스너 함수의 네이밍은 

앞에는 이벤트 뒤에는 Handler로 끝나게 작성하면 좋겠다.

 

 

 

 

 

 

 

 

useState는 리액트 라이브러리에서 제공하는 함수로, 

컴포넌트 함수가 다시 호출되는 곳에서 

변경된 값을 반영하기 위해 state로 값을 정의할 수 있게 해주는 함수이다.

 

 

 

 

useState 함수는 리액트 훅(hook)의 하나로, 반드시 리액트 컴포넌트 함수 안에서 호출되어야 한다.

그리고, 내부의 중첩된 함수 안에서도 호출할 수 없고 컴포넌트 함수 안에서 직접적으로 호출되어야 한다.

 

useState는 기본적인 state 값 대신 특별한 종류의 변수를 생성한다고 할 수 있다.

이 변수는 변경사항으로 인해 컴포넌트 함수가 다시 호출되도록 한다.

 

useState 함수에 인자로 전달한 것이 특별하게 생성될 변수의 초깃값으로 설정된다. 

이 함수가 반환하는 값이 특별한 변수에 접근하게 해줄 뿐 아니라, 

그 변수에 새로운 값을 할당하기 위해 우리가 호출할 수 있는 함수도 반환한다 ! 

 

useState는 실제로 첫번째 요소는 이 변수 자체이고, 두번째 요소는 업데이트되는 함수인 배열을 반환한다.

(요소가 2개 짜리인 배열 반환)

 

 

 

 

위의 빨간 박스는 useState()의 반환값을 배열 구조 분해하여 독립된 두 요소를 각각의 상수에 저장하도록 작성한 것이다. 

 

 

 

 

 

 

setState 함수를 사용해 새로운 값을 할당하는 이유!!!!!!!!!

 

52강  8:04

 

 

 

 

 

 

 

9:17 

 

 

 

 

 

리액트는 state가 변하면 state가 등록된 컴포넌트 재평가한다. 

 

 

 

 

53강 중요!!!

스크립트 자세히 다시 복습.

 

 

 

 

state는 컴포넌트의 인스턴스 별로 독립적으로 나뉘어져 있다 !

 

 

useState를 사용해 새로운 값을 할당하는데, const를 사용할 수 있는 이유는,

새 값을 등호를 사용해서 할당하지 않고

대신 state를 업데이트하는 setState 함수를 호출하여 그 state 값들은 리액트에 의해 어딘가에서 관리되고 있기 때문이다.

useState가 반환하는 배열에서 가장 최신의 상태를 리액트가 우리에게 제공한다.

 

 

state는 유저 이벤트 발생 시 뿐만 아니라, 예를 들어 setTimeoout()을 사용하여 타이머가 만료되어 상태를 업데이트되게 하는 등 어떤 이유로든 상태를 업데이트할 수 있다 !

 

 

 

 

! JSX 문법은 React 라이브러리를 사용하지만, 명시적으로 import하지 않아도 이미 환경설정적으로 리액트 라이브러리를 임포트하게 되어있으므로 작성 유무 상관없이 잘 작동한다.

 

 

 

 

 

 

 

 

 

 

 

 

모든 키 입력이나 입력값의 변화를 수신하기 위해 리스너를 추가해야 한다.

 

 

onInputChange 이벤트에 비해 onChange 이벤트의 이점은 input 외에도 드랍다운 메뉴와 같은 모든 입력 타입의 이벤트를 감지하는 것이다.

 

 

 

 

 

 

 

 

 

 

 

 

event.target.value는 이벤트가 벌여졌을 시점의 현재 입력값을 갖게 된다.

 

 

 

 

 

 

 

 

 

 

그런데 위의 두 가지 방법보다 더 추천되는 코드와 그 이유, 
59강 1:29

 

 

 

 

위의 빨간 박스와 같은 접근 방법을 사용하면,

리액트는 이 함수 안의 state 스냅샷이 가장 최신인 것과 스케쥴된 상태 업데이트를 항상 염두에 두는 것을 보장할 수 있다.

그래서 이 방법이 항상 최신 상태의 스냅샷에서 작업하도록 하는 좀 더 안전한 방법이다.

만약 state 업데이트가 이전 상태에 의존하고 있는 경우에는 이 함수 형태로 작성하는 것이 좋다 !

 

 

 

 

 

 

60강 설명 다시 확인 !

 

 

 

 

 

 

 

 

state를 사용하면 양방향 바인딩(binding)을 할 수 있는데, 

변경되는 입력값만 수신하는 것이 아니라 

입력에 새로운 값을 다시 전달할 수도 있다 ! > 프로그램에 따라 입력값을 재설정하거나 입력할 수 있다.

 

 

 

양방향 바인딩이란,

위 노란 박스처럼 value 라는 기본 속성에 enteredTitle이라는 이름을 값으로 갖게하면

enteredTitle이라는 속성명으로 입력값을 받을 수 있기도 하지만, 다시 이 이름으로 입력값을 설정할 수도 있게 된다는 말이다. 폼으로 작업할 때 폼 전송에 따라 사용자의 입력을 모으거나 변경할 수 있게 해주기 때문에 아주 유용하다.

 

 

 

 

 

 

 

 

 

자식에게서 부모에게로 데이터를 전달할 방법은, 

부모로부터 자식에게 전달한 함수가 있을 때,

자식이 그 함수를 호출할 때 매개변수로 데이터를 전달할 수 있다 !

 

부모에게 가는 중 중간에 중첩되는 컴포넌트가 있다면 생략할 수 없고 모두 거쳐가야 한다 !

 

 

사용자 정의 컴포넌트 내의 사용자 정의 props 이름을 onSaveExpenseData라고 정한 이유는,

이 프랍의 값은 함수가 될 것이고, 이 함수가 컴포넌트 내부에서 어떤 일이 일어났을 때 작동되는 함수인지 직관적으로 알 수 있게 하기 위해서이고, 관례적으로 on을 붙였다. > 이 함수의 경우는 입력된 ExpenseData가 폼에 제출되었을 때 작동됨

 

 

 

 

saveExpenseDataHandler 함수는 컴포넌트 NewExpense에서 실행되지 않고 ExpenseForm으로 전달된다.

 

 

 

saveExpenseDataHandler 함수는 이 값의 키 역할을 하는 onSaveExpenseData를 통해 정의된 NewExpense 컴포넌트가 아닌 데이터(함수)가 props로 내려진 ExpenseForm 컴포넌트에서 실행()할 수 있게 되는데, 

이유는 onSaveExpenseData를 통해 saveExpenseDataHandler 이벤트 핸들러 함수의 포인터를 전달하기 때문이다.

이것이 컴포넌트끼리 혹은 자식에서 부모 컴포넌트로 소통하는 방법이다 ! 

 

 

 

 

 

ExpenseForm 자식 컴포넌트의 데이터(expenseData)를 NewExpense 부모 컴포넌트에서 내려받은 onSaveExpenseData 함수의 매개변수로 집어 넣어, 데이터를 자식으로부터 부모로 보낼 수 있게 하는 것이다 ! <Lifting State Up>

 

 

 

 

폼에서 새로운 데이터를 입력하고 나서, 콘솔을 확인해보면 NewExpense 부모 컴포넌트에서 ExpenseForm 자식 컴포넌트를 통해 입력된 데이터가 잘 전달되어 출력되는 것을 확인할 수 있다.

이와 같은 방식으로 NewExpense 컴포넌트에서 상위 컴포넌트인 App 컴포넌트로 데이터를 전달할 수도 있겠다.

 

 

 

 

 

 

onAddExpense 속성은 관례대로 인자를 전달하는 포인터 함수라는 것을 명시하기 위해 on을 붙여 작성했다.

NewExpense 컴포넌트에 설정한 속성 onAddExpense에 addExpenseHandler 포인터를 값으로 지정하여 이 속성을 통해 포인터를 NewExpense 컴포넌트에 전달하면  NewExpense 컴포넌트에서 포인터 함수 onAddExpense의 매개변수로 넣어준 값이 App으로 전달될 수 있게 되는 구조인 것이다 !

 

 

 

 

 

콘솔에 'In App.js'이라고 찍히는 걸 보니 NewExpense 컴포넌트에서의 포인터 함수 onAddExpense 호출이 잘 실행되고 있는 것을 확인할 수 있다.

 

 

 

 

 

 

 

 

1. 드랍다운 메뉴의 변경사항 수신(listen)하기

 

 

 

 

 

 

2. 선택한 값을 Expenses.js 파일로 보내기

컴포넌트 Expenses에서 내려보낸 props인 포인터 함수를 통해 e.target.value로 변경된 ExpenseFilter 컴포넌트의 데이터 값을 컴포넌트 Expenses로 올려보낸 것이 콘솔에서 확인된다.

 

 

 

 

 

 

 

 

3. 올라온 데이터를 state로 저장하기

양방향 바인딩을 사용해 Expenses 컴포넌트에서 2020로 저장해놓은 기본값을 조절할 수 있다.

 

65강 과제 중

 

 

 

 

 

 

 

 

 

이 앱에서 ExpenseFilter는 단지 드랍다운을 보여주며 UI를 나타내는 컴포넌트이다.

그 안에 리스너와 props를 가지고 있지만

실제 로직은 부모 컴포넌트인 Expenses가 가지고 있고, 

이 로직을 통해 ExpensesFilter를 제어된 컴포넌트로 바꾸는 것이다.

 

값들은 ExpensesFilter 컴포넌트 자체에서 다루는 것이 아니라 부모 컴포넌트에서 처리된다.

 

 

 

 

 

(working on..)