<React> 양방향 바인드 / 자식 ➡️ 부모 컴포넌트 통신(상향식)

·2023년 4월 24일
0

React

목록 보기
3/23

<Form>으로 양식을 전송할 때, 아래와 같이 새로고침을 꼭 막아주어야 한다.

const submitHandler = (e) => {
    e.preventDefault();
    console.log("새로고침 방지 성공");
  };

양방향 바인딩

state를 이용하면 양방향 바인딩을 쉽게 구현할 수 있다.
변경되는 입력값만 수신하는 것이 아니라, 입력에 새로운 값을 다시 전달할 수도 있다는 뜻이다.
그래서 프로그램에 따라 입력값을 재설정하거나 입력할 수 있다.

양방향 바인딩
import React, { useState } from "react";
import "./ExpenseForm.css";
const ExpenseForm = () => {
  const [title, setTitle] = useState("");
  const [amount, setAmount] = useState("");
  const [date, setDate] = useState("");

  const titleChangeHandler = (e) => {
    setTitle(e.target.value);
    console.log(" title : ", title);
    console.log(" e : ", e);
  };

  const amountHandler = (e) => {
    setAmount(e.target.value);
    console.log(amount);
  };

  const dateHandler = (e) => {
    setDate(e.target.value);
    console.log(date);
  };



  const submitHandler = (e) => {
    e.preventDefault();
    console.log("새로고침 방지 성공");

    const expenseData = {
      title,
      amount,
      date: new Date(date),
    };
    console.log(expenseData);
  };
  return (
    <form onSubmit={submitHandler}>
      <div className="new-expense__controls">
        <div className="new-expense__control">
          <label htmlFor="new-expense__control">Title</label><input type="text" onChange={titleChangeHandler} value={title} />
        </div>
        <div className="new-expense__control">
          <label htmlFor="new-expense__control">Amount</label><input
            type="number"
            min="0.0.1"
            step="0.01"
            onChange={amountHandler}
            value={amount}
          />
        </div>
        <div className="new-expense__control">
          <label htmlFor="new-expense__control">Date</label><input
            type="date"
            min="2020-01-01"
            max="2099-12-31"
            onChange={dateHandler}
            value={date}
          />
        </div>
      </div>
      <div className="new-expense__actions">
        <button type="submit">Add Expense</button>
      </div>
    </form>
  );
};

export default ExpenseForm;

가 있는 코드 부분에, value 프로퍼티를 추가함으로써 양방향 바인딩이 되었다 할 수 있다.
이로써 상태를 업데이트하기 위해 입력에서 변경사항을 수신하는 것 뿐만 아니라, 입력에 상태를 다시 보내주기도 한다.
그래서 state를 변경하면, 입력도 변하게 된다.
무한루프는 아니다. 따라서 문제가 생기진 않는다.

state와 input에 value 프로퍼티를 적용시킴으로써 양방향 바인드의 장점은
Form이 전송되고 나서, setState 함수를 이용하여 값을 초기화시켜줄 수 있다는 것이다. (공백으로 오버라이드)

const submitHandler = (e) => {
    e.preventDefault();
    console.log("새로고침 방지 성공");

    const expenseData = {
// 해당 코드에서 title은 key와 value 이름이 같기 때문에 하나로 축약 가능. 아래 amount도 같은 이유.
      title, 
      amount,
      date: new Date(date),
    };
    console.log(expenseData);

⬆️ input 입력 값을 Form으로 전송한 뒤,
⬇️ 입력값을 보내고 나서 input값을 빈 값으로 오버라이드., input value 프로퍼티를 공백으로 초기화.  
    setTitle("");
    setAmount("");
    setDate("");
  };

정리

  • state를 이용하면 양방향 바인딩을 쉽게 구현할 수 있다.
  • 양방향 바인드는 리액트에서 핵심 개념이다.
  • Form 작업할 때 매우 유용하다. (예시 : Form 전송에 따라 사용자의 입력을 모으거나 변경할 수 있게 해준다.)
const submitHandler = (e) => {
    e.preventDefault();
    console.log("새로고침 방지 성공");const expenseData = { // 여기서 input 값을 하나의 객체로 모아서 처리할 수 있음.
      title, 
      amount,
      date: new Date(date),
    };
    console.log(expenseData);setTitle(""); // ⬇️ 여기부터 아래까지 input의 기본 value를 공백으로 초기화.
// (value와 state가 바인딩 되어있기 때문에 가능하다.)
    setAmount("");
    setDate("");
  };
  • inputvalue 프로퍼티를 적용시킴으로써 state를 양방향 바인드 처리할 수 있다.
  • 변경되는 입력값만 수신하는 것이 아니라, 입력에 새로운 값을 다시 전달할 수도 있다는 뜻이다.

자식 => 부모 컴포넌트 통신 (상향식)

부모에서 자식 컴포넌트로 데이터나 값을 전달할 때는 props를 이용하여 전달하면 된다.
하지만 자식 컴포넌트에서 부모 컴포넌트로 값을 끌어올릴 때는 어떻게 해야하는가?

함수를 이용하면 가능하다.
부모컴포넌트에서 함수를 정의하고, 함수를 자식 컴포넌트에게 props로 내려준다.

그 후, 자식 컴포넌트에서 함수 props를 사용하여 해당 컴포넌트 데이터 or 값을 부모 컴포넌트에게 전달 가능하다.

아래 코드에 스스로 이해한 것을 주석으로 달아놨는데, 보면서 이해할 수 있겠다. :)

부모 컴포넌트
import React from "react";
import ExpenseForm from "./ExpenseForm";
import "./NewExpense.css";

const NewExpense = () => {
// 자식에게 넘겨줄 함수const saveExpenseDataHandler = (enteredExpenseData) => {
    console.log("enteredExpenseData : ", enteredExpenseData);
    const expenseData = {
      ...enteredExpenseData,
      id: Math.random().toString(),
    };
    console.log("expenseData : ", expenseData);
  };

// ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ

  return (
    <div className="new-expense">
// 넘겨줄 자식 컴포넌트에게 props로 함수 전달
// 중요한 것은, saveExpenseDataHandler 라는 함수 Pointer 역할만 한다는 것이다. 자식 컴포넌트에서 해당 함수를 사용하면, 그 때 실행된다.<ExpenseForm onSaveExpenseData={saveExpenseDataHandler} />
    </div>
  );
};

export default NewExpense;

자식 컴포넌트
import React, { useState } from "react";
import "./ExpenseForm.css";
const ExpenseForm = (props) => {
  const [title, setTitle] = useState("");
  const [amount, setAmount] = useState("");
  const [date, setDate] = useState("");

  const titleChangeHandler = (e) => {
    setTitle(e.target.value);
    console.log(" title : ", title);
    console.log(" e : ", e);
  };

  const amountHandler = (e) => {
    setAmount(e.target.value);
    console.log(amount);
  };

  const dateHandler = (e) => {
    setDate(e.target.value);
    console.log(date);
  };

// 자식 컴포넌트에서 해당 핸들러 함수가 실행되면, 부모 컴포넌트로 값 전달const submitHandler = (e) => {
    e.preventDefault();

    const expenseData = {
      title,
      amount,
      date: new Date(date),
    };

    if ((title || amount || date) == "") {
      alert("값을 채워주세요.");
    } else {
// 부모 컴포넌트에서 받아온 함수. 끌어 올려보내줄 값을 매개변수로 전달한다. 
✅     props.onSaveExpenseData(expenseData);
    }

    setTitle("");
    setAmount("");
    setDate("");
  };
  return (
    <form onSubmit={submitHandler}>
      <div className="new-expense__controls">
        <div className="new-expense__control">
          <label htmlFor="new-expense__control">Title</label>
          <input type="text" onChange={titleChangeHandler} value={title} />
        </div>
        <div className="new-expense__control">
          <label htmlFor="new-expense__control">Amount</label>
          <input
            type="number"
            min="0.0.1"
            step="0.01"
            onChange={amountHandler}
            value={amount}
          />
        </div>
        <div className="new-expense__control">
          <label htmlFor="new-expense__control">Date</label>
          <input
            type="date"
            min="2020-01-01"
            max="2099-12-31"
            onChange={dateHandler}
            value={date}
          />
        </div>
      </div>
      <div className="new-expense__actions">
        <button type="submit">Add Expense</button>
      </div>
    </form>
  );
};

export default ExpenseForm;

정리

  • 자식 컴포넌트에서 부모 컴포넌트로 값을 끌어올릴 때는, 부모 컴포넌트에서 함수를 만들어서 props로 함수를 내려준다.
  • 이 패턴은 React에서 매우매우 아주아주 중요한 패턴이다.

0개의 댓글