๐Ÿ’ป6/15

๋ฐฉ์˜ˆ์„œยท2022๋…„ 6์›” 15์ผ
0

Project

๋ชฉ๋ก ๋ณด๊ธฐ
3/4

6/15

๊ฐ์ž ๋งก์€ ๋ถ€๋ถ„์— ๋Œ€ํ•ด์„œ ๊ตฌํ˜„ํ•˜๋Š” ์‹œ๊ฐ„์„ ๊ฐ€์กŒ๋‹ค.
๋‚˜๋Š” search history ๋ถ€๋ถ„์„ ๋งก์•˜๋‹ค. ์š”๊ตฌ์‚ฌํ•ญ์€

  • ์ตœ๊ทผ ๊ฒ€์ƒ‰์–ด ์ตœ๋Œ€ 5๊ฐœ๊นŒ์ง€ ๋ณด์ธ๋‹ค.
  • ๊ฐ™์€ ๊ฒ€์ƒ‰์–ด๋ฅผ ๋‹ค์‹œ ๊ฒ€์ƒ‰ํ•˜๋ฉด ๊ทธ ๊ฒ€์ƒ‰์–ด๋Š” ์ตœ๊ทผ ๊ฒ€์ƒ‰์–ด๋กœ ๋ฐ”๋€๋‹ค.

์šฐ๋ฆฌ๋Š” search history๋ฅผ ์ „์—ญ์œผ๋กœ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด store, reducer๋ฅผ ์ž‘์„ฑํ•ด๋‘์—ˆ์—ˆ๋‹ค.

// searchSlice.js

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

const searchSlice = createSlice({
  name: 'search',
  initialState: [],
  reducers: {
    updateHistory: (state, action) => {
      return [...action.payload];
    },
});

export const { updateHistory } = searchSlice.actions;
export default searchSlice.reducer;

์ปดํฌ๋„ŒํŠธ ์•ˆ์—์„œ ์š”๊ตฌ์‚ฌํ•ญ ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋„๋ก ๋ฐฐ์—ด์„ ์™„์„ฑํ•˜๊ณ  update ์‹œํ‚ค๋Š” action ํ•˜๋‚˜๋งŒ์„ ์ž‘์„ฑํ–ˆ์—ˆ๋‹ค.

// Input.jsx
import React, { useState } from 'react'
import { useSelector, useDispatch } from 'react-redux';

import { deleteHistory, replaceHistory, updateHistory } from '../reducer/searchSlice';

// search history ๋ณด์—ฌ์ค„ ์ตœ๋Œ€ ๊ฐœ์ˆ˜
const historyMax = 5;

export default function Input() {

  const history = useSelector(state => state.searchSlice);
  const dispatch = useDispatch();

  const [value, setValue] = useState("");

  const onChange = (e) => {
    setValue(e.target.value);
  }

  const onEnterDown = (e) => {
    if (e.key === "Enter") {
      searchFunc();
    }
  }

  function searchFunc() {
    if (history.includes(value)) {
      // ๊ฐ™์€ ๊ฐ’์ด ์žˆ์„ ๋•Œ ์ตœ์ƒ๋‹จ์œผ๋กœ ์˜ฌ๋ฆฐ๋‹ค.
      let temp = [...history];
      temp.splice(history.indexOf(value), 1);
      dispatch(updateHistory([value, ...temp]));
    } else {
      if (history.length === historyMax) {
        dispatch(updateHistory([value, ...history.slice(0, history.length-1)]));
      } else {
		dispatch(updateHistory([value, ...history]))
      }
    }
  }

  return (
    <div>
      <input onChange={onChange} onKeyDown={onEnterDown}/>
      <div> {history.map((value, i) => (<p key={i}>{i} : {value}</p>))}</div>
    </div>
  )
}

์—”ํ„ฐ ํ‚ค๋ฅผ ๋ˆ„๋ฅด๋ฉด ๊ฒ€์ƒ‰์–ด๊ฐ€ ์ €์žฅ๋  ์ˆ˜ ์žˆ๋„๋ก onEnterDown ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์ž‘์„ฑํ–ˆ๊ณ , ์‚ฌ์šฉ์ž๊ฐ€ ๋ˆ„๋ฅธ ๊ฒƒ์ด ์—”ํ„ฐ ํ‚ค์ด๋ฉด searchFun์„ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ–ˆ๋‹ค.
๋‚˜์ค‘์— ์ฝ”๋“œ๋ฅผ ํ•ฉ์น  ๋•Œ์˜ ์šฉ์ดํ•จ๊ณผ ์žฌ์‚ฌ์šฉ์„ฑ์„ ๊ณ ๋ คํ•ด ํ•จ์ˆ˜๋กœ ๋นผ๋ณด์•˜๋‹ค.

์ด์ œ ์กฐ๊ฑด๋ฌธ์„ ๋”ฐ์ ธ๋ณด์•˜๋‹ค.

  • ๊ฒ€์ƒ‰ํ•œ ๊ฐ’ ์ค‘ ๊ฐ™์€ ๊ฐ’์ด ์žˆ์„ ๋•Œ
    store๋กœ ๊ด€๋ฆฌ๋˜๊ณ  ์žˆ๋Š” ์ƒํƒœ๋Š” immutable ํ•ด์•ผํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ณ€์ˆ˜ temp๋ฅผ ๋งŒ๋“ค์–ด์ฃผ์—ˆ๋‹ค.
    ํ˜„์žฌ ์ž…๋ ฅํ•œ ๊ฐ’์ด ๋“ค์–ด์žˆ๋Š” ์ธ๋ฑ์Šค๋ฅผ ์ฐพ์•„ splice()๋กœ ์—†์• ์ฃผ๊ณ , ๊ทธ ์ƒํƒœ๋ฅผ ๊ทธ๋Œ€๋กœ update ํ•ด์ค€๋‹ค.

  • ์ตœ๋Œ€ ๊ฒ€์ƒ‰์–ด ๊ฐœ์ˆ˜์— ๋„๋‹ฌํ–ˆ์„ ๋•Œ
    ๊ฒ€์ƒ‰์–ด ๊ฐœ์ˆ˜๊ฐ€ historyMax์ผ ๋•Œ, ๊ฐ€์žฅ ์˜ค๋ž˜๋œ ๊ฒ€์ƒ‰์–ด๋ฅผ ์‚ญ์ œํ•˜๊ณ  ์ƒˆ๋กœ ๊ฐ’์„ ๋„ฃ์–ด์ฃผ์–ด์•ผํ•œ๋‹ค.
    ์ด ๋˜ํ•œ history๋Š” immutable ํ•ด์•ผํ•˜๋ฏ€๋กœ splice()๊ฐ€ ์•„๋‹Œ slice() ํ†ตํ•ด ์–•์€ ๋ณต์‚ฌ๋ฅผ ํ•ด์ฃผ์—ˆ๋‹ค.

  • ์•„๋‹Œ ๊ฒฝ์šฐ (์ตœ๋Œ€ ๊ฐœ์ˆ˜๋ณด๋‹ค ์ดํ•˜์ด๊ณ , ์ƒˆ๋กœ์šด ๊ฒ€์ƒ‰์–ด์ผ ๊ฒฝ์šฐ)
    ๊ทธ๋Œ€๋กœ update ํ•ด์ค€๋‹ค.

๋ Œ๋”๋ง ํ• ๋•Œ ์ฃผ์˜ํ•  ์ ์€

  • key ๊ฐ’์ด ์žˆ์–ด์•ผ ํ•œ๋‹ค.
    ๋”ฑํžˆ ์–ด๋–ค id ๊ฐ’์ด ์—†๊ธฐ ๋•Œ๋ฌธ์— ๊ทธ๋ƒฅ i(index)๋กœ key ๊ฐ’์„ ์ง€์ •ํ•ด์ฃผ์—ˆ๋‹ค.

  • ์—ญ์ˆœ์œผ๋กœ ๋ณด์—ฌ์ฃผ์–ด์•ผ ํ•œ๋‹ค. (์ตœ๊ทผ ๊ฒ€์ƒ‰์–ด๊ฐ€ ์œ„์— ์žˆ๊ฒŒ)
    input์ด ๊ณ„์† ๋“ค์–ด์˜ค๊ธฐ ๋•Œ๋ฌธ์— ์• ์ดˆ์— ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•  ๋•Œ ์ฒ˜๋ฆฌํ•ด์ฃผ์—ˆ๋‹ค.


์ด์ œ ์—ฌ๊ธฐ์„œ ๊ณ ๋ฏผ์ด ๋˜์—ˆ๋˜ ๋ถ€๋ถ„์€, ์ด๋ ‡๊ฒŒ action์€ ํ•˜๋‚˜๋งŒ ์“ฐ๊ณ  ๋ชจ๋“  ์กฐ๊ฑด ์ฒ˜๋ฆฌ๋ฅผ ์ปดํฌ๋„ŒํŠธ์—์„œ ํ•ด์ฃผ๋Š” ๊ฒƒ์ด ๋งž๋‚˜ ํ•˜๋Š” ์ƒ๊ฐ์ด ๋“ค์—ˆ๋‹ค.

์ฒ˜์Œ์— ๋ฐ”๋กœ ์œ„์ฒ˜๋Ÿผ ์ž‘์„ฑํ•œ ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์‚ญ์ œํ•˜๋Š” action์ด ํ•„์š”ํ•˜์ง€ ์•Š๋‚˜? ์‹ถ์–ด์„œ ์‚ญ์ œํ•˜๋Š” action์„ ์ž‘์„ฑํ–ˆ์—ˆ๋Š”๋ฐ, ๋˜ ๊ทธ๋ ‡๊ฒŒ ์ž‘์„ฑํ•˜๋‹ˆ๊นŒ ์ด ๋ฐฉ๋ฒ•์ด ๋งž๋‚˜ ์‹ถ์€ ๊ฑฐ๋‹ค.

๊ทธ๋ž˜์„œ ํŒ€์›๋“ค๊ณผ ๋งค๋‹ˆ์ €๋‹˜์—๊ฒŒ ๋ฌผ์–ด๋ดค๋‹ค.

-> middleware๋ฅผ ๋งŒ๋“ค์–ด ๊ทธ ์•ˆ์—์„œ ์กฐ๊ฑด ์ฒ˜๋ฆฌ๋ฅผ ํ•ด์ฃผ๋Š” ๊ฒƒ์€ ์–ด๋–ค๊ฐ€?
-> middleware์˜ ๊ฐœ๋…์ด ์–ด๋ ต๋‹ค๋ฉด, updateHistory action ๋‚ด์—์„œ ๋‹ค ์ฒ˜๋ฆฌํ•˜๋„๋ก (reducer ์•ˆ์—์„œ ๋ชจ๋‘ ์ฒ˜๋ฆฌํ•˜๊ฒŒ)

์žฌ์‚ฌ์šฉ์„ฑ์„ ๊ณ ๋ คํ•ด์„œ reducer ๋‚ด์—์„œ ์ฒ˜๋ฆฌ๋ฅผ ํ•ด์ฃผ๋Š” ๊ฒƒ์ด ๋งž๋‹ค๋Š” ํŒ๋‹จ์„ ๋‚ด๋ ค์ฃผ์…จ๋‹ค.
(ํ•˜์ง€๋งŒ middleware... ๋„ˆ๋ฌด ๋ฉ€๊ณ  ๋ฉ€๋‹ค.)

์—ด์‹ฌํžˆ ์ฐพ์•„๋ด์„œ ๊ณ ์ณ๋ณด๋Š” ์ค‘.

์•„๋ž˜๋Š” ์•ก์…˜์„ ์—ฌ๋Ÿฌ ๊ฐœ ๋งŒ๋“ค์–ด ๊ณ ์ณ๋ณธ ๊ฒƒ์ด๋‹ค.

// searchSlice.js

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

const searchSlice = createSlice({
  name: 'search',
  initialState: [],
  reducers: {
    updateHistory: (state, action) => {
      // ์—ญ์ˆœ์œผ๋กœ ๋„ฃ์–ด์ฃผ๊ธฐ
      return [action.payload, ...state];
    },
    deleteHistory: (state) => {
      // **
      // ๋งจ ๋’ค ์š”์†Œ ์‚ญ์ œํ•˜๋Š” action
      return [...state.slice(0, state.length-1)];
    },
    replaceHistory: (state, action) => {
      // **
      // ๊ฐ™์€ ๊ฐ’์ด ๋“ค์–ด์˜จ ๊ฒฝ์šฐ ์œ„์น˜๋ฅผ ๋ฐ”๊ฟ”์ฃผ๋Š” action
      let temp = [...state];
      temp.splice(state.indexOf(action.payload), 1);
      return [action.payload, ...temp];
    }
  },
});

export const { updateHistory, deleteHistory, replaceHistory } = searchSlice.actions;
export default searchSlice.reducer;

// Input.jsx

import React, { useState } from 'react'
import { useSelector, useDispatch } from 'react-redux';

import { deleteHistory, replaceHistory, updateHistory } from '../reducer/searchSlice';

// search history ๋ณด์—ฌ์ค„ ์ตœ๋Œ€ ๊ฐœ์ˆ˜
const historyMax = 5;

export default function Input() {

  const history = useSelector(state => state.searchSlice);
  const dispatch = useDispatch();

  const [value, setValue] = useState("");

  const onChange = (e) => {
    setValue(e.target.value);
  }

  const onEnterDown = (e) => {
    if (e.key === "Enter") {
      searchFunc();
    }
  }

  function searchFunc() {
    if (history.includes(value)) {
      dispatch(replaceHistory(value));
    } else {
      if (history.length === historyMax) {
        // action์œผ๋กœ ์ƒํƒœ ์ฒ˜๋ฆฌ
        dispatch(deleteHistory());
        dispatch(updateHistory(value));
      } else {
        dispatch(updateHistory(value));
      }
    }
  }

  return (
    <div>
      <input onChange={onChange} onKeyDown={onEnterDown}/>
      <div> {history.map((value, i) => (<p key={i}>{i} : {value}</p>))}</div>
    </div>
  )
}

TODO

  • middleware ์ถ”๊ฐ€ํ•ด์„œ reducer์—์„œ ๋‹ค ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•˜๊ธฐ








์—Š๊ทธ์ œ ๋ฉ˜ํ† ๋ง์—์„œ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋ณด๋‹ค react์— ๋” ์ดˆ์ ์„ ๋‘์ž๊ณ  ํ–ˆ๋Š”๋ฐ
๊ฐ‘์ž๊ธฐ ๋ฏธ๋“ค์›จ์–ด๊นŒ์ง€ ์ถ”๊ฐ€ํ•˜๋ ค๋‹ˆ๊นŒ ๋‚ด๊ฐ€ ์ง€๊ธˆ ๋”ฑ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ์ง‘์ค‘ํ•˜๊ณ  ์žˆ๋Š” ๋“ฏํ•œ ๊ทธ ๊ผด์ด๋‹ค.
์•ฝ๊ฐ„ ๊ณ ๋ฏผ์ด ๋˜๊ธด ํ•˜์ง€๋งŒ ... ๊ทธ๋ž˜๋„ ๋ช‡์‹œ๊ฐ„ ์ •๋„ ๋” ํˆฌ์žํ•˜๋Š” ๊ฒƒ์ด๋‹ˆ ์ผ๋‹จ ํ•˜๋Š”๋Œ€๊นŒ์ง€ ํ•ด๋ณด๊ธฐ.
profile
console.log('bang log');

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