React - 생활코딩 3 - 클래스 방식과 함수방식 비교 및 라이프 사이클
★ React 리액트 리덕스(Redux) - 리덕스 완전정복 , 최신 리덕스 Toolkit 사용
vscode 확장 패키지 추가
1. - Auto Import - ES6, TS, JSX, TSX
2. - Reactjs code snippets
3. - ESLint
4. - Prettier - Code formatter
Visual Studio Code 폴더/파일 아이콘 변경하기
리액트 프로젝트 생성
npx create-react-app 경로
예) npx create-react-app E:\react-app2
1. 오리엔테이션
1.수업소개
2. 리덕스 여행의 지도
2-1.소개
2-2.state와 render의 관계
2-2.action과 reducer
3.Redux가 좋은 가장 중요한 이유
크롬브라우저 확장프로그램설치 리덕스 :
https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd?hl=ko-KR
4.Redux가 없다면
without-redux.html
<!DOCTYPE html> <html lang="ko"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>리덕스가 없다면</title> <style> .container{ border:5px solid black; padding:10px } </style> </head> <body> <div id="red"></div> <div id="green"></div> <div id="blue"></div> <script> function red(){ document.querySelector("#red").innerHTML=` <div class="container" id="component_red"> <h1>red</h1> <input type="button" value="fire" onclick="document.querySelector('#component_red').style.backgroundColor='red'; document.querySelector('#component_green').style.backgroundColor='red' document.querySelector('#component_blue').style.backgroundColor='red' "> </div> `; } red(); function green(){ document.querySelector("#green").innerHTML=` <div class="container" id="component_green"> <h1>green</h1> <input type="button" value="fire" onclick=" document.querySelector('#component_red').style.backgroundColor='green'; document.querySelector('#component_green').style.backgroundColor='green' ; document.querySelector('#component_blue').style.backgroundColor='green' "> </div> `; } green(); function blue(){ document.querySelector("#blue").innerHTML=` <div class="container" id="component_blue"> <h1>blue</h1> <input type="button" value="fire" onclick=" document.querySelector('#component_red').style.backgroundColor='blue'; document.querySelector('#component_green').style.backgroundColor='blue' ; document.querySelector('#component_blue').style.backgroundColor='blue' "> </div> `; } blue(); </script> </body> </html>
3. Redux의 적용
공식 사이트 : https://redux.js.org/
설치방식 : $npm install --save redux
CDN 방식 : https://cdnjs.com/libraries/redux
===================== ======== 다음을 추천한다.============= =====================
1. redux 설치
& yarn add redux react-redux redux-promise redux-thunk
2. createStore deprecate 로 인하여 React Redux Toolkit 설치
$ yarn add @reduxjs/toolkit
또는
$ npm install @reduxjs/toolkit react-redux
크롬브라우저 확장프로그램설치 리덕스 :
https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd?hl=ko-KR
===================== ===================== =====================
5.1.Redux의 적용 :store 생성
with-redux.html
<!DOCTYPE html> <html lang="ko"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>리덕스 적용</title> <script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.2.0/redux.min.js"></script> <style> .container{ border:5px solid black; padding:10px } </style> </head> <body> <div id="red"></div> <script> //은행 예시 //state - 은행 장부 //reducer - 은행 장부직원 //dispatch - 은행 창구직원 function reducer(state, action){ if(state===undefined){ return {color:"yellow"} } } //초기값 생성 const store=Redux.createStore(reducer); function red(){ //리덕스에서 데이터 가져오기 store.getState(); const state=store.getState(); console.log("getState" , state); document.querySelector("#red").innerHTML=` <div class="container" id="component_red" style="background-color:${state.color}"> <h1>red</h1> <input type="button" value="fire" onclick="document.querySelector('#component_red').style.backgroundColor='red'; document.querySelector('#component_green').style.backgroundColor='red' document.querySelector('#component_blue').style.backgroundColor='red' "> </div> `; } red(); </script> </body> </html>
5.2.reducer와 action을 이용해서 새로운 state 값 만들기
with-redux.html
<!DOCTYPE html> <html lang="ko"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>리덕스 적용</title> <script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.2.0/redux.min.js"></script> <style> .container{ border:5px solid black; padding:10px } </style> </head> <body> <div id="red"></div> <script> //은행 예시 //state - 은행 장부 //reducer - 은행 장부직원 //dispatch - 은행 창구직원 function reducer(state, action){ //state=>현재 store 값 console.log(state, action); if(state===undefined){ return {color:"yellow"} } if(action.type==="CHANGE_COLOR"){ //깊은 복사 newState=Object.assign({}, state, {color:'red'}) } return newState } //초기값 생성 const store=Redux.createStore(reducer); function red(){ //리덕스에서 데이터 가져오기 store.getState(); const state=store.getState(); console.log("getState" , state); document.querySelector("#red").innerHTML=` <div class="container" id="component_red" style="background-color:${state.color}"> <h1>red</h1> <input type="button" value="fire" onclick=" store.dispatch({type:'CHANGE_COLOR', color:'red'}) "> </div> `; } red(); </script> </body> </html>
5.3.state의 변화에 따라서 UI 반영하기
with-redux.html
<!DOCTYPE html> <html lang="ko"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>리덕스 적용</title> <script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.2.0/redux.min.js"></script> <style> .container{ border:5px solid black; padding:10px } </style> </head> <body> <div id="red"></div> <div id="blue"></div> <div id="green"></div> <script> //은행 예시 //state - 은행 장부 //reducer - 은행 장부직원 //dispatch - 은행 창구직원 function reducer(state, action){ //state=>현재 store 값 if(state===undefined){ return {color:"yellow"} } if(action.type==="CHANGE_COLOR"){ //깊은 복사 newState=Object.assign({}, state, {color:action.color}) } console.log(action.type, action, state, newState); return newState } //초기값 생성 const store=Redux.createStore(reducer); function red(){ //리덕스에서 데이터 가져오기 store.getState(); const state=store.getState(); document.querySelector("#red").innerHTML=` <div class="container" id="component_red" style="background-color:${state.color}"> <h1>red</h1> <input type="button" value="fire" onclick="store.dispatch({type:'CHANGE_COLOR', color:'red'})"> </div> `; } //subscribe 은 store 값이 변경되면 red 함수(여기서는 render()역할)가 호출되도록 한다. store.subscribe(red); red(); function blue(){ const state=store.getState(); document.querySelector("#blue").innerHTML=` <div class="container" id="component_blue" style="background-color:${state.color}"> <h1>blue</h1> <input type="button" value="fire" onclick="store.dispatch({type:'CHANGE_COLOR', color:'blue'})"> </div> `; } store.subscribe(blue); blue(); function green(){ const state=store.getState(); document.querySelector("#green").innerHTML=` <div class="container" id="component_green" style="background-color:${state.color}"> <h1>green</h1> <input type="button" value="fire" onclick="store.dispatch({type:'CHANGE_COLOR', color:'green'})"> </div> `; } store.subscribe(green); green(); </script> </body> </html>
6.Redux 선물: 시간여행과 로깅
크롬브라우저 확장프로그램설치 리덕스 :
https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd?hl=ko-KR
https://github.com/reduxjs/redux-devtools
Redux DevTools Extension : https://github.com/zalmoxisus/redux-devtools-extension
//초기값 생성 const store=Redux.createStore(reducer, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__() );
소스 : https://github.com/braverokmc79/LifeCoding/commit/af0e4bc73502d41268ed12f903db351e3ecf061c
4. 실전 Redux
7-1.정적인 웹페이지 만들기
main.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>실전 Redux</title> </head> <body> <header> <h1>WEB</h1> Hello, WEB! </header> <nav> <ol> <li><a href="1.html">HTML</a></li> <li><a href="2.html">CSS</a></li> </ol> </nav> <article> <ul> <li><a href="/create">create</a></li> <li><a href="/update">create</a></li> <li><input type="button" value="delete"></li> </ul> <h2>HTML</h2> HTML is ... </article> </body> </html>
7-2.부품화
main.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>실전 Redux</title> </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><a href="/update">update</a></li> <li><input type="button" value="delete"></li> </ul> `; } function article(){ document.querySelector("#content").innerHTML=` <article> <h2>HTML</h2> HTML is ... </article> `; } subject(); TOC(); control(); article(); </script> </body> </html>
7-3.store 생성과 state 사용하기
main.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.2.0/redux.min.js"></script> <title>실전 Redux</title> </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(){ const state=store.getState(); const liTags= state.controls.map(item=>{ return ` <li><a href="${item.id}">${item.title}</a></li> `; }); document.querySelector("#toc").innerHTML=` <nav> <ol> ${liTags.join("")} </ol> </nav> `; } function control(){ document.querySelector("#control").innerHTML=` <ul> <li><a href="/create">create</a></li> <li><a href="/update">update</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){ if(state===undefined){ return{ controls:[ {id:1,title:'HTML',desc:"HTML is ..."}, {id:2,title:'CSS', desc:"CSS is ..."}, {id:3,title:'js', desc:"js is ..."} ] } }<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.2.0/redux.min.js"></script> <title>실전 Redux</title> </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(){ const state=store.getState(); const liTags= state.controls.map(item=>{ return ` <li><a href="${item.id}">${item.title}</a></li> `; }); document.querySelector("#toc").innerHTML=` <nav> <ol> ${liTags.join("")} </ol> </nav> `; } function control(){ document.querySelector("#control").innerHTML=` <ul> <li><a href="/create">create</a></li> <li><a href="/update">update</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){ if(state===undefined){ return{ controls:[ {id:1,title:'HTML',desc:"HTML is ..."}, {id:2,title:'CSS', desc:"CSS is ..."}, {id:3,title:'js', desc:"js is ..."} ] } } return; } const store=Redux.createStore(reducer); const state=store.getState(); console.log("state ", state); subject(); TOC(); control(); article(); </script> </body> </html> return; } const store=Redux.createStore(reducer); const state=store.getState(); console.log("state ", state); subject(); TOC(); control(); article(); </script> </body> </html>
7-4.action을 dispatch를 통해서 전달하기
main.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.2.0/redux.min.js"></script> <title>실전 Redux</title> </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(){ const state=store.getState(); const liTags= state.controls.map(item=>{ return ` <li><a href="#" onclick="event.preventDefault(); const action={ type:'SELECT', id:${item.id} } store.dispatch(action); " href="${item.id}">${item.title}</a></li> `; }); document.querySelector("#toc").innerHTML=` <nav> <ol> ${liTags.join("")} </ol> </nav> `; } function control(){ document.querySelector("#control").innerHTML=` <ul> <li><a href="/create">create</a></li> <li><a href="/update">update</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){ if(state===undefined){ return{ selectd_id:null, controls:[ {id:1,title:'HTML',desc:"HTML is ..."}, {id:2,title:'CSS', desc:"CSS is ..."}, {id:3,title:'js', desc:"js is ..."} ] } } let newState={}; if(action.type==="SELECT"){ //깊은 복사 newState=Object.assign({}, state, {selectd_id:action.id}); } console.log(action, state, newState); } const store=Redux.createStore(reducer); const state=store.getState(); console.log("state ", state); subject(); TOC(); control(); article(); </script> </body> </html>
7-5.subscribe를 통해서 자동 갱신 되도록 처리
main.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.2.0/redux.min.js"></script> <title>실전 Redux</title> </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(){ const state=store.getState(); const liTags= state.contents.map(item=>{ return ` <li><a href="#" onclick="event.preventDefault(); const action={ type:'SELECT', id:${item.id} } store.dispatch(action); " href="${item.id}">${item.title}</a></li> `; }); document.querySelector("#toc").innerHTML=` <nav> <ol> ${liTags.join("")} </ol> </nav> `; } function control(){ document.querySelector("#control").innerHTML=` <ul> <li><a href="/create">create</a></li> <li><a href="/update">update</a></li> <li><input type="button" value="delete"></li> </ul> `; } function article(){ const state=store.getState(); console.log(" state", state); if(state.selectd_id!=undefined){ const data=state.contents.filter(item=>{ return item.id==state.selectd_id; })[0]; document.querySelector("#content").innerHTML=` <article> <h2>${data.title}</h2> ${data.desc} </article> `; } } function reducer(state, action){ if(state===undefined){ return{ selectd_id:2, contents:[ {id:1,title:'HTML',desc:"HTML is ..."}, {id:2,title:'CSS', desc:"CSS is ..."}, {id:3,title:'js', desc:"js is ..."} ] } } let newState={}; if(action.type==="SELECT"){ //깊은 복사 newState=Object.assign({}, state, {selectd_id:action.id}); } console.log(action, state, newState); return newState; } const store=Redux.createStore(reducer); store.subscribe(article); subject(); TOC(); control(); article(); </script> </body> </html>
7-6.글생성 기능 구현
main.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.2.0/redux.min.js"></script> <title>실전 Redux</title> </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(){ const state=store.getState(); const liTags= state.contents.map(item=>{ return ` <li><a href="#" onclick="event.preventDefault(); const action={ type:'SELECT', id:${item.id} } store.dispatch(action); " href="${item.id}">${item.title}</a></li> `; }); document.querySelector("#toc").innerHTML=` <nav> <ol> ${liTags.join("")} </ol> </nav> `; } function control(){ const state=store.getState(); document.querySelector("#control").innerHTML=` <ul> <li><a onclick=" event.preventDefault(); " href="/create">create</a></li> <li><a onclick="event.preventDefault(); " href="/update">update</a></li> <li><input type="button" value="delete"></li> </ul> `; } function article(){ const state=store.getState(); if(state.mode==="create"){ document.querySelector("#content").innerHTML=` <article> <form onsubmit=" event.preventDefault(); const _title=this.title.value; const _desc=this.desc.value; store.dispatch({ type:'CREATE', title:_title, desc:_desc }) " > <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"){ const data=state.contents.filter(item=>{ return item.id==state.selectd_id; })[0]; document.querySelector("#content").innerHTML=` <article> <h2>${data.title}</h2> ${data.desc} </article> `; } } function reducer(state, action){ if(state===undefined){ return{ max_id:3, mode:'create', selectd_id:2, contents:[ {id:1,title:'HTML',desc:'HTML is ...'}, {id:2,title:'CSS', desc:'CSS is ...'}, {id:3,title:'js', desc:'js is ...'} ] } } let newState={}; if(action.type==="SELECT"){ //깊은 복사 newState=Object.assign({}, state, {selectd_id:action.id}); }else if(action.type==="CREATE"){ //concat() 을 하면 복제 처리 된다. 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, selectd_id:newMaxId, mode:'read' }); } console.log(action, state, newState); return newState; } const store=Redux.createStore(reducer); store.subscribe(article); store.subscribe(TOC); subject(); TOC(); control(); article(); </script> </body> </html>
7-7.글삭제 기능 구현
main.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.2.0/redux.min.js"></script> <title>실전 Redux</title> </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(){ const state=store.getState(); const liTags= state.contents.map(item=>{ return ` <li><a href="#" onclick="event.preventDefault(); const action={ type:'SELECT', id:${item.id} } store.dispatch(action); " href="${item.id}">${item.title}</a></li> `; }); document.querySelector("#toc").innerHTML=` <nav> <ol> ${liTags.join("")} </ol> </nav> `; } function control(){ const state=store.getState(); document.querySelector("#control").innerHTML=` <ul> <li><a onclick=" event.preventDefault(); store.dispatch({ type:'CREATE_FORM' }) " href="/create">create</a></li> <li><a onclick="event.preventDefault(); store.dispatch({ type:'UPDATE_FORM' }) " href="/update">update</a></li> <li><input type="button" onclick="event.preventDefault(); store.dispatch({ type:'DELETE' }) " value="delete"></li> </ul> `; } function article(){ const state=store.getState(); if(state.mode==="create"){ document.querySelector("#content").innerHTML=` <article> <form onsubmit=" event.preventDefault(); const _title=this.title.value; const _desc=this.desc.value; store.dispatch({ type:'CREATE', title:_title, desc:_desc }) " > <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"){ const data=state.contents.filter(item=>{ return item.id==state.selectd_id; })[0]; document.querySelector("#content").innerHTML=` <article> <h2>${data.title}</h2> ${data.desc} </article> `; }else if(state.mode=="welcome"){ document.querySelector("#content").innerHTML=` <article> <h2>Welcome</h2> Hello, Redux!!! </article> `; } } function reducer(state, action){ if(state===undefined){ return{ max_id:3, mode:'welcome', selectd_id:2, contents:[ {id:1,title:'HTML',desc:'HTML is ...'}, {id:2,title:'CSS', desc:'CSS is ...'}, {id:3,title:'js', desc:'js is ...'} ] } } let newState={}; if(action.type==="SELECT"){ //깊은 복사 newState=Object.assign({}, state, { mode:"read", selectd_id:action.id }); }else if(action.type==="CREATE_FORM" ){ state.mode="create"; newState=Object.assign({}, state, { mode:"create" }) }else if(action.type==="CREATE"){ //concat() 을 하면 복제 처리 된다. 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, selectd_id:newMaxId, mode:'read' }); }else if(action.type==="DELETE"){ const newContents=state.contents.filter((item)=>{ return item.id !=state.selectd_id; }); //console.log("_contents ", _contents); newState=Object.assign({}, state, { contents:newContents, mode:'welcome' }); } console.log(action, state, newState); return newState; } const store=Redux.createStore(reducer); store.subscribe(article); store.subscribe(TOC); subject(); TOC(); control(); article(); </script> </body> </html>
7-7.글수정 구현
main.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.2.0/redux.min.js"></script> <title>실전 Redux</title> </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(){ const state=store.getState(); const liTags= state.contents.map(item=>{ return ` <li><a href="#" onclick="event.preventDefault(); const action={ type:'SELECT', id:${item.id} } store.dispatch(action); " href="${item.id}">${item.title}</a></li> `; }); document.querySelector("#toc").innerHTML=` <nav> <ol> ${liTags.join("")} </ol> </nav> `; } function control(){ const state=store.getState(); document.querySelector("#control").innerHTML=` <ul> <li><a onclick=" event.preventDefault(); store.dispatch({ type:'CREATE_FORM' }) " href="/create">create</a></li> <li><a onclick="event.preventDefault(); store.dispatch({ type:'UPDATE_FORM' }) " href="/update">update</a></li> <li><input type="button" onclick="event.preventDefault(); store.dispatch({ type:'DELETE' }) " value="delete"></li> </ul> `; } function article(){ const state=store.getState(); if(state.mode==="create"){ document.querySelector("#content").innerHTML=` <article> <form onsubmit=" event.preventDefault(); const _title=this.title.value; const _desc=this.desc.value; store.dispatch({ type:'CREATE', title:_title, desc:_desc }) " > <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"){ const data=state.contents.filter(item=>{ return item.id==state.selectd_id; })[0]; document.querySelector("#content").innerHTML=` <article> <h2>${data.title}</h2> ${data.desc} </article> `; }else if(state.mode=="welcome"){ document.querySelector("#content").innerHTML=` <article> <h2>Welcome</h2> Hello, Redux!!! </article> `; }else if(state.mode=="update"){ const state=store.getState(); const data=state.contents.filter((item)=>{ return item.id===state.selectd_id; })[0]; console.log("data ", data); document.querySelector("#content").innerHTML=` <article> <form onsubmit=" event.preventDefault(); const _title=this.title.value; const _desc=this.desc.value; store.dispatch({ type:'UPDATE', title:_title, desc:_desc }) " > <p> <input type="text" name="title" placeholder="title" value="${data.title}" > </p> <p> <textarea name="desc" placeholder="description" >${data.desc}</textarea> </p> <p> <input type="submit"> </p> </form> </article> `; } } function reducer(state, action){ if(state===undefined){ return{ max_id:3, mode:'welcome', selectd_id:2, contents:[ {id:1,title:'HTML',desc:'HTML is ...'}, {id:2,title:'CSS', desc:'CSS is ...'}, {id:3,title:'js', desc:'js is ...'} ] } } let newState={}; if(action.type==="SELECT"){ //깊은 복사 newState=Object.assign({}, state, { mode:"read", selectd_id:action.id }); }else if(action.type==="CREATE_FORM" ){ newState=Object.assign({}, state, { mode:"create" }) }else if(action.type==="CREATE"){ //concat() 을 하면 복제 처리 된다. 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, selectd_id:newMaxId, mode:'read' }); }else if(action.type==="DELETE"){ const newContents=state.contents.filter((item)=>{ return item.id !=state.selectd_id; }); //console.log("_contents ", _contents); newState=Object.assign({}, state, { contents:newContents, mode:'welcome' }); }else if(action.type==="UPDATE_FORM" ){ newState=Object.assign({}, state, { mode:"update" }) }else if(action.type==="UPDATE"){ console.log("UPDATE DATA : ", action); const newContents=state.contents.map(item=>{ if(item.id===state.selectd_id){ const data={ id:state.selectd_id, title:action.title, desc:action.desc }; return data; }else{ return item; } }); newState=Object.assign({}, state, { contents:newContents, mode:'read', }); } console.log(action, state, newState); return newState; } const store=Redux.createStore(reducer); store.subscribe(article); store.subscribe(TOC); subject(); TOC(); control(); article(); </script> </body> </html>
5. 마무리
소스 : https://github.com/braverokmc79/LifeCoding
댓글 ( 4)
댓글 남기기