๐Ÿ‘พ Redux๋ฅผ ์ด์šฉํ•œ ๊ฐ„๋‹จํ•œ ๊ฒŒ์‹œ๋ฌผ ์ถ”๊ฐ€ ๋ฐ ์‚ญ์ œ

๊ถŒ๊ทœ๋ฆฌยท2023๋…„ 6์›” 5์ผ
0

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ปFrontEnd

๋ชฉ๋ก ๋ณด๊ธฐ
24/29
post-thumbnail

๐Ÿ“ข ์—ฌ๋Š” ๋ง

์ด์ „์— ๋ฐ”๋‹๋ผ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ ToDo-List๋ฅผ ๊ฐ„๋‹จํ•˜๊ฒŒ ๊ตฌํ˜„ํ•œ ์ ์ด ์žˆ์—ˆ๋‹ค. ๊ทธ๋•Œ๋„ ๋ฉ”๋ชจ์žฅ์„ ์ถ”๊ฐ€ํ•˜๊ณ , ์‚ญ์ œํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ๊นŒ์ง€๋งŒ ๊ตฌํ˜„์„ ํ–ˆ์—ˆ๋Š”๋ฐ, ๋ฆฌ๋•์Šค๋กœ ๋งŒ๋“ค์–ด๋ณผ๊นŒ? ํ•˜๋Š” ์ƒ๊ฐ์ด ๋“ค์—ˆ๋‹ค. ๊ฒฐ๋ก ์€ ... ์ •๋ง ๊ฐ„๋‹จํ•˜๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์„ ์ค„ ์•Œ์•˜์ง€๋งŒ ์ƒ๊ฐ๋ณด๋‹ค ๋” ๋ณต์žกํ–ˆ๋‹ค๋Š” ๊ฒƒ. ๊ทธ๋ž˜์„œ ํ—ท๊ฐˆ๋ฆฌ๊ณ  ์–ด๋ ค์› ๋˜ ๋ถ€๋ถ„ ์œ„์ฃผ๋กœ ๊ธ€์„ ์ž‘์„ฑํ•ด๋ณด๋ ค๊ณ  ํ•œ๋‹ค.


01. ๊ธฐ๋ณธ์ ์ธ ํ‹€

    <div id="subject"></div>
    <div id="toc"></div>
    <div id="control"></div>
    <div id="content"></div>

์ด๋ ‡๊ฒŒ id ๊ฐ’์„ ์ฃผ๊ณ  ์ด๋“ค์„ ํ•จ์ˆ˜ ์•ˆ์— document.querySelector์„ ํ†ตํ•ด ๋„ฃ์–ด์ค„ ๊ฒƒ์ด๋‹ค.


02. ์ฝ”๋“œ ๋ฆฌ๋ทฐ

1. reducer ํ•จ์ˆ˜

๐Ÿ“reducer์€ store์„ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•ด ๋งŒ๋“  ํ•จ์ˆ˜์ด๋‹ค.

function reducer(state,action){
    if(state===undefined){
        // 1.HTML, 2.CSS ๊ธ€๋ชฉ๋ก์„ ๋„ฃ์–ด์ค„ ๊ฒƒ.
        return{
            max_id:2 ,
          	selcted_id:2,
            mode:'welcome',
            contents:[
                {id:1, title:"HTML", desc:"HTML is ..."},
                {id:2, title:"CSS", desc:"CSS is ..."}
            ]
        }
    }
  • ํ™”๋ฉด์— ์žˆ๋Š” HTML๊ณผ CSS์˜ id , title, desc์„ content๋ผ๋Š” ๋ฐฐ์—ด์— ๋‹ด์•„์ฃผ์—ˆ๊ณ  mode : 'welcome'์œผ๋กœ ์ง€์ •ํ•˜์—ฌ ์ด๋ฅผ ์ดˆ๊ธฐ๊ฐ’์œผ๋กœ ์„ค์ •ํ–ˆ๋‹ค.

2. TOC ํ•จ์ˆ˜

๐Ÿ“TOC ํ•จ์ˆ˜ ๋ถ€๋ถ„์€ ๊ธ€ ๋ชฉ๋ก์ด ๋‚˜ํƒ€๋‚˜๋Š” ๋ถ€๋ถ„์ด๋‹ค.

let state= store.getState();
    let i= 0;
    let liTags='';
    while(i<state.contents.length){
        liTags= liTags+ `
            <li>
                <a onclick='
                    event.preventDefault();
                    let action = {type:'SELECT', id:${state.contents[i].id}}
                    store.dispatch(action);
                ' href="${state.contents[i].id}">${state.contents[i].title}</a>
            </li>
                `;
        i+=1;
    }
    document.querySelector('#toc').innerHTML=
    `
        <nav>
            <ol>${liTags}</ol>
        </nav>
    `;
}
  • liTags๋Š” ๋นˆ ๋ฌธ์ž์—ด๋กœ ์„ ์–ธํ•œ ๋’ค, ๋ฐ˜๋ณต๋ฌธ์„ ํ†ตํ•ด ๋ฐ˜๋ณตํ•˜๋ฉด์„œ 1.HTML , 2.CSS ์ฒ˜๋Ÿผ ๊ธ€ ๋ชฉ๋ก์ด ๋‚˜ํƒ€๋‚  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ฃผ์—ˆ๋‹ค.
  • ๊ธ€ ๋ชฉ๋ก์€ ๊ฐ๊ฐ ๋งํฌ๋กœ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ์–ด์„œ ๋งํฌ๋ฅผ ํด๋ฆญํ•˜๋ฉด 404๊ฐ€ ๋œฌ๋‹ค. ์ด๋ฅผ ๋ฐฉ์ง€ํ•ด์ฃผ๊ธฐ ์œ„ํ•˜์—ฌ onClick ์ด๋ฒคํŠธ์— event.preventDefault( )๊ฐ’์„ ์ฃผ์—ˆ๋‹ค.

  • ๊ธ€ ๋ชฉ๋ก์„ ๋ˆ„๋ฅด๋ฉด title์ด ๋‹ค๋ฅด๊ฒŒ ๋‚˜ํƒ€๋‚˜์•ผ ํ•œ๋‹ค. ๊ทธ๋ž˜์„œ action์— type: 'SELECT', id:id:${state.contents[i].id} ๋ฅผ ์„ค์ •ํ–ˆ๋‹ค. ๐Ÿ“Œ id๊ฐ€ ๊ธ€์˜ ๋ฒˆํ˜ธ์ด๋‹ค.

  • action ๊ฐ’์€ store.dispatch(action);๋กœ ์ „๋‹ฌ๋˜์–ด reducer์—๊ฒŒ ๊ฐ€์•ผํ•ด์„œ ์ด ๊ตฌ๋ฌธ์„ ์ž‘์„ฑํ–ˆ๋‹ค.


3. control ํ•จ์ˆ˜

๐Ÿ“ control์€ ๊ธ€์„ ์ž‘์„ฑ, ์‚ญ์ œํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์„ ๋‹ด์€ ๋ถ€๋ถ„์ด๋‹ค.

function control(){
    document.querySelector('#control').innerHTML = `
    <ul>
        <li><a href="/create">create</a></li>

        <li><input type="button" value="delete"></li>
    </ul>
    `;
}
  • create์™€ delete๋Š” ๋”ฐ๋กœ action์„ ๋ณ€์ˆ˜๋กœ ์„ ์–ธํ•˜์—ฌ ๋‹ด์ง€ ์•Š๊ณ , ๋ฐ”๋กœ dispatch์—๊ฒŒ ์ „๋‹ฌํ•ด์ฃผ๋Š” ๋ฐฉ์‹์œผ๋กœ ํ–ˆ๋‹ค.

๐Ÿค” ์™œ create๋Š” a ํƒœ๊ทธ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ , delete๋Š” button์œผ๋กœ ํ–ˆ์„๊นŒ?

๐Ÿ”Ž delete๋Š” a href ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด, ์ž๋™ํ™”๋œ ํ”„๋กœ๊ทธ๋žจ์— ์˜ํ•ด ์‚ญ์ œ ๊ธฐ๋Šฅ์„ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— button์œผ๋กœ ๊ตฌํ˜„ํ–ˆ๋‹ค.


4. article ํ•จ์ˆ˜

๐Ÿ“ create, read, welcome ๋ชจ๋“œ๋ฅผ ๋‹ด์€ ํ•จ์ˆ˜์ด๋‹ค.

  • create ๋ชจ๋“œ๋Š” control ํ•จ์ˆ˜์—์„œ create๋ฅผ ๋ˆŒ๋ €์„ ๋•Œ ๊ธ€์„ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋Š” ๋ถ€๋ถ„์ด ๋‚˜ํƒ€๋‚œ๋‹ค.
  • read ๋ชจ๋“œ๋Š” TOC ํ•จ์ˆ˜์—์„œ ๊ธ€ ๋ชฉ๋ก์„ ํด๋ฆญ ํ–ˆ์„ ๋•Œ ์•„๋ž˜ ์‚ฌ์ง„๊ณผ ๊ฐ™์ด ํ•˜๋‹จ์—์„œ ๋ฌธ๊ตฌ๋ฅผ ๋ณด์—ฌ์ค€๋‹ค.
  • welcome ๋ชจ๋“œ๋Š” delete action์ด ์‹คํ–‰๋  ๋•Œ ์•„๋ž˜ ์‚ฌ์ง„๊ณผ ๊ฐ™์ด ํ•˜๋‹จ์—์„œ ๋ฌธ๊ตฌ๋ฅผ ๋ณด์—ฌ์ค€๋‹ค.

function article(){
    let state = store.getState();
    if(state.mode === 'create'){
        document.querySelector('#content').innerHTML = `
        <article>
            <form>
                <p>
                    <input type="text" name="title" placeholder="title">
                </p>
                <p>
                    <textarea name="desc" placeholder="description"></textarea>
                </p>
                <p>
                    <input type="submit">
                </p>
            </form>
        </article>
        `
    } else if(state.mode === 'read'){
        let i = 0;
        let aTitle, aDesc;
        while(i < state.contents.length){
            if(state.contents[i].id === state.selcted_id) {
                aTitle = state.contents[i].title;
                aDesc = state.contents[i].desc;
                break;
            }
            i = i + 1;
        }
        document.querySelector('#content').innerHTML = `
        <article>
            <h2>${aTitle}</h2>
            ${aDesc}
        </article>
        `
    } else if(state.mode === 'welcome'){
        document.querySelector('#content').innerHTML = `
        <article>
            <h2>Welcome</h2>
            Hello, Redux!!!
        </article>
        `
    }
}
  • read๋ชจ๋“œ์—์„œ if(state.contents[i].id === state.selcted_id) ๋ถ€๋ถ„์€ ๋‚ด๊ฐ€ ๊ณ ๋ฅธ ๊ธ€ ๋ชฉ๋ก์˜ ๋ฒˆํ˜ธ(state.selcted_id)์ด state.contents์— ์žˆ๋Š” id์˜ ๊ฐ’๊ณผ ๋™์ผํ•œ์ง€ ํ™•์ธํ•œ๋‹ค๋Š” ์˜๋ฏธ์ด๋‹ค.

5. reducer ํ•จ์ˆ˜ ๋‚ด์— ๋ณต์ œํ•œ state

๐Ÿ“ ๊ธฐ์กด์˜ state๋ฅผ ๋ณ€๊ฒฝ์‹œ์ผœ return ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ state ๊ฐ’์„ ๋ณต์ œํ•˜์—ฌ ๊ฐ’์„ ๋ณ€๊ฒฝ์‹œํ‚จ ๊ฒƒ์„ return ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

   let newState;
   // SELECT๋Š” 1.HTML์ฒ˜๋Ÿผ ๊ธ€ ๋ชฉ๋ก ๋ถ€๋ถ„
   if(action.type === 'SELECT'){
       newState = Object.assign({}, state, 
           {selcted_id:action.id, mode:'read'});
   } 
	else if(action.type === 'CREATE'){
       let newMaxId = state.max_id + 1;
       let newContents = state.contents.concat();
       newContents.push({id:newMaxId, title:action.title, desc:action.desc});
       newState = Object.assign({}, state, {
           max_id:newMaxId,
           contents:newContents,
           mode:'read'
       })
   } 
	else if(action.type === 'DELETE'){
       let newContents = [];
       let i = 0;
       while(i < state.contents.length){
           if(state.selcted_id !== state.contents[i].id){
               newContents.push(
                   state.contents[i]
               );
           }
           i = i + 1;
       }
       newState = Object.assign({},state, {
           contents:newContents,
           mode:'welcome'
       })
   } else if(action.type === 'CHANGE_MODE'){
       newState = Object.assign({}, state, {
           mode:action.mode
       });
   }
   console.log(action, state, newState);
   return newState;
  • action.type์ด CHANGE_MODE(create ๋งํฌ)์ผ ๋•Œ mode:action.mode์€ CHANGE_MODE์ผ ๋•Œ mode๊ฐ€ create์ด๋ฏ€๋กœ article์˜ create ๋ถ€๋ถ„์„ ๊ฐ€๋ฅดํ‚จ๋‹ค.
profile
๊ธฐ๋ก์žฅ ๐Ÿ“

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