React의 모든 이벤트는 on으로 시작하고 함수를 값으로 필요로 한다.
아래의 예제에서는 onClick 이벤트를 사용한다.
이때 함수는 JSX내부에서 익명의 함수를 사용하는 것 보다 따로 함수를 정의 하여 사용하는것이 깔끔하고 더 좋다.
function App(){
const clickHandler = () => {
console.log("clicked")
}
return (
<button onClick(clickHandler)>click button</button>
)
}
function App(){
let title = "title"
const clickHandler=()=>{
title = "update"
}
return(
<>
<div>{title}</div>
<button onClick={clickHandler}>click</button>
</>
)
}
위의 코드는 버튼을 클릭시 title값을 변경하여 보여주는 코드이다.
하지만 버튼을 클릭 해도 예상과 달리 변경된 title 값이 아닌 기존의 "title" 값만 볼 수 있다.
이러한 이유는 리액트의 작동방식에 있다.
리액트는 처음 컴포넌트를 평가하고 나서 컴포넌트 안의 변수가 변해도 재평가 하지 않고 무시한다, 그렇기 때문에 title 변수가 변경 되더라도 컴포넌트의 변화는 없다!!!😨
그렇다면 어떻게 리액트가 컴포넌트를 재평가 하게 할 수 있을까?
useState를 사용하면 된다.
useState를 사용하여 컴포넌트 내부 상태가 변경되면 리액트는 컴포넌트를 재평가 한다.
useState는 다음과 같이 사용된다.
const [title,setTitle] = useState("title")
아래 코드와 같이 useState를 사용하여 코드를 작성하면 title가 변경 될때 마다 컴포넌트가 재평가 되며 title이 변경된 값이 표시 된다.
function App(){
const [title,setTitle] = useState('title')
const clickHandler = () => {
setTitle('update')
}
return (
<div>{title}</div>
<button onClic={clickHandler}>button</button>
)
}
추가로 React는 해당 변수(여기서는 title)를 리렌더링할 때 기억하고, 가장 최근에 갱신된 값을 제공한다.
function App(){
const [title,setTitle] = useState('')
const [amount,setAmount] = useState('')
}
이렇게 state를 저장하면 한번에 여러개의 state를 저장할 수 있지만.. 주의점으로는 state를 변경할때 나머지 state들도 전개연산자를 통해 복사해 줘야한다.
function App(){
const [userInput,setUserInput] = useState({
title : '',
amount : ''
})
const changeHandler = (event) => {
setUsetInput({...userInput, amount : event.target.value})
}
}
하지만 이렇게 업데이트 해주면 매번 상태를 업데이트 해줄때 마다 이전 상태에 의존하게 된다.
대부분의 경우에는 문제가 없겠지만 만약 동시에 많은 상태 업데이트가 생기는 조건이라면 문제가 발생한다.
왜냐하면 리액트의 상태 업데이트는 즉시 일어나지 않기 때문에 잘못된 상태 snapshot에 의존할 수 도 있다.
그래서 위의 코드와 같이 이전 상태에 의존한 상태 업데이트의 경우 아래와 같이 업데이트 해주는게 좋다.
아래와 같이 업데이트 해주게 되면 리액트는 항상 최신 상태 snapshot을 제공해주기 때문에 문제가 발생하지 않는다.
const [userInput,setUserInput] = useState({
title : '',
amount : ''
})
const changeHandler = (event) => {
setUsetInput((prevState)=>{
...prevState , amount : event.target.value
})
아래 사진과 같이 Expenses 컴포넌트와 NewExpense 컴포넌트는 다이렉트로 데이터를 주고 받을 수 없다.
이때 데이터를 주고 받기 위해서는 공통된 부모 컴포넌트로 부터 데이터를 받을 수 있는데 이때! NewExpense 컴포넌트에서 어떻게 App 컴포넌트로 데이터를 보낼수 있을까?
그건 부모 컴포넌트에서 props로 자식 컴포넌트에게 데이터를 보낸 방식과 비슷하다.
아래 코드와 같이 부모 컴포넌트 App 에서 props로 함수를 넘겨주면 된다.
function App (){
const addExpenseHandler = (expenseData) => {
console.log(expenseData)
}
return(
<NewExpense onAddExpense={addExpenseHandler}/>
)
}
그럼 자식 컴포넌트 NewExpense 에서 props로 받은 onAddExpens함수에 인자로 데이터를 넣어주면 자식에서 부모 컴포넌트로 데이터를 받을 수 있다.
function NewExpense({onAddExpense}){
const [enteredTitle, setEnteredTitle] = useState('')
const titleChangeHandler = (event) => {
setEnteredTitle(event.target.value)
}
const saveExpenseData = () => {
onAddExpense(enteredTitle)
}
return(
<form onSubmit={saveExpenseData}>
<input type="text" value={enteredTitle} onChange={titleChangeHandler} />
<button type="submit">submit</button>
</from>
)
}
출처 useState