반응형
useSelector 와 useDispatch 를 대신하여 사용할 hook을 지정
// app/store.ts
import { configureStore } from '@reduxjs/toolkit'
import searchSlice from './slice/searchSlice'
/* 스토어 생성 */
const store = configureStore({
reducer: {
search: searchSlice.reducer
}
})
// store의 getState는 각 레듀서가 반환하는 state 값을 담고 있다.
// 해당 반환값을 typeof 로 검사하여 반환된 타입으로
// 반환되는 state의 타입을 동적으로 결정한다.
export type RootState = ReturnType<typeof store.getState>
// 추론된 타입: {posts: PostsState, comments: CommentsState, users: UsersState}
export type AppDispatch = typeof store.dispatch
export default store
useSelector 와 useDispatch 를 대신하여 사용할 hook을 지정
AppDispatch 는 store 가 반환하는 dispatch 로 부터 타입을 유추하여 타입을 자동으로 지정해준다.
예를 들어, {posts: PostsState, comments: CommentsState, users: UsersState}이런 형식이다.
// app/hooks.ts
import { useDispatch, useSelector } from "react-redux";
import type { TypedUseSelectorHook } from "react-redux";
import type { RootState, AppDispatch } from "./store";
export const useAppDispatch: () => AppDispatch = useDispatch
// 기존의 useSelector 훅을 대신하는 훅으로
// 리듀서에서 반환되는 값의 타입을 자신의 타입으로 한다.
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector
스토어의 루트 리듀서에 도달하기 전에 처리하고자 하는 요청이 있을 때
스토어의 루트 리튜서에 actions 을 전달하기 전에 우선적으로 처리하고자 하는 작업이 있다면 createAsyncThunk 미들웨어를 사용한다. 이를 이용하면 비동기적으로 처리하고자 하는 네트워크 요청이 있다면 요청처리 전, 처리 후, 처리가 불가능한 상태에 따른 다양한 상태에 대한 처리를 실시할 수 있다.
// app/slice/ searchSlice
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import axios from "axios";
import type { PayloadAction } from "@reduxjs/toolkit";
import type { RootState } from "../store";
const asyncGetSearchData = createAsyncThunk(
"searchSlice/asyncGetSearchData",
async (item:string) => {
const response = await axios.get(
`http://apis.data.go.kr/1471000/FoodNtrIrdntInfoService1/getFoodNtrItdntList1?servicekey=${process.env.REACT_APP_BUSAN_KEY}&type=json&desc_kor=${item}`
);
const data = await response.data;
return data.body.items;
}
);
// 초기 state 의 타입을 지정한다.
interface InitialState {
value: string[];
}
// 초기 state 를 지정한다.
const initialState: InitialState = {
value: [],
};
// 슬라이스를 생성한다.
const searchSlice = createSlice({
name: "search",
initialState,
reducers: {},
extraReducers: (builder) => {
builder.addCase(asyncGetSearchData.pending, (state, action) => {
state.value = ['데이터를 준비중 입니다.'];
});
builder.addCase(
asyncGetSearchData.fulfilled,
(state, action: PayloadAction<string[]>) => {
state.value = action.payload;
}
);
builder.addCase(asyncGetSearchData.rejected, (state, action) => {
state.value = ['요청이 처리되지 않았습니다.'];
});
},
});
// 사용한 레듀서를 내보낸다.
export {asyncGetSearchData}
// store로 전달할 슬라이스를 내보낸다.
export default searchSlice;
처리가 완료된 요청에 대한 결과를 스토어에서 가져오려면
useSelector() 선택자를 사용하여 스토어에서 dispatch 한 actions 에 대한 처리 결과인 state 을 사용할 수 있다.
// src / Search.tsx
import styles from "./Search.module.css";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faMagnifyingGlass } from "@fortawesome/free-solid-svg-icons";
import { useNavigate } from "react-router-dom";
import { useAppDispatch } from "../../app/hooks";
import { asyncGetSearchData } from "../../app/slice/searchSlice";
import Header from "./Header";
interface SearchType {
fixed: boolean;
}
function Search({ fixed }: SearchType) {
const navigate = useNavigate();
const dispatch = useAppDispatch();
return (
<>
<Header isStyle={true}></Header>
<article
className={styles.search}
style={
fixed
? {
position: "relative",
top: "8rem",
maxWidth: "600px",
}
: { position: "fixed" }
}
>
<div className={styles.search_container}>
<label className={styles.search_icon} htmlFor="search">
<FontAwesomeIcon
style={{ color: "black" }}
icon={faMagnifyingGlass}
/>
</label>
<input
onKeyUp={(e) => {
if (e.code === "Enter") {
// sendURL(e.currentTarget.value);
if (e.currentTarget.value !== "")
dispatch(asyncGetSearchData(e.currentTarget.value));
e.currentTarget.value = "";
return navigate("/busan_item_map/search");
}
}}
placeholder="음식명을 입력 후 [Enter] 를 눌러주세요!!"
type="text"
id="search"
className={styles.search_input}
style={fixed ? { border: '1px solid rgba(28, 99, 231,0.1)', boxShadow:'inset 0 0 5px 2px rgba(55,55,55,0.5)' } : {}}
/>
</div>
</article>
</>
);
}
export default Search;
반응형
'리액트' 카테고리의 다른 글
[React Error] Error: [Immer] An immer producer returned a new value ... 을 해결하려면 (0) | 2023.10.18 |
---|---|
[리액트 npm error] CRA 환경에서 nth-check 취약점 문제 (0) | 2023.09.11 |
[React] 리액트에서 카카오 맵 불러오기 (with kakao map) (0) | 2023.07.21 |
[react] 리액트에서 카카오 맵 사용하기( with ReactKakaoMapSDK) (0) | 2023.07.21 |
[react hooks] 3. useContext 에 대한 정리 (0) | 2023.06.06 |