본문 바로가기
React

React 완벽 가이드 Session 4

by bmodel 2022. 8. 9.

모듈 소개

이번 섹션에서는 사용자와의 상호작용, 클릭하거나 텍스트 입력창에 입력하기 같은 사용자 이벤트 다루기, state에 대해 배워본다.

리액트의 필수적인 중요개념을 배운다.

 

이벤트 리스닝 및 이벤트 핸들러 수행하기

이벤트 핸들러 props는 값으로 함수가 필요하고, onClick 과 같은 이런 모든 다른 on props에 대한 값으로 전달된 함수는 이벤트가 발생할 때 실행한다.

상수로 함수를 정의한 다음 이벤트 헨들러의 함수를 실행시킬 수 있다.

const clickHandler = () => {
    console.log('Clicked!!')
  };

<button onClick={clickHandler}>Change Title</button>

요소에 이벤트가 지원된다면 on 다음에 이벤트명 props를 추가해서 리액트로 리스너를 쓸 수 있다.

함수의 이름 짓기

이벤트에서 트리거되고 헨들러로 끝나게 이름을 짓는다.

 

"State"와 함께 일하기 

일부 변수가 변경되었다 하더라도 전반적인 컴포넌트 함수는 다시 실행되지 않는다.

 

trigger

연쇄 작용

 

useState() 함수

컴포넌트 함수가 다시 호출되는 곳에서 변경된 값을 반영하기 위해서 state로 값을 정의 할 수 있게 하는 함수

첫 번째 값은 관리되고 있는 값

두 번째 값은 새로운 값을 업데이트 하기 위한 함수

 

왜 state를 업데이트하는 함수를 사용하는 것일까?

왜냐하면, 이 함수를 호출하는 것은 새로운 값을 할당하는 것이 아니라 특별한 변수로 시작하기 때문이다. 중요한 것은 다시 실행된다는 점이다. 이 변경함수를 사용하면 리액트에게 이 함수는 재평가되어야한다고 말한다. 그래서 리액트는 함수를 재실행하고 다시 평가한다. 지난번과 비교해서 다른 변화를 화면에 나타나게한다. 이것이 그냥 변수를 정의해서 바꾸는 것이 실행되지 않는 이유다.

 

"useState" 훅 자세히 살펴보기 중요

왜 상수 const를 사용하는가?

리액트에서 state는 변경될 때마다 재실행되서 값이 변하기 때문이다.

state는 컴포넌트 인스턴스 별로 나뉘어져 있다.

const ExpenseItem = (props) => {
  // function clickHanlder() {}
  const [title,setTitle] = useState(props.title);
  console.log('ExpenseItem') // 4번

  const clickHandler = () => {
    setTitle('Updated') 
    console.log(title)  //1번
  };

 

인스턴스 (instance)란 객체 지향 프로그래밍(OOP)에서 클래스(class)에 소속된 개별적인 객체를 말한다. 예를 들어, 사용자(user)라는 클래스를 정의하고 홍길동(hong)이라는 객체를 생성할 경우, hong이라는 객체는 user라는 클래스의 인스턴스가 된다.

 

양식 입력 추가하기

사용자의 입력을 수집하는 능력

App.js에서 모든 컴포넌트들을 결합한다.

input 숫자 최대값/최소값은 max 속성값으로,최소값은 min 속성값으로 설정해주면 된다.

<input type="number" min="0.01" step="0.01" />

 

<label>

HTML <label> 요소는 사용자 인터페이스 항목의 설명을 나타냅니다.

 

flex-wrap

property는 flex-item 요소들이 강제로 한줄에 배치되게 할 것인지, 또는 가능한 영역 내에서 벗어나지 않고 여러행으로 나누어 표현 할 것인지 결정하는 속성입니다.

 

Values

아래는 사용 가능한 속성값들입니다.

nowrap

기본 설정값으로, flex-container 부모요소 영역을 벗어나더라도 flex-item 요소들을 한 줄에 배치합니다.

wrap

flex-item요소들이 내부 로직에 의해 분할되어 여러 행에 걸쳐서 배치됩니다.

 

 

사용자 입력 리스닝(listening)

사용자로부터 입력된 값을 출력하기

const titleChangeHandler = (e) => {
  console.log(e.target.value)
};
return (
...
<input type="text" onChange={titleChangeHandler}/>
)

 

 

여러 State 다루기

사용자가 입력한 값을 저장하고 나중에 폼이 넘겨졌을 떄 그 값을 사용할 수 있도록 하는 것

사용자가 입력한값을 저장해서 살리는 방법 → useState

여러 상태, 여러 개의 상태 조각들 또는 컴포넌트별로 상태조각을 가질 수 있다.

별도의 상태를 갖고 각각 업데이트 할 수 있다.

다른 입력도 변경 이벤트를 수신하는지 확인하고 변경상태를 저장을 해서

상태 만들기, 변경상태 저장하기

const [enteredTitle, setEnteredTitle] = useState('')
  const [enteredAmount, setEnteredAmount] = useState('')
  const [enteredDate, setEnteredDate] = useState('')

const titleChangeHandler = (e) => {
  setEnteredTitle(e.target.value)
};
const amountChangeHandler = (e) => {
  setEnteredAmount(e.target.value)
};
const dateChangeHandler = (e) => {
  setEnteredDate(e.target.value)
};

변경 이벤트 수신하기

<input type="text" onChange={titleChangeHandler}/>
<input type="number" min="0.01" step="0.01" onChange={amountChangeHandler}/>
<input type="date" min="2019-01-01" max="2022-12-31" onChange={dateChangeHandler}/>

 

State 대신 사용하기(그리고 더 나은 방법) *

 

독립적인 state를 선호한다.

하나의 객체를 관리한다면 모든 데이터가 사라지지 않도록 해야한다.

 

스프레드 연산자

객체를 취해서 모든 키와 값의 쌍을 추출해서 새로운 객체에 추가한다.

키와 쌍을 오버라이드해서 모든 값들이 버려지지 않도록 할 수 있다.

const titleChangeHandler = (e) => {
  // setEnteredTitle(e.target.value)
  setUserInput({
    ...userInput,
    enteredTitle: e.target.value,
  })
};

오버라이드(Overriding)

기존에 정의되어 있는 클래스의 모든 필드와 메소드를 물려받는다 .

 

이전 State에 의존하는 State 업데이트

setUserInput((prevState) => {
   return {...prevState, enteredTitle, event.target.value };
});
};

이 함수 구문은 항상 계획된 상태 업데이트가 있다는 것을 보장하고 있다.

만약 상태 업데이트가 이전 상태에 의존하고 있다면 이 함수 폼을 사용해라

양식 제출 처리

const submitHandler = (event) => {
    event.preventDefault();
}

자바스크립트에 내장된 것으로 구체적으로 반응하지 않는 기본 요청이 들어오지는 것을 막을 수 있다.

 

양방향 바인딩 추가

입력된 것들을 어떻게 없앨 수 있을까?

state를 사용하면 양방향 바인딩을 구현할 수 있다.

 

양방향 바인딩

간단히 말해서 변경되는 입력값만 수신하는 것이 아니라 입력에 새로운 값을 다시 전달 할 수 있다.

const submitHandler = (e) => {
    e.preventDefault();

    const expenseData = {
      title: enteredTitle,
      amount: +enteredAmount,
      date: new Date(enteredDate),
    };
    props.onSaveExpenseData(expenseData);
    setEnteredTitle('')
    setEnteredAmount('')
    setEnteredDate('')
  };
<form onSubmit={submitHandler}>
      <div className="new-expense__controls">
        <div className="new-expense__control">
          <label>Title</label>
          <input type="text" 
          value={enteredTitle}
          onChange={titleChangeHandler} />
        </div>
        <div className="new-expense__control">
          <label>Amount</label>
          <input
            type="number"
            min="0.01"
            step="0.01"
            value={enteredAmount}
            onChange={amountChangeHandler}
          />
        </div>
        <div className="new-expense__control">
          <label>Date</label>
          <input
            type="date"
            min="2019-01-01"
            max="2022-12-31"
            value={enteredDate}
            onChange={dateChangeHandler}
          />
        </div>
        <div className="new-expense__actions">
          <button type="submit">Add Expense</button>
        </div>
      </div>
    </form>

상태를 업데이트하기 위해 입력에서 변경사항을 수신하는 것뿐만 아니라 입력된 상태를 보내준다. 그래서 상태를 변경하면 입력도 변한다.

양방향 바인딩의 경우, 사용자의 입력값이 곧바로 코드 상의 변수에 바인딩 될 수 있지만 단방향바인딩의 경우 적절한 Event를 통해서만 코드 상 변수에 데이터 값이 담긴다.

따라서 리셋시키거나 입력값을 프로그램에 따라 변화 시킬 수 있다. 간단하게 value 속성을 input에 추가해주기만 하면 가능하다. 이 속성은 모든 input 요소들의 내부 값 프로퍼티를 설정하게 해준다. 이렇게 설정하면 단순히 변화만을 listen해서 state를 업데이트 시켜주는것만 아니라 state를 다시 input으로 피드백 해주게 된다. 따라서 state를 변화할때 input도 변화시킨다는 말이다. 무한루프처럼 보일수 있지만 실제로는 그렇게 동작하지는 않는다.

 

바인딩(binding)

바인딩(binding)이란 프로그램에 사용된 구성 요소의 실제 값 또는 프로퍼티를 결정짓는 행위를 의미합니다.

예를 들어 함수를 호출하는 부분에서 실제 함수가 위치한 메모리를 연결하는 것도 바로 바인딩입니다.

 

결론

입력된 것을 제출했을 떄 입력된 것이 모두 지워지는 것을 볼 수 있다.

자식 대 부모 컴포넌트 통신(상향식) *

목표

사용자가 입력한 비용을 기존의 비용 목록에 추가하는 것

지금까지는 부모에서 자식으로 데이터를 전송했다. 그럼 자식에서 부모로 데이터를 전송하는 방법은 무엇일까?

함수를 이용한다. 자식은 props를 사용해서 부모에게 데이터를 건네줄 수 없다.

따라서 부모가 함수를 넣어 props로 자식에게 넘겨주면, 자식이 데이터를 파라미터로 넣어 호출하는 방식으로 동작한다.

방법은 부모 컴포넌트에서 자식 컴포넌트로 props를 이용해서 함수를 보내준다.

그리고 자식 컴포넌트에서 함수를 호출할때 보내줄 데이터를 매개변수(parameter)로 그 함수에 넣어서 부모로 보낼 수 있다.

두 번쨰 단계는 이 함수를 우리의 지정 컴포넌트에서 사용하는 것이다.

App.js→NewExpense.js→ExpenseForm.js

 

State 끌어올리기

State 끌어올리기

자식에서 부모컴포넌트로 전달하고 전달된 데이터를 다시 자식 컴포넌트에 전달 할 수 있다.

 

연습하기 : 이벤트 및 State 작업하기 (정답) *

두 번째 부분은 선택한 값을 Expenses.js에 보내는 것입니다.

 

사용자 입력을 받고 출력하기 정리

<form onSubmit={submitHandler}>
      <div className="new-expense__controls">
        <div className="new-expense__control">
          <label>Title</label>
          <input type="text" 
          value={enteredTitle}
          onChange={titleChangeHandler} />
        </div>
        <div className="new-expense__control">
          <label>Amount</label>
          <input
            type="number"
            min="0.01"
            step="0.01"
            value={enteredAmount}
            onChange={amountChangeHandler}
          />
        </div>
        <div className="new-expense__control">
          <label>Date</label>
          <input
            type="date"
            min="2019-01-01"
            max="2022-12-31"
            value={enteredDate}
            onChange={dateChangeHandler}
          />
        </div>
        <div className="new-expense__actions">
          <button type="submit">Add Expense</button>
        </div>
      </div>
    </form>

입력을 했을 떄 값이 변하는 것을 감지하고 값이 제출되었을 때 input에 업데이트 된 값을 저장한다.

const titleChangeHandler = (e) => {
    setEnteredTitle(e.target.value);
    // setUserInput({
    //   ...userInput,
    //   enteredTitle: e.target.value,
    // })
    // setUserInput((prevState)=> {
    //   return {...prevState, enterdTitle:e.target.value}
    // })
  };
  const amountChangeHandler = (e) => {
    setEnteredAmount(e.target.value);
    // setUserInput({
    //   ...userInput,
    //   enteredTitle: e.target.value,
    // })
  };
  const dateChangeHandler = (e) => {
    setEnteredDate(e.target.value);
    // setUserInput({
    //   ...userInput,
    //   enteredTitle: e.target.value,
    // })
  };

값이 바뀌었을 떄 값을 업데이트하는 함수

const submitHandler = (e) => {
    e.preventDefault();

    const expenseData = {
      title: enteredTitle,
      amount: +enteredAmount,
      date: new Date(enteredDate),
    };
    props.onSaveExpenseData(expenseData);
    setEnteredTitle('')
    setEnteredAmount('')
    setEnteredDate('')
  };

제출 이벤트가 발생하고 업데이트 된 값을

저장한다.

'React' 카테고리의 다른 글

React 완벽가이드 Session3  (0) 2022.08.08

댓글