유데미의 리액트 강의를 듣던 중에 버튼을 클릭하면 조건에 따라 폼 태그를 보여주거나 보여주지 않거나 하는 기능을 만들어 보는 것을 과제로 받았다.
위와 같이 처음에는 Add New Expense 버튼이 하나만 보이고,
해당 버튼을 클릭했을 때 내용을 입력할 수 있는 폼을 보여준다.
Add New Expense 버튼이 사라지고, 폼이 보여진다.
폼 내에서 Cancel 버튼을 클릭하면 초기화면과 같은 Add New Expense 버튼만 보여준다.
폼에 내용을 입력하고 Add Expense 버튼을 클릭하면 expense가 추가된 후 Add New Expense 버튼만 보여준다.
NewExpense 컴포넌트 내에서 expense 추가해주는 상황인지 아닌지는 state를 추가하여 확인했다.
isEditing 이라는 state를 추가하여 해당 상태값을 이용해 반환값을 다르게 했다.
false
이면 Add New Expense 버튼 반환true
이면 form 반환import React, { useState } from 'react';
import ExpenseForm from './ExpenseForm';
import './NewExpense.css';
const NewExpense = (props) => {
const [isEditing, setIsEditing] = useState(false);
const saveExpenseData = (enteredExpenseData) => {
const expenseData = {
id: Math.random().toString(),
...enteredExpenseData,
};
props.onAddExpense(expenseData);
setIsEditing(false);
};
const startEditingHandler = () => {
setIsEditing(true);
};
const stopEditingHandler = () => {
setIsEditing(false);
};
// 유의할 점은 함수를 실행하지 않고 함수 자체를 ExpenseForm 컴포넌트에 전달했다는 것이다.
return (
<div className="new-expense">
{!isEditing && (
<button onClick={startEditingHandler}>Add New Expense</button>
)}
{isEditing && (
<ExpenseForm
onSaveExpenseData={saveExpenseData}
stopEditing={stopEditingHandler}
/>
)}
</div>
);
};
export default NewExpense;
import React, { useState } from 'react';
import './ExpenseForm.css';
const ExpenseForm = (props) => {
const [enteredTitle, setEnteredTitle] = useState('');
const [enteredAmount, setEnteredAmount] = useState('');
const [enteredDate, setEnteredDate] = useState('');
const titleChangeHandler = (event) => {
setEnteredTitle(event.target.value);
};
const amountChangeHandler = (event) => {
setEnteredAmount(event.target.value);
};
const dateChangeHandler = (event) => {
setEnteredDate(event.target.value);
};
const submitHandler = (event) => {
event.preventDefault();
const expenseData = {
title: enteredTitle,
amount: +enteredAmount,
date: new Date(enteredDate),
};
props.onSaveExpenseData(expenseData);
setEnteredTitle('');
setEnteredAmount('');
setEnteredDate('');
};
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"
min="0.01"
step="0.01"
value={enteredAmount}
onChange={amountChangeHandler}
/>
</div>
<div className="new-expense__control">
<label>Date</label>
<input
type="date"
min="2022-01-01"
max="2024-12-31"
value={enteredDate}
onChange={dateChangeHandler}
/>
</div>
</div>
<div className="new-expense__actions">
<button onClick={props.stopEditing}>Cancel</button>
<button type="submit">Add Expense</button>
</div>
</form>
);
};
export default ExpenseForm;
처음에 해당 과제를 할 때, 정답에서와 유사하게 flag를 이용하여 버튼만 보여주거나 폼만 보여주도록 하고 싶었다.
그런데 아무리 flag 를 변경을 해도 화면에서는 재렌더링을 해주지 않는 것이었다.
그래서 찾아보니 리액트에서 재렌더링이 되려면 몇가지 조건이 있었다.
나의 경우 state가 아닌 그냥 일반 변수의 값만 변경해주었기 때문에 재렌더링이 되지 않았던 것이다.