[๐Ÿ’ป ์ฝ”๋“œ์Šคํ…Œ์ด์ธ  FE 44๊ธฐ]pre-project - 10์ผ์ฐจ

JiEunยท2023๋…„ 6์›” 22์ผ
0

โœ”๏ธ ์‹œ์ž‘

์งˆ๋ฌธ ์ž‘์„ฑ, ์ˆ˜์ • ํŽ˜์ด์ง€ ๋ฆฌํŒฉํ† ๋ง ๋ฐ ์ด์Šˆ ์‚ฌํ•ญ์„ ํ•ด๊ฒฐํ–ˆ๋‹ค.


๐Ÿ“ ์งˆ๋ฌธ ์ž‘์„ฑ, ์ˆ˜์ • ํŽ˜์ด์ง€

์งˆ๋ฌธ ์ž‘์„ฑ, ์ˆ˜์ • ํŽ˜์ด์ง€ quill editor ๋„์ž…,
๋ฆฌ๋•์Šค ํˆดํ‚ท์œผ๋กœ ๋ฆฌํŒฉํ† ๋ง, ์ปค์„œ๊ฐ€ ์•ž์œผ๋กœ ์˜ค๋Š” ์ด์Šˆ๋ฅผ ํ•ด๊ฒฐ ํ–ˆ๋‹ค.

store, reduce๋“ฑ์€ ๋ฏธ๋ฆฌ ์„ธํŒ…๋˜์–ด ์žˆ์–ด์„œ

๐Ÿ› ๏ธ quill editor

quill ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์„ค์น˜ํ•˜๊ณ 
textarea๋กœ ์ž‘์„ฑ๋˜์–ด ์žˆ๋˜ ๋ถ€๋ถ„์„ ๋ณ€๊ฒฝ๋งŒ ํ•ด์ฃผ๋ฉด ๋˜์„œ ๊ธˆ๋ฐฉ ์ ์šฉ์ด ๋˜์—ˆ๋‹ค.

<EditorContent
  value={'์•ˆ๋…•!'}
  theme='bubble'
  readOnly
  />

theme: "bubble"๋ฅผ ๋„ฃ์–ด์ฃผ๋ฉด ์ƒ๋‹จ ํˆด๋ฐ”๊ฐ€ ์‚ฌ๋ผ์ง€๊ณ 
input๊ณผ ๋™์ผํ•˜๊ฒŒ readonly ๋ฅผ ๋„ฃ์–ด์ฃผ๋ฉด ์ž‘์„ฑํ•˜์ง€ ๋ชปํ•˜๋„๋ก ๋ง‰์•„์ค€๋‹ค.

์ด๊ฑธ ํ†ตํ•ด ์งˆ๋ฌธ ๋ทฐํŽ˜์ด์ง€๋„ ์ˆ˜์ •ํ•˜๋ฉด ์ข‹์„ ๋“ฏ ์‹ถ๋‹ค.

๐Ÿ› ๏ธ ๋ฆฌ๋•์Šค ํˆดํ‚ท์œผ๋กœ ๋ฆฌํŒฉํ† ๋ง

//modules/index.js
const store = configureStore({
  reducer: {
    question: questionSlice.reducer,
  }
});

export default store;
.
.
.
//modules/questionSlice.jsx
const initialState = {
  tags: [],
}
const questionSlice = createSlice({
  name: "questionSlice",
  initialState,
typeTags: (state, action) => {
      state.tags = [...state.tags, action.payload];
    },
    updateTags: (state, action) => {
      state.tags = action.payload
    },
    checkPlusTags: (state) => {
      state.checkedCount += 1
    },
    checkMinusTags: (state) => {
      state.checkedCount -= 1
    },
	}
})

export const { updateTags, checkPlusTags, checkMinusTags, typeTags } = questionSlice.actions;
export default questionSlice;

์›๋ž˜๋Š” typeTags๋งŒ ์žˆ์—ˆ๋Š”๋ฐ updateTags, checkPlusTags,checkMinusTags ์ถ”๊ฐ€ํ•ด ์ฃผ์—ˆ๋‹ค.

action.payload๋Š” ๊ฐ ํ•จ์ˆ˜์˜ ์ธ์ž๋กœ ๋“ค์–ด์˜ค๋Š” ๊ฐ’๋“ค์ด๋ผ ์ƒ๊ฐํ•˜๋ฉด ๋œ๋‹ค.

//question.jsx
import { typeTags , checkPlusTags, checkMinusTags, updateTags} from '../../modules/questionSlice';

const tags = useSelector((state) => state.question.tags);
const checkCount = useSelector(state => state.question.checkedCount)

const handlerTag = (name, description) => {
    const tagSelected = tags.some((el) => el.tagName === name);

    if (tagSelected) {
      const updatedTags = tags.filter((el) => el.tagName !== name);
      dispatch(updateTags(updatedTags));
      dispatch(checkMinusTags())
    } else {
      const newTag = { tagName: name, tagDescription: description };
      dispatch(typeTags(newTag));
      dispatch(checkPlusTags())
    }
  };

state.question.checkedCount
์—์„œ question๋Š” store์— ์ž‘์„ฑ๋œ question: questionSlice.reducer๋ผ ์ƒ๊ฐํ•˜๋ฉด ๋œ๋‹ค.

questionํ•ด๋‹น ํŽ˜์ด์ง€๋Š”
useDispatch, useSelection์„ ์ด์šฉํ•ด action.payload๋กœ ์ „๋‹ฌ๋  ๊ฐ’์„ ์ธ์ž๋กœ ๋„ฃ์–ด์ฃผ๋ฉด ๋œ๋‹ค.

๋˜ํ•œ ๋‹ค๋ฅธ ์ฝ”๋“œ์—์„œ๋„ ์žฌ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•ด์„œ ๊ฐ’์„ ํ•˜๋‚˜ ๋” ๋งŒ๋“ค ํ•„์š”๊ฐ€ ์—†์—ˆ๊ณ 
ํ™•์‹คํžˆ ์ด์ „ ์ฝ”๋“œ์™€ ๋น„๊ตํ–ˆ์„ ๋•Œ ๊ฐ„๊ฒฐํ•ด ์กŒ๋‹ค.

๐Ÿ› ๏ธ ์—๋””ํ„ฐ ์ž‘์„ฑ ์‹œ ์ปค์„œ๊ฐ€ ์ž๊พธ ๋งจ ์•ž์œผ๋กœ ์ด๋™ ํ•˜๋Š” ๋ฌธ์ œ

๊ธ€ ์ž‘์„ฑ์‹œ ์ปค์„œ๊ฐ€ ๊ณ„์† ๋งจ ์•ž์œผ๋กœ ์ด๋™ํ•˜๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ์—ˆ๋‹ค.

๋ฌธ์ œ๋Š” title ๊ธฐ๋ณธ ๊ฐ’์ด "" ๋นˆ ๋ฌธ์ž์—ด๋กœ ๋“ค์–ด๊ฐ€๋Š”๋ฐ ์ด๊ฒŒ ๋ฌธ์ œ๊ฐ€ ๋˜์—ˆ๋˜๊ฑฐ ๊ฐ™๋‹ค.
defaultValue={memTitle || title} ์ด๋ ‡๊ฒŒ ์กฐ๊ฑด์„์ค˜ ์ˆ˜์ •ํ–ˆ๋‹ค.

๋˜ํ•œ value="" ๋กœ ๋„ฃ์„ ๊ฒฝ์šฐ input text ๋‚ด์šฉ์„ ์ˆ˜์ •ํ•  ์ˆ˜ ์—†์—ˆ๋‹ค.
์ด ๋ถ€๋ถ„์„ defaultValue="" ์œผ๋กœ ์ค˜์„œ ํ•ด๊ฒฐ ํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.

const title = useSelector((state) => state.question.title);
<QInput
  type='text'
  placeholder='์ œ๋ชฉ์„ ์ž‘์„ฑํ•ด ์ฃผ์„ธ์š”. (80์ž ์ดํ•˜)'
  defaultValue={memTitle || title}
  onChange={handleChange}
  />

โœ”๏ธ ์งˆ๋ฌธ ์ž‘์„ฑ

โœ”๏ธ ์งˆ๋ฌธ ์ˆ˜์ •


โœ”๏ธ Keep

  • ์ œ๋ชฉ ์ฐฝ์ด ์›๋ž˜ ํšŒ์ƒ‰ ๋ฐฐ๊ฒฝ์ด์˜€๋Š”๋ฐ ์—๋””ํ„ฐ์— ๋งž์ถฐ ์Šคํƒ€์ผ์„ ์ˆ˜์ •ํ–ˆ๋‹ค.
  • ๋ฌธ์ œ์˜ ๋‹ต ๊ฒ€์ƒ‰ํ•˜๋ฉด์„œ ์•Œ๊ฒŒ๋˜๋ฉด ์™œ ์ด๋Ÿฐ ๋‹ต์ด ๋‚˜์™”๋Š”์ง€ ์ฐพ์•„ ๋ณด์•˜๋‹ค.

โœ๏ธ Problem

  • quill ๋ง๊ณ  toast๋กœ ์ง„ํ–‰ํ•˜๋ ค๊ณ  ํ–ˆ์œผ๋‚˜ ๋ฒ„์ „ ๋ฌธ์ œ๋กœ ์ง„ํ–‰ํ•˜์ง€ ๋ชปํ–ˆ๋‹ค.
  • ์—๋””ํ„ฐ ์ž‘์„ฑ์‹œ ๋งจ ์•ž์œผ๋กœ ๋‚˜์˜ค๋Š” ๋ฌธ์ œ ํ•ด๊ฒฐํ•˜๋Š”๋ฐ ์‹œ๊ฐ„์„ ๋บ๊ฒผ๋‹ค.
  • ํƒœ๊ทธ ์„ ํƒ ๋ถ€๋ถ„์€ API ๋ช…์„ธ์„œ๊ฐ€ ๋ณ€๊ฒฝ๋˜๊ธฐ๋„ ํ–ˆ๊ณ  ๋ฐฑ์—”๋“œ ์ธก์—์„œ [1,2,3] ๋ฐฐ์—ด ์•ˆ์— ์ˆซ์ž๋กœ ์ง€์ •ํ•ด ์ฃผ์…”์„œ... ์•„์ง ์ง„ํ–‰ํ•˜์ง€ ๋ชปํ•˜๊ณ  ์žˆ๋‹ค.

๐Ÿš€ Try

  • ์งˆ๋ฌธ ๋ทฐํŽ˜์ด์ง€๋„ ์—๋””ํ„ฐ๋ฅผ ์ด์šฉํ•ด ์ง„ํ–‰ํ•˜๋ฉด ์ข‹์„ ๊ฒƒ ๊ฐ™๋‹ค ์ƒ๊ฐํ–ˆ๋‹ค.
    - dangerouslySetInnerHTML ๋ผ๋Š” ์†์„ฑ์„ ์ด์šฉํ•ด๋„ ๋˜์ง€๋งŒ ๋ณด์•ˆ์ƒ ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค๊ณ  ํ•œ๋‹ค.
    • ์—๋””ํ„ฐ์— readonly ์†์„ฑ์„ ์ฃผ๋ฉด ์–ด๋–จ๊นŒ ์‹ถ๋‹ค.

โœ๏ธ ๋งˆ์น˜๋ฉฐ

๋ฐฑ์—”๋“œ ์ธก๊ณผ์˜ ์†Œํ†ต์ด ์›ํ™œํ•˜์ง€ ์•Š์•„
ํƒœ๊ทธ ์˜์—ญ์— ์ด์Šˆ๊ฐ€ ์žˆ๋Š”๊ฑฐ ๊ฐ™๋‹ค.

๋˜ํ•œ OAuth ๋ถ€๋ถ„๋„ ์•„์ง ๊ตฌํ˜„ ์ค‘์ด๋ผ๊ณ  ํ•˜์…”์„œ
๋กœ๊ทธ์ธ ํŽ˜์ด์ง€, ๋กœ๊ทธ์ธ ๋  ๊ฒฝ์šฐ ๋‹ค๋ฅธ ๊ณณ๋„ ์ „๋ฉด ์ˆ˜์ •์ด ํ•„์š”ํ•œ ์ƒํ™ฉ์ด๋‹ค.

ํ˜„์žฌ 3~4์ผ ์ •๋„ ๋‚จ์€ ์ƒํ™ฉ์ธ๋ฐ
๋ฐฐํฌ ๊ธฐ๊ฐ„์„ ์ œ์™ธํ•˜๋ฉด 2์ผ ์ •๋„ ๋‚จ์•˜๋‹ค.

๊ณผ์—ฐ... ์ž˜ ํ•  ์ˆ˜ ์žˆ์„์ง€ ๊ฑฑ์ •์ด ๋œ๋‹ค.

profile
๐Ÿ’ป ํ”„๋ก ํŠธ์—”๋“œ๋ฅผ ๋ชฉํ‘œ๋กœ ์„ฑ์žฅ ์ค‘! (์•Œ์•„๋ดค๋˜ ๋‚ด์šฉ ๋“ฑ์„ ์ •๋ฆฌํ•˜๊ธฐ)

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