๐ Redux + React + TypeScript
๐ index.tsx
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import {Provider} from 'react-redux';
import store from './store';
ReactDOM.render(
1๏ธโฃ <React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>,
document.getElementById('root')
);
๐ Memo(index.tsx)
1๏ธโฃ <React.StrictMode>
1. ์์ ํ์ง ์์ ์๋ช
์ฃผ๊ธฐ๋ฅผ ์ฌ์ฉํ๋ ์ปดํฌ๋ํธ๋ฅผ ์ฐพ๋๋ค.
2. ๋ ๊ฑฐ์ ๋ฌธ์์ด ref ์ฌ์ฉ์ ๋ํ ๊ฒฝ๊ณ ํ๋ค.
3. ๊ถ์ฅ๋์ง ์๋ findDOMNode ์ฌ์ฉ์ ๋ํ ๊ฒฝ๊ณ ํ๋ค.
4. ์์์น ๋ชปํ ๋ถ์์ฉ์ ๊ฒ์ฌํ๋ค.
5. ๋ ๊ฑฐ์ context API๋ฅผ ๊ฒ์ฌํ๋ค.
๐ store.ts
import {applyMiddleware, createStore} from 'redux';
import rootReducer from './reducers/index'
1๏ธโฃ import thunk from 'redux-thunk'
const store = createStore(rootReducer, applyMiddleware(thunk));
export type RootReducerType = 2๏ธโฃ ReturnType<typeof rootReducer>
export default store;
๐ Memo(store.ts)
1๏ธโฃ import thunk from 'redux-thunk'
1.๋น๋๊ธฐ๋ก redux state๋ค์ ๊ด๋ฆฌ ํ ๋ ํ์ํ middleware์ด๋ค.
2๏ธโฃ ReturnType<typeof rootReducer>
1. ReturnType ํ์
์ ์ฃผ์ด์ง generic type์ return type์ ํ ๋นํ๋ค.
๐ reducers
๐ index.ts
1๏ธโฃ import {combineReducers} from 'redux';
import PokemonReducer from './PokemonReducer';
const rootReducer = combineReducers({
PokemonReducer
})
export default rootReducer;
๐ Memo(index.ts)
1๏ธโฃ import {combineReducers} from 'redux';
1.์ฌ๋ฌ๊ฐ์ reducer๊ฐ ์กด์ฌ ํ ๋ ํ๋๋ก ํฉ์ณ์ ํ ๋น์ํค๋ ์ญํ ์ ํ๋ค.
๐ PokemonReducer.ts
import {POKEMON_FAIL, POKEMON_SUCCESS,PokemonType,PokemonDispatchType} from '../actions/PokemonActionType'
interface InitialState {
success:boolean
pokemon?:PokemonType
}
const initialState : InitialState = {
success:false
}
const PokemonReducer = (state=initialState, action:PokemonDispatchType) : InitialState=> {
switch (action.type) {
case POKEMON_FAIL :
return{
...state,
success:false
}
case POKEMON_SUCCESS :
1๏ธโฃ const {abilities,sprites} = action.payload
return {
...state,
success:true,
pokemon: {
abilities,
sprites
}
}
default:
return{
...state
}
}
}
export default PokemonReducer
๐ Memo(PokemonReducer.ts)
1๏ธโฃ const {abilities,sprites} = action.payload
1.abilities = action.payload.abiliteis
2.sprites = action.payload.sprites
๐ actions
๐ PokemonActionType.ts
1๏ธโฃ export const POKEMON_SUCCESS = 'POKEMON_SUCCESS'
export const POKEMON_FAIL = 'POKEMON_FAIL'
2๏ธโฃ export type PokemonType = {
abilities : PokemonAbility[]
sprites : PokemonSprites
}
3๏ธโฃ export type PokemonAbility = {
ability: {
name:string,
url:string,
},
is_hidden:boolean,
slot:number
}
export type PokemonSprites = {
front_default : string
}
4๏ธโฃ export interface pokemonFailDispatch {
type : typeof POKEMON_FAIL
}
export interface pokemonSuccessDispatch {
type : typeof POKEMON_SUCCESS
payload: {
abilities : PokemonAbility[],
sprites : PokemonSprites
}
}
5๏ธโฃ export type PokemonDispatchType = pokemonFailDispatch | pokemonSuccessDispatch
๐ Memo(PokemonActionType.ts)
1๏ธโฃ export const POKEMON_SUCCESS = 'POKEMON_SUCCESS'...
1. action์ type์ ๋ณ์๋ก ์ ์ธํ๋ค.
2๏ธโฃ export type PokemonType
1. fetchํ data์์ ์ฌ์ฉํ data์ธ abilities์ sprites์ type์ ์ ์ธํ๋ค.
3๏ธโฃ export type PokemonAbility,export type PokemonSprites
1. ability, is_hidden, slot, front_default์ type์ ์ ์ธํ๋ค.
4๏ธโฃ export interface pokemonFailDispatch, export interface pokemonSuccessDispatch
1. fetch๋ฅผ ์คํจ ํ์ ๋, ์ฑ๊ณต ํ์ ๋์ action์ type์ ์ ์ํ๋ค.
5๏ธโฃ export type PokemonDispatchType
1. PokemonAction.ts ํ์ผ ์์ dispatch ํจ์์ type์ ์ ์ํ๋ค.
๐ PokemonAction.ts
import axios from 'axios'
import {Dispatch} from 'redux';
import {PokemonDispatchType, POKEMON_SUCCESS, POKEMON_FAIL} from './PokemonActionType';
export const fetchPokemonData = (pokemonName:string) => async (dispatch:Dispatch<PokemonDispatchType>) => {
try {
const res = await axios.get(`https://pokeapi.co/api/v2/pokemon/${pokemonName}`)
const data = res.data
1๏ธโฃ dispatch({
type:POKEMON_SUCCESS,
payload:data
})
} catch(err) {
2๏ธโฃ dispatch({
type:POKEMON_FAIL
})
}
}
๐ Memo(PokemonAction.ts)
1๏ธโฃ dispatch => Success
1. axios.get()์ ์ฑ๊ณตํ์์ ๊ฒฝ์ฐ data์ ํจ๊ป action ์์ฑํจ์ ์์ด,
type์ด POKEMON_SUCCESS์ธ action object๋ฅผ dispatchํ๋ค.
2๏ธโฃ dispatch => fail
1. axios.get()์ ์คํจํ์์ ๊ฒฝ์ฐ type์ด POKEMON_FAIL์ธ action object๋ฅผ dispatchํ๋ค.
๐ App.tsx
import React from 'react'; import { useDispatch, useSelector } from 'react-redux'; import {useState} from 'react'; import {RootReducerType} from './store' import {fetchPokemonData} from './actions/PokemonAction'
function App() {
const [pokemonName, setPokemonName] = useState("");
1๏ธโฃ const pokemonReducer = useSelector((state : RootReducerType) => state.PokemonReducer)
2๏ธโฃ const dispatch = useDispatch();
const handlePokemonName = (event : React.ChangeEvent) => setPokemonName(event.target.value);
const searchButtonTapped = () => {
dispatch(fetchPokemonData(pokemonName))
}
return (
<div className="App">
<input value = {pokemonName} onChange={handlePokemonName}/>
<button onClick={searchButtonTapped}>ํฌ์ผ๋ชฌ์ฐพ๊ธฐ</button>
<div>
{pokemonReducer.success && <div>
<p>{pokemonName}</p>
{pokemonReducer.pokemon?.abilities.map((ability, id) => {
return <div key={id}><p>{ability.ability.name}</p>
<p>{ability.slot}</p></div>
})}
<img src={pokemonReducer.pokemon?.sprites.front_default} />
</div> }
</div>
</div>
);
}
export default App;
#### ๐ Memo(App.tsx)
```typescript
1๏ธโฃ const pokemonReducer = useSelector((state : RootReducerType) => state.PokemonReducer)
1. PokemonReducer๊ฐ ๊ด๋ฆฌํ๋ state๋ฅผ useSelector hook์ผ๋ก ์กฐํํ๋ค.
2๏ธโฃ const dispatch = useDispatch();
1. fetchPokemonData์ return ๊ฐ์ธ action์ dispatchํ๊ธฐ ์ํด์
useDispatch hook์ ์ฌ์ฉํ๋ค.
Author And Source
์ด ๋ฌธ์ ์ ๊ดํ์ฌ(๐ Redux + React + TypeScript), ์ฐ๋ฆฌ๋ ์ด๊ณณ์์ ๋ ๋ง์ ์๋ฃ๋ฅผ ๋ฐ๊ฒฌํ๊ณ ๋งํฌ๋ฅผ ํด๋ฆญํ์ฌ ๋ณด์๋ค https://velog.io/@aspalt85/Redux-React-TypeScript์ ์ ๊ท์: ์์์ ์ ๋ณด๊ฐ ์์์ URL์ ํฌํจ๋์ด ์์ผ๋ฉฐ ์ ์๊ถ์ ์์์ ์์ ์ ๋๋ค.
์ฐ์ํ ๊ฐ๋ฐ์ ์ฝํ ์ธ ๋ฐ๊ฒฌ์ ์ ๋ (Collection and Share based on the CC Protocol.)
์ข์ ์นํ์ด์ง ์ฆ๊ฒจ์ฐพ๊ธฐ
๊ฐ๋ฐ์ ์ฐ์ ์ฌ์ดํธ ์์ง
๊ฐ๋ฐ์๊ฐ ์์์ผ ํ ํ์ ์ฌ์ดํธ 100์ ์ถ์ฒ ์ฐ๋ฆฌ๋ ๋น์ ์ ์ํด 100๊ฐ์ ์์ฃผ ์ฌ์ฉํ๋ ๊ฐ๋ฐ์ ํ์ต ์ฌ์ดํธ๋ฅผ ์ ๋ฆฌํ์ต๋๋ค