<button onClick = {() => {console.log("something")}> Change Title </button>
const clickHandler = () => {
console.log('Clicked!!!');
};
<button onClick = ⭐{clickHandler}> Change Title </button>
// ⭐onClick = {clickHandler()} (x)
// -> executes it as the HTML codes are rendered
pass a pointer at this function as a value to onClick
and then React basically memorizes this
=> only changes the modified DOM element
React doesnt' re-render the modified value
if the value is pronounced with keyword such as 'let'.
Instead, it re-renders the modified value
when dealing with the "state" value.
Here, we use useState hook to manage the value with state.
const [presentState, setPresentState] = useState(initial value)
// useState() returns a array with two elements
// [the value itself, and the updating function]
// initial value is only meaningful when the component is rendered for the first time
when the setPresentState function is called, it re-renders the very component function it is belonged to.
when the setPresentState is called,
it doesn't immediately updates the state
but schedules the update
-> therefore when you track the value by console.log() right after calling the setPresentState, it shows the previous value
we use const key-word because we are not using equal sign(=) when updating a value
(dealing with event 객체)
const titleChangeHandler = (e) => {
console.log(e.target.value);
};
return (
<form>
<input type='text' onChange = {titleChangeHandler}
</form>
)
if there are several states to manage
const [enteredTitle, setEnteredTitle] = useState('');
const [enteredAmount, setEnteredAmount] = useState('');
const [enteredDate, setEnteredDate] = useState('');
const titleChangeHandler = (e) => {
setEnteredTitle(e.target.value)
}
// ... same with setEnteredAmount, setEnteredDate
const [userInput, setUserInput] = useState({
enteredTitle : '',
enteredAmount : '',
enteredDate : ''
});
const titleChangeHandler = (e) => {
// setUserInput ({
// ...userInput,
// enteredTitle : e.target.value,
// })
// this isn't a good apporach (has a possibility to trigger bugs)
// it is because React schedules state updates,
// it doesn't perform them istantly
// so if you schedule a lot of state updates at the same time,
// could be depending on an outdated or incorrect state snapshot
// therefore, should call it and pass in a function to the very function
setUserInput((prevState) => {
return {...prevState, enteredTitle : e.target.value };
});
// in this way, React will guarantee
// that the prevState it gives in this inner function
// will always be the latest state snapshot,
// keeping all scheduled state updates in mind
// it ensures that it is working on the latest state snapshot
// so whenever state update depends on the previous state,
// the code should be written by this way
}
틀린 예시
const [counter, setCounter] = useState(1);
...
setCounter(counter + 1);
맞는 예시
const [counter, setCounter] = useState(1);
...
setCounter ((prevState) =>
return (prevState+1);
);
const [enteredTitle, setEnteredTitle] = useState('');
const submitHandler = (e) => {
e.preventDefault();
// a part of the default browser behavior
// is that if the button is clicked, the page is reloaded,
// because the browser actually automatically sends a request
// whenver the form is submitted to the server which is hoisting the webpage
// two-way binding :
// for inputs, we not only listen to changes
// but also pass a new value back into the input
// so that we can reset or change the input programmatically
setEnteredTitle('')
};
return (
<form onSubmit = {submitHandler}>
<input type = 'text' ⭐value={enteredTitle}
⭐onChange = {titleChangeHandler}/>
</form>
)
return (
<form onSubmit = {submitHadler}>
// the content
<button type="submit"> Add Expense </button>
</form>
)
(child component -> parent component)(상향식으로)
=> 프로퍼티를 통해 함수를 받아들이고
이를 하위 수준(자식) 컴포턴트 내부로부터 호출하고
해당 함수를 부모 컴포넌트에 전달하는 방식
parent-parent component(App.js)
const addExpenseHandler = expense => {
console.log('Im App.js');
console.log(expense);
};
return (
<div>
<NewExpenses ⭐onAddExpense = {addExpenseHandler}/>
</div>
)
parent component(NewExpense.js)
const saveExpenseDataHancler = (enteredExpenseData) => {
const expenseData = {
...enteredExpenseData,
// use spread operator for 얕은 복사
id : Math.random().toString()
};
⭐props.onAddExpense(expenseData);
};
return (
<div>
<ExpenseForm ⭐onSaveExpenseData = {saveExpenseDatahandler} />
</div>
child component(ExpenseForm.js)
const submitHandler = (e) => {
e.preventDefault();
const expenseData = {
title : enteredTitle,
};
⭐props.onSaveExpenseData(expenseData);
setEnteredTitle('');
}
parent component(Expenses.js)
const [filteredYear, setFilteredYear = useState('2020');
const filterChangeHandler = selectedYear => {
setFilteredYear(selectedYear);
};
return (
<ExpensesFilter ⭐selected = {filteredYear}
⭐onChangeFilter = {filterChangeHandler} />
child component(ExpensesFilter.js)
const ExpensesFilter = (props) => {
const dropdownChangeHandler = (event) => {
⭐props.onChangeFilter(event.target.value);
};
return (
<div className='expenses-filter'>
<div className='expenses-filter__control'>
<label>Filter by year</label>
<select ⭐value={props.selected} onChange={dropdownChangeHandler}>
<option value='2022'>2022</option>
<option value='2021'>2021</option>
<option value='2020'>2020</option>
<option value='2019'>2019</option>
</select>
</div>
</div>
);
};