스무디 한 잔 마시며 끝내는 리액트 + TDD (9)

y_cat·2022년 12월 13일
0

Props를 통한 데이터 전달

Props는 부모 컴포넌트로부터 자식 컴포넌트로 전달되는 데이터이다.
현재 개발 중인 페이지에서 부모 컴포넌트는 App 컴포넌트가 되며, 자식 컴포넌트는 Button 컴포넌트이다. 이제 부모 컴포넌트인 App 컴포넌트로부터 자식 컴포넌트인 Button 컴포넌트에 Props를 사용하여 데이터를 전달해보자.

다음과 같이 App.tsx를 수정해본다.

부모 컴포넌트인 App 컴포넌트에서 자식 컴포넌트인 Button 컴포넌트에 label이라는 Props를 통해 "추가"라는 데이터를 전달하고 있다. 이는 HTML 요소의 속성(Attribute 또는 Property)을 설정하는 방식과 매우 유사하다.


<div id="name" class="label" onclick="alert('Hello');">Hello world!</div>

위의 HTML 코드처럼 div 태그에 id와 class 속성을 설정하고 onclick 속성에 직접 js의 alert 코드를 사용했다. React에서는 이 속성 개념에 데이터를 전달한다는 개념을 추가 확장한 것이다.

자식 컴포넌트인 Button 컴포넌트에서 label 속성을 전달받을 준비가 되어 있지 않아 빨간줄이 나오게 된다. 이를 해결하기 위해 ./src/Component/Button/index.tsx 파일을 열어 다음과 같이 수정한다.

우선 전달받을 label 데이터의 데이터 타입을 체크하기 위해 typescript의 인터페이스(interface)를 사용하여 Props라는 이름의 인터페이스를 정의했고 해당 인터페이스에 문자열(string) 데이터를 받을 label을 읽기 전용(readonly)으로 정의했다.

React에서 부모 컴포넌트로부터 데이터를 전달받을 때 export const Button = ("부모 컴포넌트로부터 전달받는 데이터") => { ... }로 표현하여 함수 매개 변수를 통해 데이터를 전달 받게 된다.

하지만 js는 동적 프로그래밍 언어로써 프로그램을 실행하기 전까지는 전달받는 데이터가 어떤 데이터를 포함하고 있는지, 포함된 데이터가 어떤 데이터 타입을 가졌는지 알 수가 없다. 그러므로 부모 컴포넌트로부터 해당값을 전달받지 않았다면 실행 중에 에러가 발생할 것이다. 이런 변수 타입에 의한 버그를 없애기 위해 정적 타입 분석에 typescript를 사용하는 것이다.

데이터 타입을 체크하기 위해 앞어서 만든 typescript의 인터페이스를 다음과 같이 매개변수에 사용하여 전달받을 데이터 타입을 체크한다. ( props: Props 부분)

export const Button = (props: Props) => {
	...
}

위와 같이 선언하면 App 컴포넌트를 vscode에서 확인해봤을 때 더이상 타입 에러가 발생하지 않는다. 이렇게 typescript를 사용하여 타입을 지정하여서 js의 변수 타입에 따른 버그와 에러를 예방할 수 있다.

export const Button = (props: Props) => {
	return (
    	<Container>
        	<Label>{props.label}</Label>
        </Container>
    );
}

위와 같이 부모 컴포넌트로부터 전달받은 데이터를 다음과 같이 자식 컴포넌트의 사용하고자 하는 곳에서 사용한다. 부모 컴포넌트로부터 전달받는 모든 데이터는 우리가 정의한 props라는 매개변수에 객체 형태로 전달받게 된다. 따라서 props.label과 같이 객체의 속성값에 접근하는 형태로 사용할 수 있다.

하지만 전달받는 데이터가 많아지고 그 데이터들을 자식 컴포넌트에서 자주 사용한다면 매번 객체에 접근하여 값을 사용하는 것은 매우 비효율적이다. 따라서 실무에서는 다음과 같이 js의 구조 분해 할당(Destructuring assignment) 문법을 사용하여 전달받은 데이터를 분해 할당해서 사용한다.

지금까지 Button 컴포넌트를 수정하여 부모 컴포넌트로부터 Props를 통해 전달받은 label 데이터를 화면에 표시하도록 수정했다.

터미널에 npm start를 입력하여 제대로 버튼이 나오는지 확인해보고 App.tsx에서 Button 컴포넌트에 label 값을 변경해본다.

function App() {
  return (
    <Container>
      <Contents>
        <Button label="테스트" />
      </Contents>
    </Container>
  );
}



여러개의 데이터로 확장

이렇게 만든 Button 컴포넌트는 삭제에서도 사용될 예정이다. 하지만 현재는 추가 버튼의 배경 색상만을 가지고 있다. 확장성을 위해 배경 색상도 Props를 통해 부모 컴포넌트로부터 전달받도록 한다.

./src/Component/Button/index.tsx 파일을 열어 typescript의 인터페이스를 다음과 같이 수정해야 한다.

버튼의 배경 색상과 호버 색상을 Props를 통해 지정하여 전달받을 예정이다. 추가적으로 물음표 기호(?)를 사용했는데, typescript에서는 물음표 기호(?)를 사용하여 필수로 전달받아야 하는 데이터와 필수가 아닌 데이터를 구별할 수 있다. 이는 optional하게 문자열 데이터를 넘길 수도/안 넘길 수도 있다는 것이다.

위와 같이 부모 컴포넌트로 전달받은 Props 데이터를 실제로 사용하기 위해 구조 분해 할당을 통해 값을 할당하여 수정한다. 하지만 backgroundColor와 hoverColor 값은 필수가 아니므로 비어있는 경우가 있다. 이를 대비하기 위해 구조 분해 할당할 때 초기값을 설정했다.

이제 전달받은 데이터를 styled-components로 만든 Container 컴포넌트에 전달했다. styled-components로 만든 Container 컴포넌트도 React 컴포넌트이므로 Props로 데이터를 전달하는 게 가능하다. 또한, Props에 대한 타입을 typescript로 지정하지 않으면 에디터에서 에러가 발생한다. 따라서 Button 컴포넌트에 정의한 Container 컴포넌트를 다음과 같이 수정한다. (./src/Component/Button/index.tsx)


우선 Container 컴포넌트의 Props를 위해 typescript의 인터페이스를 사용하여 ContainerProps를 정의했다. 정의한 ContainerProps를 typescript의 Generic 문법을 사용하여 styled-components로 생성한 Container 컴포넌트에 적용했다. 그리고 Container 컴포넌트의 스타일에서 Props에 있는 데이터를 사용했다.


이제 부모 컴포넌트인 App 컴포넌트에서 Button 컴포넌트의 새로운 Props인 backgroundColor와 hoverColor를 사용하여 버튼의 색상을 변경해보자. 버튼의 색상을 변경하기 위해 App.tsx 파일에서 다음과 같이 수정한다.

웹브라우저를 확인해보면 다음과 같이 버튼과 호버 색상이 바뀐 것을 확인할 수 있다.



Github Repo

profile
토이 프로젝트와 기술들 정리하는 블로그

0개의 댓글