ts + react 글로 돌아왔습니다 (아무도 안 기다림)
백날 타입스크립트만 공부해봤자 프론트엔드 개발자인데 리액트에서 사용할 줄 모른다면
배운 의미가 없기에 사실상 이 글의 내용이 전 글보다 더 중요하다고 볼 수 있다..
react, react-native에서 ts사용하는 방법은 사실상 거의 똑같아서
구별이 무의미하긴 하지만 필자는 RN에 내장되어 있는 컴포넌트를 사용할 것이기 때문에(View, Text 등)
제목을 저렇게 지정했다.
그럼 빠르게 ㄱㄱ
일단, 처음에 jsx 형식으로 초기 컴포넌트를 만들어 전체적인 틀을 만들어놓고 시작하겠다.
App.tsx
import React, {useState} from 'react';
import {SafeAreaView, Text, View} from 'react-native';
import Store from './src/Store';
function App(){
let data= {name: '청포도에이드', age: 27, job: '개발자', address: '서울'};
const [myInfo, setMyInfo] = useState(data);
const changeAddress = () => {
setMyInfo({...myInfo, address});
};
return (
<SafeAreaView style={{flex: 1}}>
<View
style={{
flex: 1,
backgroundColor: 'skyblue',
}}>
<Text>안녕하세요?</Text>
<Text>저는 {myInfo.name}입니다</Text>
<Text>지금 주소는 {myInfo.address}</Text>
<Store info={data} changeAddress={changeAddress} />
</View>
</SafeAreaView>
);
}
export default App;
단순하게 data에 담긴 정보를 state에 저장해주고, 정보를 그대로 출력해주는 코드이다.
Store라는 자식 컴포넌트에 data를 담아 보내주고, changeAddress라는 주소를 변환하는 함수를 만들어 역시 같이 보내준다.
src/Store.tsx
import React from 'react';
import {Text, TouchableOpacity} from 'react-native';
const Store = ({info, changeAddress}) => {
return (
<>
<Text>나는 자식 컴포넌트야! {info.name}</Text>;
<TouchableOpacity
style={{width: 30, height: 30, backgroundColor: 'red'}}
onPress={() => changeAddress('강원도')}></TouchableOpacity>
</>
);
};
export default Store;
허접한 버튼을 하나 만들었다. 클릭하면 주소가 바뀌는 함수이다.
이렇게 만들었다면 에러가 미친 듯이 터질 거다.. 당연함 ts파일에 js코드를 적었으니까...
하나하나 해결해나가보자.
1. 컴포넌트 역시 타입이 존재한다! 컴포넌트의 타입을 지정해주자.
이 경우는 이미 라이브러리 안에 이미 타입이 내장되어 있기 때문에
아래처럼 간단하게 바꿔주면 된다.
App.tsx
function App(): React.JSX.Element {
return
...
}
App() 뒤에 React.JSX.Element라는 타입을 지정해주자.
만약 함수 컴포넌트를 사용한다면 React.FC라는 타입을 지정해줄 수 있는데
얘는 props에 children이 항상 있다고 가정하는 타입이기 때문에 이에 대해서 논란의 여지가 있어
지양하는 분위기이긴 하니 알고는 있자.
2. model 폴더를 추가해준다.
위치는 src파일 안에 넣어준다. src/model
그리고 그 안에 info.ts라는 파일을 넣어준다. src/model/info.ts
3. 데이터의 타입을 먼저 지정해주어야한다.
src/model/info.ts
export type Info = {
name: string;
age: number;
job: string;
address: string;
};
App.tsx 파일에서 사용했던 data라는 객체의 타입을 선언해준다.
4. data의 타입을 지정해준다.
App.tsx 에서 import로 Info라는 type을 가져온 뒤,
+ import {Info} from './src/model/info';
let data= {name: '청포도에이드', age: 27, job: '개발자', address: '서울'};
였던 코드를 아래처럼 바꾼다.
let data : Info = {name: '청포도에이드', age: 27, job: '개발자', address: '서울'};
5. useState 타입 지정해주기
const [myInfo, setMyInfo] = useState<Info>(data);
간단하다. useState안에 넣을 data의 타입을 제네릭<>안에 넣어주면 된다!
6. 함수 타입 지정해주기
const changeAddress = (address: string) => {
setMyInfo({...myInfo, address});
};
address를 인자로 받을 것이기 때문에 address의 type만 적어주면 해결~!
이제 App.tsx 파일은 문제가 없다. 문제는 App 컴포넌트 안에 있는 Store라는 자식 컴포넌트이다.
info라는 이름으로 data를 담아보내주고 changeAddress함수를 props로 내려보내줄건데 현시점에선 오류가 빵빵 터질 것이다.
그 이유는 props로 내려준 자식 컴포넌트도 타입을 지정해주어야하기 때문~
7. Store 컴포넌트 타입과 props 데이터 타입 지정해주기
+ import {Info} from './model/info';
interface OwnProps {
info: Info;
changeAddress(address: string): void;
}
App.tsx에서 사용했던 Info 타입을 가져와주고, 자식 컴포넌트에서 쓰일 타입을 새롭게 커스텀해줄 거다.
App.tsx 파일에서 Store라는 컴포넌트로 changeAddress라는 함수를 추가로 보내줬기 때문에
기존에 쓰던 Info 타입에 changeAddress가 섞인 타입이 필요해졌다.
따라서 OwnProps라는 이름으로 새로운 interface를 만들어준다.
type 선언자를 쓰고 싶으면
type OwnProps = {
info: Info;
changeAddress(address: string): void;
}
라고 쓰면된다.
8. Store 컴포넌트 타입 지정해주기
const Store = ({info, changeAddress}: OwnProps) => {
return (
<>
<Text>나는 자식 컴포넌트야! {info.name}</Text>;
<TouchableOpacity
style={{width: 30, height: 30, backgroundColor: 'red'}}
onPress={() => changeAddress('강원도')}></TouchableOpacity>
</>
);
};
함수형 컴포넌트이기 때문에 그냥 children 객체 뒤에 :OwnProps 만 써주면 끝
최종 코드
App.tsx
import React, {useState} from 'react';
import {SafeAreaView, Text, View} from 'react-native';
import Store from './src/Store';
import {Info} from './src/model/info';
function App(): React.JSX.Element {
let data: Info = {name: 'gyuri', age: 27, job: '개백수', address: '서울'};
const [myInfo, setMyInfo] = useState<Info>(data);
const changeAddress = (address: string) => {
setMyInfo({...myInfo, address});
};
return (
<SafeAreaView style={{flex: 1}}>
<View
style={{
flex: 1,
backgroundColor: 'skyblue',
}}>
<Text>안녕하세요?</Text>
<Text>저는 {myInfo.name}입니다</Text>
<Text>지금 주소는 {myInfo.address}</Text>
<Store info={data} changeAddress={changeAddress} />
</View>
</SafeAreaView>
);
}
export default App;
Store.tsx
import React from 'react';
import {Info} from './model/info';
import {Text, TouchableOpacity} from 'react-native';
interface OwnProps {
info: Info;
changeAddress(address: string): void;
}
const Store = ({info, changeAddress}: OwnProps) => {
return (
<>
<Text>나는 자식 컴포넌트야! {info.name}</Text>;
<TouchableOpacity
style={{width: 30, height: 30, backgroundColor: 'red'}}
onPress={() => changeAddress('구의')}></TouchableOpacity>
</>
);
};
export default Store;
앞에 얘기했던 React.FC에 대한 얘기를 해보고자 한다.
원래 React.FC를 사용했다면, 아래처럼 작성해야하는데,
const Store:React.FC<OwnProps> = ({info, changeAddress}) => {
return (
<>
<Text>나는 자식 컴포넌트야! {info.name}</Text>;
<TouchableOpacity
style={{width: 30, height: 30, backgroundColor: 'red'}}
onPress={() => changeAddress('구의')}></TouchableOpacity>
</>
);
};
논란의 여지도 있는데 코드도 더 길다. 굳이 쓸 이유가 이제는 없어보인다.
끝
'프론트엔드 > Typescript' 카테고리의 다른 글
[TS] 타입스크립트 기본 + 실전편 종결 (0) | 2024.12.28 |
---|---|
[Typescript] 타입스크립트 interface (0) | 2022.06.09 |
[Typescript] 기본 설정, 세팅 (0) | 2022.06.09 |