TIL | React (thunk, custom hooks ...), ๋žœ๋ค id, confirm ...

ํœ’ยท2023๋…„ 7์›” 6์ผ

TIL # WIL

๋ชฉ๋ก ๋ณด๊ธฐ
21/65
post-thumbnail

23.07.06

1. thunk ๐Ÿ”†

thunk : redux ํ™˜๊ฒฝ์—์„œ ๋น„๋™๊ธฐ ํ†ต์‹ ์„ ์œ„ํ•ด ๋นผ๋†“์„ ์ˆ˜ ์—†๋Š” ๋ฏธ๋“ค์›จ์–ด, redux ๋ฏธ๋“ค์›จ์–ด๋Š” ๋ณดํ†ต ์„œ๋ฒ„์™€์˜ ํ†ต์‹ ์„ ์œ„ํ•ด์„œ ์‚ฌ์šฉ (๊ทธ ์ค‘์—์„œ thunk์™€ saga๋ฅผ ์ฃผ๋กœ ์‚ฌ์šฉํ•จ)

๋งŒ์•ฝ ๋ฏธ๋“ค์›จ์–ด๊ฐ€ ์—†๋Š” ๋ฆฌ๋•์Šค๋ผ๋ฉด dispatch๊ฐ€ ๋˜์ž๋งˆ์ž action์ด ๋ฆฌ๋“€์„œ๋กœ ๋‹ฌ๋ ค๊ฐ€์„œ ์ƒˆ๋กœ์šด state๋ฅผ ๋ฐ˜ํ™˜ํ•ด๋ฒ„๋ฆฌ๋Š”๋ฐ, ๋ฏธ๋“ค์›จ์–ด๊ฐ€ ์žˆ๋‹ค๋ฉด ์ด ์ค‘๊ฐ„ ๊ณผ์ •์—์„œ ์šฐ๋ฆฌ๊ฐ€ ํ•˜๊ณ  ์‹ถ์€ ์ž‘์—…๋“ค์„ ๋„ฃ์„ ์ˆ˜ ์žˆ์Œ !

๋ฆฌ๋•์Šค ํˆดํ‚ท์—์„œ thunk ํ•จ์ˆ˜(ex. createAsyncThunk())๋ฅผ ๊ธฐ๋ณธ์ ์œผ๋กœ ๋‚ด์žฅํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋”ฐ๋กœ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์„ค์น˜๊ฐ€ ํ•„์š”์—†์Œ !

+) reducer ์•ˆ์—์„œ๋Š” promise ๊ฐ์ฒด(= ๋น„๋™๊ธฐ ์ฝ”๋“œ)๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์•ˆ๋จ. ๊ทธ๋Ÿฌ๋‚˜, thunk๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ด ์•ˆ์—์„œ async - await ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•จ

1-1. createAsyncThunk(action value, ํ•จ์ˆ˜) ๐Ÿ”†

2๊ฐœ์˜ INPUT : (1) ์ด๋ฆ„ : ์˜๋ฏธ๋Š” ํฌ๊ฒŒ ์—†์Œ (2) ํ•จ์ˆ˜๊ฐ€ ๋“ค์–ด๊ฐ

export const __addNumber = createAsyncThunk(
  "ADD_NUMBER_WAIT",
  (payload, thunkAPI) => {
    // ์ˆ˜ํ–‰ํ•˜๊ณ ์‹ถ์€ ๋™์ž‘ : 3์ดˆ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๊ฒŒ ํ•  ์˜ˆ์ •
    setTimeout(() => {
      // action creator ํ˜ธ์ถœ
      thunkAPI.dispatch(addNumber(payload));
    }, 3000);
  }
);

์ •๋ฆฌ

  1. ๋ฆฌ๋•์Šค ๋ฏธ๋“ค์›จ์–ด๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์•ก์…˜์ด ๋ฆฌ๋“€์„œ๋กœ ์ „๋‹ฌ๋˜๊ธฐ ์ „์— ์ค‘๊ฐ„์— ์–ด๋–ค ์ž‘์—…์„ ๋” ํ•  ์ˆ˜ ์žˆ์Œ
  2. Thunk๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด, ๊ฐ์ฒด๊ฐ€ ์•„๋‹Œ ํ•จ์ˆ˜๋ฅผ dispatch ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์คŒ ! ๐Ÿ”†
  3. ๋ฆฌ๋•์Šค ํˆดํ‚ท์—์„œ Thunk ํ•จ์ˆ˜๋ฅผ ์ƒ์„ฑํ•  ๋•Œ๋Š” npm or yarn add๊ฐ€ ์•„๋‹Œ ๋‚ด์žฅ๋˜์–ด์žˆ๋Š” createAsyncThunk() ํ•จ์ˆ˜๋ฅผ ์ด์šฉ
  4. createAsyncThunk()์˜ ์ฒซ๋ฒˆ์งธ ์ž๋ฆฌ์—๋Š” action value, ๋‘๋ฒˆ์งธ์—๋Š” ํ•จ์ˆ˜๊ฐ€ ๋“ค์–ด๊ฐ
  5. ๋‘๋ฒˆ์งธ๋กœ ๋“ค์–ด๊ฐ„ ํ•จ์ˆ˜์—์„œ 2๊ฐœ์˜ ์ธ์ž๋ฅผ ๊บผ๋‚ด์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, ์ฒซ๋ฒˆ์งธ ์ธ์ž๋Š” ์ปดํฌ๋„ŒํŠธ์—์„œ ๋ณด๋‚ด์ค€ payload์ด๊ณ , ๋‘๋ฒˆ์งธ ์ธ์ž๋Š” thunk์—์„œ ์ œ๊ณตํ•˜๋Š” ์—ฌ๋Ÿฌ๊ฐ€์ง€ ๊ธฐ๋Šฅ์ž„ ! ๐Ÿ”†

1-2. thunk์—์„œ Promise ๋‹ค๋ฃจ๊ธฐ ๐Ÿ”†

  1. thunk ํ•จ์ˆ˜๋ฅผ ๊ตฌํ˜„
    (1) ์„œ๋ฒ„์—์„œ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ

  2. ๋ฆฌ๋“€์„œ ๋กœ์ง ๊ตฌํ˜„ : reducers -> extraReducers

    • ์„œ๋ฒ„ ํ†ต์‹  : 100% ์„ฑ๊ณต(x)
    • ์ง€๊ธˆ๊นŒ์ง€ redux state(todos, counter)
    • ์•ž์œผ๋กœ์˜ state(isLoading, isError, data)

    (2) ์ด์ œ ์ด ๋ฐ์ดํ„ฐ๋ฅผ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋‚ด๋ถ€์˜ ๋ฆฌ๋•์Šค ์Šคํ† ์–ด๋กœ ๊ฐ€์ ธ์˜ค๊ธฐ (์ด์ œ ๊ทธ๋Ÿฌ๋ฉด toolkit์—์„œ ์ œ๊ณตํ•˜๋Š” API์ธ fulfillWithValue(), rejectWithValue() ์ด 2๊ฐœ์˜ ๋ฉ”์„œ๋“œ ํ•„์š”)

  3. ๊ธฐ๋Šฅ ํ™•์ธ(network)

  4. 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;
    },
  },

์ •๋ฆฌ

  • thunkAPI.fulfillWithValue(response.data); ๋Š” [__getTodos.fulfilled] ๋ผ๋Š” ๊ณณ์„ ์ฐพ์•„๊ฐ
  • thunkAPI.rejectWithValue(error); ๋Š” [__getTodos.rejected] ๋ผ๋Š” ๊ณณ์„ ์ฐพ์•„๊ฐ
  • ๊ทธ๋ฆฌ๊ณ  ์ด์ œ ์ด๋ ‡๊ฒŒ ๋ฐ์ดํ„ฐ๋ฅผ ๋„ฃ์–ด์ค€ ๋‹ค์Œ์— (4) Store์˜ ๊ฐ’์„ ์กฐํšŒํ•˜๊ณ  ํ™”๋ฉด์— ๋ Œ๋”๋ง ์‹œํ‚ค๋ฉด ๋จ !

2. custom hooks

custom hooks : react์˜ hook์„ customํ•ด์„œ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•

์ค‘๋ณต๋˜๋Š” ๋กœ์ง์„ custom hooks์„ ์‚ฌ์šฉํ•ด์„œ ์ตœ๋Œ€ํ•œ ์–ด๋–ป๊ฒŒ ๋นผ๋‚ผ ์ˆ˜ ์žˆ์„์ง€ ์ƒ๊ฐํ•ด๋ด์•ผ ํ•จ => ์œ ์ง€๋ณด์ˆ˜ ๊ด€์ ์—์„œ ์ค‘๋ณต๋˜๋Š” ๊ฒƒ์„ ์ค„์ด๋Š”๊ฒŒ ํšจ์œจ์ ์ด๊ณ  ํšจ๊ณผ์ ์ด๋‹ˆ !

  • ์ƒˆ๋กœ ๋งŒ๋“  useInput ์ด๋ผ๋Š” ํ›…
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;
  • useInput์„ importํ•ด์™€์„œ ์ ์šฉํ•ด๋ณด๊ธฐ
import useInput from "./hooks/useInput";

const [name, onChangeNameHandler] = useInput();
const [password, onChangePasswordHandler] = useInput();

3. ํ›„๋ฐœ๋Œ€ ์ˆ˜์—…

3-1. ๋ฒ”์šฉ ๊ณ ์œ  ์‹๋ณ„ ๋žœ๋ค ์•„์ด๋””

  1. uuid() : Universally Unique Identifier
yarn add uuid

import { v4 as uuidv4 } from 'uuid';

id : uuidv4(); // '9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d'
  1. shortid.generate()

    shortid๋Š” ๋ฌด์ž‘์œ„๋กœ ์ƒ์„ฑ๋œ ID๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœํ•˜๋ฉฐ, ๊ธฐ๋ณธ์ ์œผ๋กœ ์ปดํ“จํ„ฐ์˜ ํ˜„์žฌ ์‹œ๊ฐ„, ๋žœ๋ค ์š”์†Œ ๋ฐ ๊ธฐํƒ€ ์š”์†Œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ID๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ํŽ˜์ด์ง€๋ฅผ ๋‹ค์‹œ ๋กœ๋“œํ•˜๊ฑฐ๋‚˜ ๋ธŒ๋ผ์šฐ์ €๋ฅผ ์žฌ์‹œ์ž‘ํ•˜๋ฉด shortid๋Š” ์ƒˆ๋กœ์šด ID๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. (๊ทผ๋ฐ ๋ Œ๋”๋ง๋  ๋•Œ๋Š” ๋ฐ”๋€Œ์ง€ ์•Š์Œ)

yarn add shortid

import shortId from 'shortid';

id: shortId.generate(),
  1. crpyto.randomUUID() : ๋ฉ”์„œ๋“œ๋ผ์„œ ๋‹ค๋ฅธ ๋žœ๋ค id์— ๋น„ํ•ด ๋”ฐ๋กœ ํŒจํ‚ค์ง€ ์„ค์น˜๊ฐ€ ํ•„์š”์—†์Œ
const uuid = crypto.randomUUID();
console.log(uuid); // "36b8f84d-df4e-4d49-b662-bcde71a8764f"
  1. nanoid()
yarn add nanoid

const { nanoid } = require('nanoid')
model.id = nanoid() //"V1StGXR8_Z5jdHi6B-myT"

3-2. confirm

confirm( ) : confirm( ) ๋ฉ”์„œ๋“œ๋Š” ์‚ฌ์šฉ์ž์—๊ฒŒ ํ™•์ธ/์ทจ์†Œ 2๊ฐ€์ง€์˜ ๋ฒ„ํŠผ์œผ๋กœ ์‚ฌ์šฉ์ž์˜ ํ™œ๋™์„ ํ™•์ธ์‹œ์ผœ์ฃผ๋Š” ์—ญํ• ์„ ํ•˜๋Š” ํŒ์—… ๋ฐ•์Šค

if (confirm("์ œ์ถœํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?")) {
  // ok // return true 
  alert("์ œ์ถœ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.")
} else  {
 // cancle // return false 
  alert("์ œ์ถœ์„ ์ทจ์†Œํ•ฉ๋‹ˆ๋‹ค.")
}

0๊ฐœ์˜ ๋Œ“๊ธ€