본문 바로가기

프론트엔드

React(+Redux) + TypeScript

1. 설치

  • 신규설치: npx create-react-app 프로젝트명 --template typescript
  • 기존프로젝트에 설치: npm install --save typescript @types/node @types/react @types/react-dom @types/jest
  •  

2. tsx파일

  • JSX문법이 있는 파일일 경우 tsx파일로!

⭐️ JSX 타입지정

let box :JSX.Element = <div></div>

⭐️ component 타입지정

	function Profile() :JSX.Element{
		return (
    		<div>프로필입니다.</div>
    	)
	}

⭐️ props 타입지정

<Profile name="ha0" age="30"></Profile>
function Profile(props :{name: string, age :string}) :JSX.Element{
		return (
    		<div>{props.name}입니다.</div>
    	)
	}
  • 더 짧게 하고싶으면 type alias, interface 등을 활용하면 된다.

⭐️state 타입지정

let [user, setUser] = useState('kim')

  • 굳이 타입지정안해도 자동으로 되서 신경안써도됨
  • 매우 드물지만, stirng | number등으로 state를 가변적인 타입을 지정하고 싶은 경우에는 generic문법을 이용한다.let [user, setUser] = useState<string | number>('kim')
  •  

3. redux

🛒 redux 타입지정(전통방식)

☃️ state 저장

state초기값, reducer(state가 변경되는 방법 정의) 생성하기

const 초기값 :{count:number} = {count: 0};

function reducer(state = 초기값, action: {type: string}) { 
  if(action.type === '증가') {
    return {...state, count : state.count + 1}
  } else if (action.type === '감소') {
    return {...state, count : state.count - 1}
  } else {
    return 초기값
  }
}

const store = createStore(reducer);

// 👇🏻 store의 타입 미리 export해두기
export type RootState = ReturnType<typeof store.getState>

reducer 파라미터 타입지정

👉🏻 state: state에 들어가는 값이 타입을 가지고 있으면 자동으로 타입지정되므로 굳이 타입지정 하지 않아도 됨

👉🏻 action: 타입지정 필요 => 컴포넌트 안에서 state수정요청 날릴 때의 파라미터 타입

☃️ state 사용

useSelector() 파라미터 타입지정

useSelector((state :{count:number}) => state)

👉🏻 하지만 store의 변수 타입을 미리 export해뒀기 때문에 import해서 사용하면 더 간편하게 작성할 수 있다.

import {RootState} from './index'

useSelector((state :RootState) => state)

☃️ state 변경

dispatch 타입지정

    import {Dispatch} from 'redux'; // dispatch 타입 import
    const dispatch :Dispatch = useDispatch();
    
    ...
    
    <button onClick={() => {dispatch({type:'증가'})}}>button</button>

🛒 redux toolkit 이용한 신문법과 타입지정

1. reduxjs/toolkit 라이브러리 설치

npm install @reduxjs/toolkit

2. createSlice import

import { createSlice } from '@reduxjs/toolkit';

3. slice 생성 (state + reducer)

createSlice({name: slice명, initialState: 초기값, reducers: reducer 등록})

	const 초기값 :{count :number, user :string}= {count: 0, user: 'ha0'};

	const counterSlice = createSlice({
  		name: 'counter',
  		initialState: 초기값,
 		reducers: {
    		증가(state) {
      			state.count += 1
    		},
    		감소(state) {
      			state.count -= 1
    		},
    		맘대로(state, action :PayloadAction<number>) {
             // 두번째 파라미터(action)은 PayloadAction타입으로 지정하고 <>에 어떤 타입으로 파라미터를 받을지 타입을 정해주면 된다.
      			state.count += action.payload
    		}
  		}
	})

reducer 파라미터 타입지정

👉🏻 state: state에 들어가는 값이 타입을 가지고 있으면 자동으로 타입지정되므로 굳이 타입지정 하지 않아도 됨

👉🏻 action: 타입지정 필요 => PayloadAction타입<사용할 자료 타입>

4. store에 등록하기

	let store = configureStore({
  		reducer: {
    		counter1 : counterSlice.reducer
  		}
	})

5. 사용할 reducer 내보내기

  • reducer안의 함수명을 export한다.
	export let {증가, 감소, 맘대로} = counterSlice.actions;

6. state 사용

  • useSelector, useDispatch하는 법은 기존방식과 동일const dispatch :Dispatch = useDispatch()
  • const state변수 = useSelector((state :RootState) => state)
  • state는 store에 등록된 reducer의 이름으로 꺼내쓴다.
  • {state변수.counter1.user}
  • dispatch할 때는 export한 함수를 import해서 쓰면 된다.
  • import {증가, 감소, 맘대로} from './index'
	<button onClick={() => {dispatch(증가())}}>button</button>

🍓 장점 1. 함수형태여서 기존 if문 reducer보다 보기 편하다.

🍓장점 2. state 수정 시 사본만들 필요가 없다. (복사본을 만들어줌)