state

kaitlin_k·2021년 8월 12일
0

React

목록 보기
4/5

상태 만들고 업데이트시켜 리렌더링 하기

const NewForm = (props) => {
  const title = props.title
  
  const clickHandler = (){
    title = 'hello world';
    console.log(title);
  }
  
  return {
    <>
    	<p>{title}</p>
        <button onClick={clickHandler}>change title</button>
    </>
}

변수의 값이 재할당되면 어떤 일이 일어날까?

위의 경우는 버튼을 클릭했을때 title이 'hello world'로 재할당된다. 하지만 리액트는 변수에 값이 바뀌는 것에 따라 JSX 엘리먼트를 다시 렌더링하지 않는다. 리액트는 처음 한번만 렌더링하고 다시 같은 컴포넌트를 렌더링하지 않는다.

따라서 title값이 바뀌어도 여전히 웹브라우저에는 props.title 값이 나타날 것이다.

컴포넌트를 리렌더링하기 위해서는 어떻게 해야할까?

데이터가 업데이트되어 컴포넌트를 리렌더링하기 위해서는 다음과 같이 useState를 써서 상태를 만들어야한다.

const NewForm = (props) => {
  const [title, setTitle] = useState(props.title);
  
  const clickHandler = (){
    setTitle('hello world');
  }
  
  return (
    <>
    	<p>{title}</p>
        <button onClick={clickHandler}>change title</button>
    </>
 )
}

필요한 경우, 한 컴포넌트에 상태가 다음과 같이 여러개일 수 있다.

const Form = (){
  const [enteredTitle, setEnteredTitle] = useState('');
  const [enteredAmount, setEnteredAmount] = useState('');
  const [enteredDate, setEnteredDate] = useState('');
  
  const titleChangeHandler = (e) => {
    setEnteredTitle(e.target.value)
  }
  
  const amountChangeHandler = (e) => {
    setEnteredAmount(e.target.value)
  }
    
  const dateChangeHandler = (e) => {
    setEnteredDate(e.target.value)
  }
  
  return (
    <form>
    	<label>Title</label>
    	<input type="text" onChange={titleChangeHandler} />
    	<label>Amount</label>
    	<input 
	  type="number" 
	  min="0.01" 
	  step="0.1" 
	  onChange={AmountChangeHandler} 
	/>
        <label>Date</label>
    	<input 
	  type="number" 
	  min="2019-01-01" 
	  step="2021-12-31" 
	  onChange={DateChangeHandler} 
	/>
   </form>
 )
}

그 경우에는 useState를 위의 경우처럼 여러번 쓸수도 있지만 다음과 같이 하나의 객체를 넘겨줄 수 있다.

const Form = (){
  const [userInput, setUserInput] = useState({
    enteredTitle: '',
    enteredAmount: '',
    enteredDate: ''
  });

  const titleChangeHandler = (e) => {
    setUserInput({
      ...userInput,
      enteredTitle: event.target.value,
    })
  }
  
  const amountChangeHandler = (e) => {
    setUserInput({
      ...userInput,
      enteredAmount: event.target.value,
    })
  }
    
  const dateChangeHandler = (e) => {
    setUserInput({
      ...userInput,
      enteredDate: event.target.value,
    })
  }
  
  return (
    <form>
    	<label>Title</label>
    	<input type="text" onChange={titleChangeHandler} />
    	<label>Amount</label>
    	<input 
	  type="number" 
	  min="0.01" 
	  step="0.1" 
	  onChange={AmountChangeHandler} 
	/>
        <label>Date</label>
    	<input 
	  type="number" 
	  min="2019-01-01" 
	  step="2021-12-31" 
	  onChange={DateChangeHandler} 
	/>
   </form>
 )
}

하지만, 위의 경우에 꼭 기억해야할 것이 있다.

이전 상태를 기반으로 상태를 업데이트 할 때에는 반드시 상태변경함수에 콜백함수를 작성하고, 인자로 기존 상태를 입력받아야한다.

리액트는 상태 업데이트를 즉시 실행시키지 않으므로 첫번째 경우는 잘못되거나 오래된 상태를 가져오게 될 수도 있다. 하지만 두번째 형태로 사용하면, 리액트는 반드시 가장 최신의 상태를 콜백함수의 인자로 전달할 것이다.

따라서, 다음과 같이 이전 상태를 바탕으로 새로운 데이터를 추가, 변경하고자 한다면, 반드시 상태변경함수에 콜백함수를 사용해야한다.

const titleChangeHandler = (e) => {
   //setUserInput({
   //  ...userInput,
   //  enteredTitle: event.target.value,
   //})
  
  setUserInput((prevState)=>{
  	return {...prevState, enteredTitle: event.target.value}
  });
  
  //이하생략
}
profile
어제보다 나은 오늘을 만드는 중

0개의 댓글