React #1

Sasha Park·2021년 5월 6일
0

props와 state

둘 다 데이터를 담는 컨테이너의 역할을 담당.
props는 모듈 간 데이터를 전달하는데 이용, state는 한 모듈안에서 데이터를 쓰는데 이용.
state는 꼭 필요한 게 아니며, 가능하면 지양해야 프로그램이 깔끔해지는 특성을 지니고 있음.

Lifting state up

부모에서 자식 component 간 props를 통해 데이터를 아래로 전달해주는 것을 확인할 수 있었음.
그러면 반대로 자식에서 부모 componenet로는 어떻게 데이터를 전달할 수 있을까?

함수를 인자로 전달하여, 해당 함수에 업데이트 된 data(state)를 넣어서 돌려주면 lift-up 해 줄 수 있다.

다음 두 script는 부모-자식 관계이며, Form이 자식 component임.

NewExpense.js

import React from 'react';
import './NewExpense.css'
import ExpenseForm from './ExpenseForm'

// ExpenseForm에서 작성된 expense data를 이곳으로 보내보자. 
const NewExpense = (props) => {

    const saveExpenseDataHandler = (enteredExpenseData) => {
        
        const expenseData = { 
            ...enteredExpenseData, 
            id: Math.random().toString() // submitHandler로 입력된 데이터를 가져오고, id 추가해준다.
        };

        props.onAddExpense(expenseData); // App.js에서 넘겨준 함수인자 onAddExpense에 위의 데이터 컨테이너인 expenseData를 넣고
        // 실행시키면 app.js와 연결된다.
        
        console.log('In NewExpense', expenseData)
    };
    
    return (
        <div className = "new-expense">
            <ExpenseForm onSaveExpenseData = {saveExpenseDataHandler} /> 
        </div> 
    )
};

//  <ExpenseForm onSaveExpenseData = {saveExpenseDataHandler} />  => pointer edit, 
// lifting state를 가능케하는 핵심코드. onSaveExpenseData 함수를 만들어 데이터를 끌어오는 ExpenseForm 컴포넌트에 전달해주자. 

// App.js에 props로 받은 addExpenseHandler를 15번째 줄에서 실행 및 인자로 expenseData를 app으로 넘겨준다. 
export default NewExpense;

inputForm.js

import React, {useState} from 'react'; 
import './ExpenseForm.css'

const ExpenseForm = (props) => {
    
    // 하기 세 state 독립적으로 작동한다.
    // *** useState를 쓰면 state를 업데이트 시켜주는 setUserInput을 실행시키고 그 결과를 userInput에 할당. ***
  
    const [enteredTitle, setEnteredTitle] = useState('');
    const [enteredAmount, setEnteredAmount] = useState('');
    const [enteredDate, setEnteredDate] = useState('');


    const titleChangeHandler = event => {
        setEnteredTitle(event.target.value);
        
        // setUserInput ({
        //     ...userInput, 
        //     enteredTitle: event.target.value // 덮어써서, 나머지 두 개의 state가 변하지 않게하기. 
        // }) //이벤트 객체 내에 있는 타이핑 된 내용을 타겟팅하여 로깅한다.  // value 안에는 항상 string 처리가 되어 있다. 
        // setUserInput((prevState) => {
        //     return {...prevState,enteredTitle: event.target.value};
        // });
        // 전의 state를 바탕으로 update 시키고 싶을 경우, 상기 form을 쓸 것.
    };

    const amountChangeHandler = event => {
        setEnteredAmount(event.target.value);
       
    };

    const dateChangeHandler = event => {
        setEnteredDate(event.target.value);
    
    };

    const submitHandler = (event) => {
        event.preventDefault(); // 화면 깜박임을 방지. 

        const expenseData = { // 위에서 생성된 state를 여기다 저장하자.
            title: enteredTitle,
            amount: enteredAmount,
            date: new Date(enteredDate)
        };
        console.log(expenseData)
        
        props.onSaveExpenseData(expenseData); // 1. NewExpense에서 전달받은 saveExpenseDateHandler를 불러옴.  
        // 2. 입력된 data를 expenseData에 만든 후, props에 저장해주자. lifting-up.

        setEnteredAmount('') // 초기화
        setEnteredDate('')
        setEnteredTitle('')
    };

    // onSubmit: submit 후 이벤트 실행. 
    // onChange: 한 텍스트 쓸때마다 반응. 단, input 창에는 데이터가 출력되지 않는다.
    return (
        <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' value = {enteredAmount} min="0.01" step="0.01" onChange={amountChangeHandler}/> 
                </div>

                <div className="new-expense__control">
                    <label> Date </label>
                    <input type='date' value = {enteredDate} min="2019-01-01" max="2022-12-31"  onChange={dateChangeHandler}/>  
                </div>    

            </div>

            <div className ="new-expense__actions">
                <button type ='submit' > Add expense </button>
            </div>                  
        </form> 
    )
};

export default ExpenseForm;
  1. NewExpense.js : component에 전달할 함수 onSaveExpenseData를 인자로 넣어주자. pointer 역할을 하기 때문에 실행시키지 않는다.
  2. ExpenseForm.js : 임의의 함수를 만들어주고 (submitHandler) 본 스크립트에서 입력된 새로운 data를 옮길 객체를 만든다.
  3. ExpenseForm.js : 2번에서 만들어진 data를 인자로 넣는 함수 onSaveExpenseData를 실행해준다.
props.onSaveExpenseData(expenseData);  
  1. NewExpense.js : 전달된 데이터는 saveExpenseDataHandler 인자인 enteredExpenseData에 할당되어 있다. 이거 가지고 가공하면 끝!
  2. NewExpense.js : 최상위 root component인 App.js에 전달하기 위해 같은 방식으로 onAddExpense 함수를 인자로 받았음. 자식 component끼리 데이터를 주고받으려면 이런 식으로 부모 component를 통해서 가능한데.. 이 얼마나 비생산적인 행동인지 가늠이 되질 않는다. 어서 redux를 배우자!
props.onAddExpense(expenseData);

이해하기까지 너무 많은 시간이 걸렸다. 언제쯤 react를 정복할 수 있을까...

profile
'어?' 에서 '아!'가 되는 순간을 즐기는 개발자입니다.

0개의 댓글

Powered by GraphCDN, the GraphQL CDN