Day +30

비트·2023년 5월 23일
1

CodeStates

목록 보기
31/54
post-thumbnail

React State & Props

이벤트 처리

  • React의 이벤트 처리(이벤트 핸들링; Event handling) 방식은 DOM의 이벤트 처리 방식과 유사합니다.
    • 단, 몇 가지 문법 차이가 있습니다.
  • React에서 이벤트는 소문자 대신 카멜 케이스(camelCase)를 사용합니다.
  • JSX를 사용하여 문자열이 아닌 함수로 이벤트 처리 함수(이벤트 핸들러; Event handler)를 전달합니다.

예를 들어 HTML에서 이벤트 처리 방식이 아래와 같다면,

  • <button onclick="handleEvent()">Event</button>

React의 이벤트 처리 방식은 아래와 같습니다.

  • <button onClick={handleEvent}>Event</button>

onChange

  • <input> <textarea> <select>와 같은 폼(Form) 엘리먼트는 사용자의 입력값을 제어하는 데 사용됩니다.

  • React에서는 이러한 변경될 수 있는 입력값을 일반적으로 컴포넌트의 state로 관리하고 업데이트합니다.

  • onChange 이벤트가 발생하면 e.target.value를 통해 이벤트 객체에 담겨있는 input 값을 읽어올 수 있습니다.

  • 컴포넌트 return 문 안의 input 태그에 valueonChange를 넣어주었습니다.

  • onChangeinput`의 텍스트가 바뀔 때마다 발생하는 이벤트입니다.

  • 이벤트가 발생하면 handleChange 함수가 작동하며, 이벤트 객체에 담긴 input 값을 setState를 통해 새로운 state로 변경합니다.

    • function NameForm() {
        const [name, setName] = useState("");
      
        const handleChange = (e) => {
          setName(e.target.value);
        }
      
        return (
          <div>
            <input type="text" value={name} onChange={handleChange}></input>
            <h1>{name}</h1>
          </div>
        )
      };

onClick

  • nClick 이벤트는 말 그대로 사용자가 클릭이라는 행동을 하였을 때 발생하는 이벤트입니다.

  • 버튼이나 <a> tag를 통한 링크 이동 등과 같이 주로 사용자의 행동에 따라 애플리케이션이 반응해야 할 때 자주 사용하는 이벤트입니다.

  • 그럼 위의 onChange 예시에 버튼을 추가하여 버튼 클릭 시 input tag에 입력한 이름이 alert을 통해 알림 창이 팝업 되도록 코드를 추가해 보겠습니다.

    • function NameForm() {
        const [name, setName] = useState("");
      
        const handleChange = (e) => {
          setName(e.target.value);
        }
      
        return (
          <div>
            <input type="text" value={name} onChange={handleChange}></input>
            <button onClick={alert(name)}>Button</button>
            <h1>{name}</h1>
          </div>
        );
      };
  • 위와 같이 onClick 이벤트에 alert(name) 함수를 바로 호출하면 컴포넌트가 렌더링 될 때 함수 자체가 아닌 함수 호출의 결과가 onClick에 적용됩니다.

  • 때문에 버튼을 클릭할 때가 아닌, 컴포넌트가 렌더링 될 때에 alert이 실행되고 따라서 그 결과인 undefined(함수는 리턴 값이 없을 때 undefined를 반환합니다.)가 onClick에 적용되어 클릭했을 때 아무런 결과도 일어나지 않습니다.

  • 따라서 onClick 이벤트에 함수를 전달할 때는 함수를 호출하는 것이 아니라 아래와 같이 리턴문 안에서 함수를 정의하거나 리턴문 외부에서 함수를 정의 후 이벤트에 함수 자체를 전달해야 합니다.

    • // 함수 정의하기
      
       return (
        <div>
      	...
          <button onClick={() => alert(name)}>Button</button>
      	...
        </div>
        );
      };
      
       // 함수 자체를 전달하기
      
       const handleClick = () => {
        alert(name);
      };
      
       return (
        <div>
            ...
          <button onClick={handleClick}>Button</button>
            ...
        </div>
        );
      };

Controlled Component

  • 종이에 글을 적어서 문서를 만들고, 이를 우편에 부쳐서 전달할 수 있었습니다.
  • 이제는 트위터와 같은 SNS를 통해서 클릭 한 번으로 사진부터 동영상까지 보낼 수 있지만요.

  • 우편 봉투에 해당하는 위 그림을 하나의 트윗 전송 폼 컴포넌트라고 합시다.
  • state는 무엇이 되어야 하나요?
    • "변경될 수 있는 값"인 보내는 사람(username)과 보낼 내용(tweet)이 state가 되어야 합니다.

React 데이터 흐름

  • React의 개발 방식의 가장 큰 특징은 페이지 단위가 아닌, 컴포넌트 단위로 시작한다는 점입니다.
    • 그림과 같이 앱의 프로토타입을 전달받았다면 먼저 컴포넌트를 찾아봅시다.

  • 프로토타입에서 그림과 같이 컴포넌트를 찾아냈습니다.
    • 이렇게 먼저 컴포넌트를 만들고, 다시 페이지를 조립해나갑니다.

  • 즉, 상향식(bottom-up)으로 앱을 만듭니다. 이것의 가장 큰 장점은 테스트가 쉽고 확장성이 좋습니다.
    • 그래서 여러분이 기획자나 PM, 또는 UX 디자이너로부터 앱의 디자인을 전달받고 나면, 이를 컴포넌트 계층 구조로 나누는 것이 가장 먼저 해야 할 일입니다.

  • 여기 간단한 트위터 클론 Twittler가 있습니다.

  • 여기에 그림과 같은 형태로 컴포넌트 디자인을 해볼 것입니다
    • 왜 이런 식으로 나누었냐고요?
    • 이는 단일 책임 원칙에 따른 구분입니다.
    • 하나의 컴포넌트는 한 가지 일만 합니다.

  • 이를 트리 구조로 나타내면 다음 그림과 같습니다.

  • 컴포넌트는 컴포넌트 바깥에서 props를 이용해 데이터를 마치 인자(arguments) 혹은 속성(attributes)처럼 전달받을 수 있습니다.

  • 즉 데이터를 전달하는 주체는 부모 컴포넌트가 됩니다. 이는 데이터 흐름이 하향식(top-down) 임을 의미합니다.

  • 이 원칙은 매우 중요합니다.
    • 얼마나 중요하냐면, 단방향 데이터 흐름(one-way data flow)이라는 키워드가 React를 대표하는 설명 중 하나일 정도입니다.
    • 또한 컴포넌트는 props를 통해 전달받은 데이터가 어디서 왔는지 전혀 알지 못합니다.

  • 애플리케이션에서 필요한 데이터가 무엇인지 먼저 정의합시다. 다음과 같은 데이터를 생각해 볼 수 있습니다.
    • 전체 트윗 목록
    • 사용자가 작성 중인 새로운 트윗 내용

  • 모든 데이터를 상태로 둘 필요는 없습니다. 사실 상태는 최소화하는 것이 가장 좋습니다.

  • 상태가 많아질수록 애플리케이션은 복잡해집니다.

  • 어떤 데이터를 상태로 두어야 하는지는 다음 세 가지 질문을 통해 판단해 보세요.

  • 부모로부터 props를 통해 전달됩니까?
    • 그러면 확실히 state가 아닙니다.

  • 시간이 지나도 변하지 않나요?
    • 그러면 확실히 state가 아닙니다.

  • 컴포넌트 안의 다른 state나 props를 가지고 계산 가능한가요?
    • 그렇다면 state가 아닙니다.

  • 상태가 특정 컴포넌트에서만 유의미하다면, 특정 컴포넌트에만 두면 되니까 크게 어렵지 않지만, 만일 하나의 상태를 기반으로 두 컴포넌트가 영향을 받는다면 이때에는 공통 소유 컴포넌트를 찾아 그곳에 상태를 위치해야 합니다.

  • 즉, 두 개의 자식 컴포넌트가 하나의 상태에 접근하고자 할 때는 두 자식의 공통 부모 컴포넌트에 상태를 위치해야 합니다.

  • 앞서 정의한 데이터를 기반으로 위치를 정해봅시다.
  • "전체 트윗 목록" 상태는 어디에 위치하는 것이 좋을까요?
  • 전체 트윗 목록은 Tweets에서 필요로 하는 데이터이고, SingleTweet 컴포넌트들은 모두 전체 트윗 목록에 의존합니다.

  • 그렇다면 SingleTweet 컴포넌트들의 부모는 무엇인가요?
  • 바로 Tweets입니다. 따라서 전체 트윗 목록 상태는 여기에 위치합시다.
  • 이처럼 React에서 데이터를 다룰 때는 컴포넌트들 간의 상호 관계와 데이터의 역할, 데이터의 흐름을 고려하여 위치를 설정해야 합니다.

profile
Drop the Bit!

0개의 댓글