🌐 Web/Redux

08. 웹페이지 만들기(2)

dlalwl_jpg 2022. 9. 14. 16:49

1. store 생성

우리가 redux를 사용하기 위해서 제일 첫 번째를 store를 만들어야 하는 동시에 reducer를 생성해야 했다.

그리고 <head> 부분에 redux를 로딩해주었다.

 main.html

<!DOCTYPE html>
<html>
    <head>
        <!--redux를 웹페이지에 로딩-->
        <script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.2.0/redux.js"></script>
    </head>

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

    function subject(){
        document.querySelector('#subject').innerHTML = `
        <header>
            <h1>WEB</h1>
            Hello, WEB!
        </header>
        `
    }

    function TOC(){
        document.querySelector('#toc').innerHTML = `
        <nav>
            <ol>
                <li><a href="1.html">HTML</a></li>
                <li><a href="2.html">CSS</a></li>
            </ol>
        </nav>
        `;
    }
    
    function control(){
        document.querySelector('#control').innerHTML = `
        <ul>
            <li><a href="/create">create</a></li>
            <li><input type="button" value="delete"></li>
        </ul>
        `;
    }

    function article(){
        document.querySelector('#content').innerHTML = `
        <article>
            <h2>HTML</h2>
            HTML is ...
        </article>
        `
    }

    function reducer(state, action){ //이전의 상태 값과 호출된 이후의 action 값을 받는다.

        if(state === undefined){ //초기값 셋팅
            return{
                contents:[
                    {id:1, title:'HTML', desc:'HTML is ...'},
                    {id:2, titme:'CSS', desc: 'CSS is ...'}
                ]
            }
        }
        return //새로운 상태값 반환
    }
    
    var store = Redux.createStore(reducer); //store생성

    subject();
    TOC();
    control();
    article();
        </script>
    </body>
</html>

 

결과화면

store.getState()를 통해 초기값도 잘 설정되었는지 확인할 수 있다.


2. state 사용하기

코드에서 TOC의 함수의 내부를 보면 글목록이 있는데 글목록을 store에 있는 정보를 바탕으로 가져올 것이다.

main.html

<!DOCTYPE html>
<html>
    <head>
        <!--redux를 웹페이지에 로딩-->
        <script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.2.0/redux.js"></script>
    </head>

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

    function subject(){
        document.querySelector('#subject').innerHTML = `
        <header>
            <h1>WEB</h1>
            Hello, WEB!
        </header>
        `
    }

    function TOC(){
        var state = store.getState();
        var i = 0;
        var liTags = '';

        while(i < state.contents.length){
            liTags = liTags + `
                <li>
                    <a href="${state.contents[i].id}">${state.contents
                    [i].title}</a>
                </li>`;
            i = i + 1;
        }

        document.querySelector('#toc').innerHTML = `
        <nav>
            <ol>${liTags}</ol>
        </nav>
        `;
    }
    
    function control(){
        document.querySelector('#control').innerHTML = `
        <ul>
            <li><a href="/create">create</a></li>
            <li><input type="button" value="delete"></li>
        </ul>
        `;
    }

    function article(){
        document.querySelector('#content').innerHTML = `
        <article>
            <h2>HTML</h2>
            HTML is ...
        </article>
        `
    }

    function reducer(state, action){ //이전의 상태 값과 호출된 이후의 action 값을 받는다.

        if(state === undefined){ //초기값 셋팅
            return{
                contents:[
                    {id:1, title:'HTML', desc:'HTML is ...'},
                    {id:2, title:'CSS', desc: 'CSS is ...'}
                ]
            }
        }
        return //새로운 상태값 반환
    }
    
    var store = Redux.createStore(reducer); //store생성

    subject();
    TOC();
    control();
    article();
        </script>
    </body>
</html>

이런 식으로 각각의 구성요소가 store에서 state를 가져온 다음, state값을 기반으로 html코드를 생성해주면 그 state에 따라 만들어지는 웹 페이지를 생성할 수 있다.

강의 영상 - https://youtu.be/NK7p71gDVTU


3. action을 dispatch를 통해 전달

이제 store의 state값을 변경하려고 한다.

이때, 그러기 위해서는 action을 발생시키고, 그 action이 dispatch를 통해서 reducer를 실행시키면 reducer가 state의 새로운 값을 내보내준다. 그리고 state의 값이 바뀌면 subscribe하고 있는 함수들을 호출해 주는 것을 통해 UI가 업데이트 된다는 것을 상기하고 코드를 작성해보자.

글 목록을 클릭했을 때 action이 만들어지도록 할 것이다.

 

main.html

<!DOCTYPE html>
<html>
    <head>
        <!--redux를 웹페이지에 로딩-->
        <script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.2.0/redux.js"></script>
    </head>

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

    function subject(){
        document.querySelector('#subject').innerHTML = `
        <header>
            <h1>WEB</h1>
            Hello, WEB!
        </header>
        `
    }

    function TOC(){
        var state = store.getState();
        var i = 0;
        var liTags = '';

        while(i < state.contents.length){
            liTags = liTags + `
                <li>
                    <a onclick="
                        event.preventDefault(); <!--event가 발생했을 때 event를 발생시킨 태그의 기본 동작을 방지-->
                        var action = {type: 'SELECT', id:${state.contents[i].id}} //type은 action에서 필수적
                        store.dispatch(action); //dispatch로 action정보가 넘어감. 그리고 reducer 호출됨
                    "href="${state.contents[i].id}">
                        ${state.contents[i].title}
                    </a>
                </li>`;
            i = i + 1;
        }

        document.querySelector('#toc').innerHTML = `
        <nav>
            <ol>${liTags}</ol>
        </nav>
        `;
    }
    
    function control(){
        document.querySelector('#control').innerHTML = `
        <ul>
            <li><a href="/create">create</a></li>
            <li><input type="button" value="delete"></li>
        </ul>
        `;
    }

    function article(){
        document.querySelector('#content').innerHTML = `
        <article>
            <h2>HTML</h2>
            HTML is ...
        </article>
        `
    }

    function reducer(state, action){ //이전의 상태 값과 호출된 이후의 action 값을 받는다.

        if(state === undefined){ //초기값 셋팅
            return{
                selected_id:null,
                contents:[
                    {id:1, title:'HTML', desc:'HTML is ...'},
                    {id:2, title:'CSS', desc: 'CSS is ...'}
                ]
            }
        }

        var newState;
        if(action.type === 'SELECT'){
            newState = Object.assign({}, state, {selected_id:action.id}); 
            //state의 속성값이 빈객체에 복제되고, 그것이 newState가 된다.
            //즉, newState는 기존의 값인 state에 selected_id값이 덮어쓰기 된 값이 된다.
        }

        console.log(action, state, newState);
        return newState;
    }
    
    var store = Redux.createStore(reducer); //store생성

    subject();
    TOC();
    control();
    article();
        </script>
    </body>
</html>

 

결과화면

첫 번째는 HTML을 클릭했을 때이고, 두 번째가 CSS를 클릭했을 때이다.

첫 번째 클릭했을 때 값을 보면 selected_id값이 1번이고, array 2개 있다는 것을 확인할 수 있다.

두 번째 클릭했을 때 값을 보면 노란색은 action, 초록색은 이전의 state, 하늘색을 새로 만들어진 state를 나타낸다.

그리고 store.getstate()를 통해 우리가 선택한 selected_id값이 잘 셋팅된 것을 확인할 수 있다.

 

강의 영상 - https://youtu.be/ldxFOG4GfLk


4. subscribe를 통해 자동 갱신 처리

이제 selected_id라는 state값에 따라 본문 영역이 그에 맞는 내용을 보여주도록 할 것이다.

그럴려면 article이 state값에 맞게 바뀌어야 한다.

그리고 state값이 바뀌었을 때 자동으로 article 함수가 호출되도록 해야 한다.

 

main.html

<!DOCTYPE html>
<html>
    <head>
        <!--redux를 웹페이지에 로딩-->
        <script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.2.0/redux.js"></script>
    </head>

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

    function subject(){
        document.querySelector('#subject').innerHTML = `
        <header>
            <h1>WEB</h1>
            Hello, WEB!
        </header>
        `
    }

    function TOC(){
        var state = store.getState();
        var i = 0;
        var liTags = '';

        while(i < state.contents.length){
            liTags = liTags + `
                <li>
                    <a onclick="
                        event.preventDefault(); <!--event가 발생했을 때 event를 발생시킨 태그의 기본 동작을 방지-->
                        var action = {type: 'SELECT', id:${state.contents[i].id}} //type은 action에서 필수적
                        store.dispatch(action); //dispatch로 action정보가 넘어감. 그리고 reducer 호출됨
                    "href="${state.contents[i].id}">
                        ${state.contents[i].title}
                    </a>
                </li>`;
            i = i + 1;
        }

        document.querySelector('#toc').innerHTML = `
        <nav>
            <ol>${liTags}</ol>
        </nav>
        `;
    }
    
    function control(){
        document.querySelector('#control').innerHTML = `
        <ul>
            <li><a href="/create">create</a></li>
            <li><input type="button" value="delete"></li>
        </ul>
        `;
    }

    function article(){
        var state = store.getState();
        var i = 0;
        var aTitle, aDesc;
        while(i < state.contents.length){
            
            if(state.contents[i].id === state.selected_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>
        `
    }

    function reducer(state, action){ //이전의 상태 값과 호출된 이후의 action 값을 받는다.

        if(state === undefined){ //초기값 셋팅
            return{
                selected_id:2,
                contents:[
                    {id:1, title:'HTML', desc:'HTML is ...'},
                    {id:2, title:'CSS', desc: 'CSS is ...'}
                ]
            }
        }

        var newState;
        if(action.type === 'SELECT'){
            newState = Object.assign({}, state, {selected_id:action.id}); 
            //state의 속성값이 빈객체에 복제되고, 그것이 newState가 된다.
            //즉, newState는 기존의 값인 state에 selected_id값이 덮어쓰기 된 값이 된다.
        }

        console.log(action, state, newState);
        return newState;
    }
    
    var store = Redux.createStore(reducer); //store생성
    store.subscribe(article);//subscribe는 값이 바뀌면 함수를 자동으로 호출함
    subject();
    TOC();
    control();
    article();
        </script>
    </body>
</html>

결과화면

HTML을 클릭했을 때와 CSS를 클릭했을 때 본문의 내용이 잘 바뀌는 것을 볼 수 있다.

그렇다면 배웠던 것을 복습삼아 왜 바뀌는지 생각해보자.

우리는 action을 통해 dispatch에 값을 전달하고 reducer가 state값을 갱신해 dispatch가 subscribe하고 있는 함수들을 호출해주기 때문에 그에 따라 render가 동작해 새로운 state값을 참조하여 UI를 새로 그리기 때문이다.

 

강의영상 - https://youtu.be/zMTqWoe25aU