[React] React Event와 useState

Kled·2023년 4월 4일

[React]

목록 보기
1/4
post-thumbnail

JS와 Event

JS의 Event 중 button과 함께 자주 쓰이는 onClick Event가 있다.
버튼이 클릭되면, 그에 따른 function을 호출하여 실행시키는 이벤트이다.

아래의 쉬운 예시를 통해 알아보자

<button onClick="clickHandler()"> button </button>

<script>
const clickHandler = () => {
    console.log('clicked!'); // clicked!
  };
</script>

당연히 버튼을 누르면, console에 clicked! 를 출력한다는 것을 충분히 예상했을 것이다.

그러나 React의 Rendering 특성을 생각하면, 일반적으로 JS에서의 Event Handler 동작과 다소 다르다.


React의 Rendering 특성

한 React의 Component 예시를 가져왔다.

const ExpenseItem = (props) => {
  let title = props.title;

  const clickHandler = () => {
    title = "changed!";
    console.log(title);
  };
  return (
    <Card className="expense-item">
      <div className="expense-item__description">
        <h2>{title}</h2> // title: "코멧 순백 3겹 라벤더 바닐라 롤화장지"
      </div>
      <button onClick={clickHandler}>Change Title</button>
    </Card>
  );
};

현재 title은 "코멧 순백 3겹 라벤더 바닐라 롤화장지" 이고, onClick 메소드는 버튼이 클릭 되었을 때 clickHandler() 함수를 호출하여 title을 "changed!"로 변경할 것임을 예상할 수 있다.

자, 그럼 버튼을 눌러 clickHandler 함수를 호출하여 title을 변경해보자

console에 clicked!가 잘 출력이 된 것을 보니, clickHandler 함수는 정상 동작 하고 있음을 알 수 있다.

그러나 아래의 사진과 같이 title은 의도하던 대로 changed!로 변경되지 못하고, 그대로
"코멧 순백 3겹 라벤더 바닐라 롤화장지"가 그려지고 있다.

console을 통해 clickHandler 함수가 정상동작 중임을 알 수 있었는데, 왜 DOM에 반영되지 않았을까?


React가 JSX를 검토하고 전달하는 방식

React가 렌더링하는 방식은 어떻게 시작되는 지 생각할 필요가 있다.
React는 App Componet가 지정하는 index.js 파일에서 렌더링을 시작한다.

import ReactDOM from 'react-dom/client';

import './index.css';
import App from './App';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);

페이지를 로드했을 때, index.js의 App Componet는 첫 번째로 호출되는 함수이며, Root Component의 하위에 있는 모든 Component를 실행시키게 된다.

우리는 수 많은 Component를 통해 페이지를 구성할 것이고, React는 더 이상 반환할 JSX 코드가 없을 때까지 그 많은 Component 함수들을 호출한다.

이 때 중요한 요점은 'React는 절대 반복하지 않는다.' 는 것이다.
변수가 변경되었다고 해도 React는 무시하고 렌더링 된 Component를 재호출하지 않는다.

그렇기에 우리는 React에게 어떤 것이 변경되었고, 재평가 받아야 하는 지 지시해야한다.


useState

useState는 리렌더링을 원하는 함수를 업데이트를 하기 위해 사용하는 React Hook이다.

useState의 사용법은 아래와 같다.

const [<상태  저장 변수>, <상태  갱신 함수>] = useState(<상태 초기 >);

더 알아보기

즉, 우리는 state를 변경하기 위해, React Component 함수를 재호출해야 하고, useState를 통해 특정 state에 새로운 값을 할당 받고 싶다고 React에게 전달한다.
이는 React가 React Component 함수를 재호출하여 JSX 파일을 재평가한 뒤,
감지된 변화들을 출력하게 된다.

useState를 사용하여 코드를 재작성 해보았다.

const ExpenseItem = (props) => {
  const [title, setTitle] = useState(props.title);

  const clickHandler = () => {
    setTitle("changed!");
    console.log(title);
  };
  return (
    // 반환하는 한 개의 요소 안에는 한 개의 루트 요소만 존재해야함. (<div></div>) 로 감싸기
    
    <Card className="expense-item">
      <div className="expense-item__description">
        <h2>{title}</h2> // title: "코멧 순백 3겹 라벤더 바닐라 롤화장지"
      </div>
      <button onClick={clickHandler}>Change Title</button>
    </Card>
  );
};

그 결과, JSX 파일은 정상적으로 재평가 되어 <h2>changed!<h2> 로 변경되었고,
console에는 일반적인 예상과 달리 기존의 title을 보여주고 있다.

왜나하면 state를 업데이트하는 함수를 호출할 때, 즉시 그 title 값을 변경하지 않기 때문이다. 그 대신 state의 변경을 예약하게 된다.

하지만 보다시피 Component 함수는 재평가되어, 변경된 JSX의 title을 출력한다.


profile
공부하는 돌멩이 🪨

0개의 댓글