
23.07.06
thunk : redux ํ๊ฒฝ์์ ๋น๋๊ธฐ ํต์ ์ ์ํด ๋นผ๋์ ์ ์๋ ๋ฏธ๋ค์จ์ด, redux ๋ฏธ๋ค์จ์ด๋ ๋ณดํต ์๋ฒ์์ ํต์ ์ ์ํด์ ์ฌ์ฉ (๊ทธ ์ค์์ thunk์ saga๋ฅผ ์ฃผ๋ก ์ฌ์ฉํจ)

๋ง์ฝ ๋ฏธ๋ค์จ์ด๊ฐ ์๋ ๋ฆฌ๋์ค๋ผ๋ฉด dispatch๊ฐ ๋์๋ง์ action์ด ๋ฆฌ๋์๋ก ๋ฌ๋ ค๊ฐ์ ์๋ก์ด state๋ฅผ ๋ฐํํด๋ฒ๋ฆฌ๋๋ฐ, ๋ฏธ๋ค์จ์ด๊ฐ ์๋ค๋ฉด ์ด ์ค๊ฐ ๊ณผ์ ์์ ์ฐ๋ฆฌ๊ฐ ํ๊ณ ์ถ์ ์์ ๋ค์ ๋ฃ์ ์ ์์ !
๋ฆฌ๋์ค ํดํท์์ thunk ํจ์(ex. createAsyncThunk())๋ฅผ ๊ธฐ๋ณธ์ ์ผ๋ก ๋ด์ฅํ๊ณ ์๊ธฐ ๋๋ฌธ์ ๋ฐ๋ก ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ค์น๊ฐ ํ์์์ !
+) reducer ์์์๋ promise ๊ฐ์ฒด(= ๋น๋๊ธฐ ์ฝ๋)๋ฅผ ์ฌ์ฉํ๋ฉด ์๋จ. ๊ทธ๋ฌ๋, thunk๋ฅผ ์ฌ์ฉํ๋ฉด ์ด ์์์ async - await ์ฌ์ฉ ๊ฐ๋ฅํจ
2๊ฐ์ INPUT : (1) ์ด๋ฆ : ์๋ฏธ๋ ํฌ๊ฒ ์์ (2) ํจ์๊ฐ ๋ค์ด๊ฐ
export const __addNumber = createAsyncThunk(
"ADD_NUMBER_WAIT",
(payload, thunkAPI) => {
// ์ํํ๊ณ ์ถ์ ๋์ : 3์ด๋ฅผ ๊ธฐ๋ค๋ฆฌ๊ฒ ํ ์์
setTimeout(() => {
// action creator ํธ์ถ
thunkAPI.dispatch(addNumber(payload));
}, 3000);
}
);
์ ๋ฆฌ
thunk ํจ์๋ฅผ ๊ตฌํ
(1) ์๋ฒ์์ ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ
๋ฆฌ๋์ ๋ก์ง ๊ตฌํ : reducers -> extraReducers
(2) ์ด์ ์ด ๋ฐ์ดํฐ๋ฅผ ์ ํ๋ฆฌ์ผ์ด์ ๋ด๋ถ์ ๋ฆฌ๋์ค ์คํ ์ด๋ก ๊ฐ์ ธ์ค๊ธฐ (์ด์ ๊ทธ๋ฌ๋ฉด toolkit์์ ์ ๊ณตํ๋ API์ธ fulfillWithValue(), rejectWithValue() ์ด 2๊ฐ์ ๋ฉ์๋ ํ์)
๊ธฐ๋ฅ ํ์ธ(network)
Store์ ๊ฐ์ ์กฐํ + ํ๋ฉด์ ๋ ๋๋ง
์ฝ๋
// (1) ์๋ฒ์์ ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ
export const __getTodos = createAsyncThunk(
"getTodos",
// thunk ํจ์๋ ์๋ฒ๋ ํต์ ํ๋ ๋ถ๋ถ์ด๊ธฐ ๋๋ฌธ์ async - await์ ์ ์ด์ค์ผ ํจ
async (payload, thunkAPI) => {
try {
// ์๋ํ๋ ๋ถ๋ถ
const response = await axios.get("http://localhost:4000/todos");
console.log("response", response);
} catch (error) {
// ์๋ฌ๋ฅผ ์ก๋ ๋ถ๋ถ
console.log("error", error);
}
}
);
// (2) ๋ฐ์ดํฐ๋ฅผ ์ ํ๋ฆฌ์ผ์ด์
๋ด๋ถ์ ๋ฆฌ๋์ค ์คํ ์ด๋ก ๊ฐ์ ธ์ค๊ธฐ
// toolkit์์ ์ ๊ณตํ๋ API
// Promise -> resolve(= ๋คํธ์ํฌ ์์ฒญ์ด '์ฑ๊ณต'ํ ๊ฒฝ์ฐ) -> dispatch ํด์ฃผ๋ ๊ธฐ๋ฅ์ ๊ฐ์ง API
return thunkAPI.fulfillWithValue(response.data);
// toolkit์์ ์ ๊ณตํ๋ API
// Promise -> resolve(= ๋คํธ์ํฌ ์์ฒญ์ด '์คํจ'ํ ๊ฒฝ์ฐ) -> dispatch ํด์ฃผ๋ ๊ธฐ๋ฅ์ ๊ฐ์ง API
return thunkAPI.rejectWithValue(error);
์ฌ๊ธฐ์ return์ ๊ผญ ์จ์ค์ผ์ง๋ง ์๋ extraReducers๋ก ๋์ด๊ฐ
extraReducers: {
[__getTodos.pending]: (state, action) => {
// ํต์ ์ด ์์ง ์งํ์ค์ผ ๋
state.isLoading = true;
state.isError = false;
},
[__getTodos.fulfilled]: (state, action) => {
state.isLoading = false;
state.isError = false;
state.todos = action.payload;
},
[__getTodos.rejected]: (state, action) => {
state.isLoading = false;
state.isError = true;
// state์ error ๊ฐ์ฒด์ action.payload๋ก ๋ฐ์์จ error ๊ฐ์ฒด๋ฅผ ๋ฃ์ด์ค
state.error = action.payload;
},
},
์ ๋ฆฌ
custom hooks : react์ hook์ customํด์ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ
์ค๋ณต๋๋ ๋ก์ง์ custom hooks์ ์ฌ์ฉํด์ ์ต๋ํ ์ด๋ป๊ฒ ๋นผ๋ผ ์ ์์์ง ์๊ฐํด๋ด์ผ ํจ => ์ ์ง๋ณด์ ๊ด์ ์์ ์ค๋ณต๋๋ ๊ฒ์ ์ค์ด๋๊ฒ ํจ์จ์ ์ด๊ณ ํจ๊ณผ์ ์ด๋ !
import { useState } from "react";
const useInput = () => {
// state
const [value, setValue] = useState("");
// handler
const handler = (e) => {
setValue(e.target.value);
};
return [value, handler];
};
export default useInput;
import useInput from "./hooks/useInput";
const [name, onChangeNameHandler] = useInput();
const [password, onChangePasswordHandler] = useInput();
yarn add uuid
import { v4 as uuidv4 } from 'uuid';
id : uuidv4(); // '9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d'
shortid๋ ๋ฌด์์๋ก ์์ฑ๋ ID๋ฅผ ๊ธฐ๋ฐ์ผ๋กํ๋ฉฐ, ๊ธฐ๋ณธ์ ์ผ๋ก ์ปดํจํฐ์ ํ์ฌ ์๊ฐ, ๋๋ค ์์ ๋ฐ ๊ธฐํ ์์๋ฅผ ์ฌ์ฉํ์ฌ ID๋ฅผ ์์ฑํฉ๋๋ค. ๋ฐ๋ผ์ ํ์ด์ง๋ฅผ ๋ค์ ๋ก๋ํ๊ฑฐ๋ ๋ธ๋ผ์ฐ์ ๋ฅผ ์ฌ์์ํ๋ฉด shortid๋ ์๋ก์ด ID๋ฅผ ์์ฑํ์ฌ ์ ๊ณตํฉ๋๋ค. (๊ทผ๋ฐ ๋ ๋๋ง๋ ๋๋ ๋ฐ๋์ง ์์)
yarn add shortid
import shortId from 'shortid';
id: shortId.generate(),
const uuid = crypto.randomUUID();
console.log(uuid); // "36b8f84d-df4e-4d49-b662-bcde71a8764f"
yarn add nanoid
const { nanoid } = require('nanoid')
model.id = nanoid() //"V1StGXR8_Z5jdHi6B-myT"
confirm( ) : confirm( ) ๋ฉ์๋๋ ์ฌ์ฉ์์๊ฒ ํ์ธ/์ทจ์ 2๊ฐ์ง์ ๋ฒํผ์ผ๋ก ์ฌ์ฉ์์ ํ๋์ ํ์ธ์์ผ์ฃผ๋ ์ญํ ์ ํ๋ ํ์ ๋ฐ์ค
if (confirm("์ ์ถํ์๊ฒ ์ต๋๊น?")) {
// ok // return true
alert("์ ์ถ๋์์ต๋๋ค.")
} else {
// cancle // return false
alert("์ ์ถ์ ์ทจ์ํฉ๋๋ค.")
}