Sparta/항해99

항해 사전준비 2일차 - 종합반2~5주차,토이프로젝트 기획, React, Redux

또롱또 2022. 4. 30. 12:48
728x90

 

사전준비 2일차

기초 문법이 준비가 됬으니 실전을 경험할 차례지만, 

곧 입학시험이 있으니

오늘 공부할 내용은

1. 웹개발 종합반 2~5주차

2. 토이프로젝트 기획

입학시험 대비여서 html, css, js, jquery, ajax, python-flask 로 구현해야한다.

3. 생활코딩의 React (function) - https://opentutorials.org/course/4900

까지만 하려고 한다.

 

종합반은 한번 수강했던 내용이므로, 정해진 시간보다 빠르게 리캡이 가능할거 같고,

토이프로젝트 기획은 뭐.. 일단 기획만 하는거고, 아이디어는 대충 있으니까

flowchart 그리는 쪽으로 진행을 해보려고 한다.

 

생활코딩은 React 강의가 2개인데, 

 class를 이용해서 만드는 강의와 function을 이용하는 강의가있다.

이것저것 찾아보니, function을 이용해 만드는 강의가 2022년 개정판이고,

이게 요즘 추세라고한다. 

 

시간이 남을경우

4. 생활코딩의 Redux- https://opentutorials.org/course/4901

까지가 목표이다.

 

아래는 위의 1~4를 공부 후 정리한 내용을 쓰려한다.

 

------------------------------------------------------------ 공부시작 -------------------------------------------------------------

1. 생활코딩의 React 

리액트가 아예 처음이라 걱정이 많이된다.

 

리액트란

- 페이스북에서 만든 자바스크립트 라이브러리이고 사용자 정의 태그를 만들 수 있다.

- 복잡한 코드를 component화 할수 있음. (재사용성이 높음)

 

개발환경 - node.js를 받고

터미널에 아래처럼 넣어준다.

제일뒤의 . 은 현재 디렉토리에 설치한다는 뜻이다.

npx create-react-app .

리액트를 설치하면서 겪은 난항

1. 다른 html, css, js가 있는 폴더에 설치하려 했더니, contains files that could conflict 파일 컨플릭트가 난다고 안됌

2. 폴더이름을 react로 하고 하려 했더니, 이름이 설치하려는 거랑 같아서 안된다함

3. 결국 react-app 이라고 생활코딩과 같게 해서 설치를 성공

 

설치 후 안내받은 명령어

npm start 
    Starts the development server.

  npm run build
    Bundles the app into static files for production.

  npm test
    Starts the test runner.

  npm run eject
    Removes this tool and copies build dependencies, configuration files
    and scripts into the app directory. If you do this, you can’t go back!

npm start로 시작을 하고나면

3000포트에 샘플 리액트 앱을 띄워준다.

(만약 3000포트가 사용중이라면 터미널에 뭐라뭐라 뜨는데 y를 눌러서 포트를 다른걸로 변경해주자)

3000포트에 열린 샘플 리액트 앱

vscode를보면 src폴더에 index.js가 있는데,

이 파일이 react가 실행하는 파일이다.

아래와 같은 코드가 index.js에 있는데

대충봐도 App.js를 import 해와서

<App /> 에서 컴포넌트처럼 꺼내 쓰는거 같다.

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';

const root = ReactDOM.createRoot(document.getElementById('root')); // root 태그는 public 폴더안에 index.html 에 있다
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

reportWebVitals();

여기까지의 나의 이해는

index.js가 다른 컴포넌트js들을 import 해와서 쓸 수 있는데,

다른 컴포넌트js들도 각각 css가 붙어있다. - App.css 등등

 

여기까지가 React의 수정이었고 배포를 할경우는

터미널에 npm run build 라고 입력할 경우,

우측에 build 폴더가 생긴다.

그러면 이제 이 빌드폴더에 있는 index.html을 가지고 서비스를 배포하면 되는것 이다.

터미널에 npx serve -s build 라고 입력한다.

serve는 웹서버이고, -s의 옵션을 주면 사용자가 어떠한 경로로 들어와도 index.html을 서비스 해주게 된다

build는 build폴더안의 index.html을 찾는다는 의미이다.

serve는 node.js로 만들어진 어플리케이션 이기때문에 npx로 실행

 

App.js 에서

컴포넌트를 만들어보았다.

생각보다 매우 쉬워서 당황했다.. 이고잉님이 설명을 잘하시는거라고 생각된다..

import logo from './logo.svg';
import './App.css';

function Header(){ // 컴포넌트를 만들때는 무조건*** 대문자로 시작
    return <header>
    <h1><a href='/'>컴포넌트</a></h1>
  </header>
} 

function App() {
  return (
    <div className="App">
      <Header></Header> {/* 위의 컴포넌트를 불러왔다. */}
      <Header></Header> {/* 위의 컴포넌트를 불러왔다. */}
      <Header></Header> {/* 위의 컴포넌트를 불러왔다. */}
      <Header></Header> {/* 위의 컴포넌트를 불러왔다. */}
    </div>
  );
}

export default App;

 

Props (속성) 정리

import logo from './logo.svg';
import './App.css';

function Header(props){ // 함수에 첫번째 파라미터로 props를 준다
    return <header>
    <h1><a href='/'>{props.title}</a></h1>  {/* 파라미터로 아래서 속성을 꺼내 올수 있다. */}
  </header>
} 

function Nav(props){
  const lis = []

  for(let i=0; i<props.topics.length; i++){ // app() 에서 만든 객체를 for문으로 돌려서 객체의 데이터를 꺼낸다
    let t = props.topics[i];
    lis.push(<li key={t.id}><a href={'/read/'+t.id}>{t.title}</a></li>) // 빈 array에 push 해줄건데, list의 각각 데이터들은 key값을 반드시 가지고 있어야한다고 한다(key 값은 유니크해야함).
  }
  
  return <nav>
    <ol>
      {lis}{/* 배열을 여기서 실행 */}
    </ol>
  </nav>
}

function Article(props){
  return <article>
    <h2>{props.title}</h2>
    {props.body}
  </article>
}

function App() {
  const topics = [
    {id:1, title:'html', body:'html is ...'},
    {id:2, title:'css', body:'css is ...'},
    {id:3, title:'javascript', body:'javascript is ...'}
  ] 
  return (
    <div>
      <Header title="WEB"></Header>
      <Nav topics={topics}></Nav>
      <Article title="Welcome" body="Hello, WEB"></Article>
    </div>
  );
}
 
export default App;

 

Event 정리

import logo from './logo.svg';
import './App.css';
 
function Header(props){
  return <header>
    <h1><a href="/" onClick={(event)=>{ // 이벤트 작성
      event.preventDefault(); // 기본동작-새로고침 방지
      props.onChangeMode(); // 속성 실행
    }}>{props.title}</a></h1>
  </header>
}
function App() {
  const topics = [
    {id:1, title:'html', body:'html is ...'},
    {id:2, title:'css', body:'css is ...'},
    {id:3, title:'javascript', body:'javascript is ...'}
  ] 
  return (
    <div>
      <Header title="WEB" onChangeMode={()=>{ // onChangeMode 라는 속성에 함수를 전달
        alert('Header'); // 로직
      }}></Header>
    </div>
  );
}
 
export default App;

 

State 정리

"prop과 state 모두 이 값이 변경되면 새로운 리턴값을 바꾸어서 UI를 바꿉니다. 차이점은 prop은 컴포넌트를 사용하는 외부자를 위한 데이터고, state는 컴포넌트를 만드는 내부자를 위한 데이터라는 것입니다."

import './App.css';
import {useState} from 'react'; // state를 사용하려면 imnport 해야한다.
 
function Article(props){ // 파라미터로 속성을 사용 가능
  return <article>
    <h2>{props.title}</h2>
    {props.body}
  </article>
}

function Header(props){
  return <header>
    <h1><a href="/" onClick={(event)=>{ 
      event.preventDefault();
      props.onChangeMode(); // onChangeMode라는 속성을 함수로 받아와서 실행
    }}>{props.title}</a></h1>
  </header>
}

function Nav(props){
  const lis = []
  for(let i=0; i<props.topics.length; i++){
    let t = props.topics[i];
    lis.push(<li key={t.id}>
      <a id={t.id} href={'/read/'+t.id} onClick={event=>{
        event.preventDefault();
        props.onChangeMode(Number(event.target.id)); // id가 t.id에서 오는건데 태그의 속성으로 넘길경우 숫자가 문자가 된다. 그래서 Number로 converting
      }}>{t.title}</a>
    </li>)
  }
  return <nav>
    <ol>
      {lis}
    </ol>
  </nav>
}

function App() {
  const [mode, setMode] = useState('WELCOME'); // mode = useState('WELCOME')[0] - 상태를 읽을수있다. setMode = useState('WELCOME')[1] - 상태를 변경할수있다.
  const [id, setId] = useState(null); // id = useState(null)[0] - 상태를 읽을수있다. setId = useState(null)[1] - 상태를 변경할수있다.
  const topics = [
    {id:1, title:'html', body:'html is ...'},
    {id:2, title:'css', body:'css is ...'},
    {id:3, title:'javascript', body:'javascript is ...'}
  ] 
  let content = null;
  if(mode === 'WELCOME'){  // mode - 상태를 읽어온다
    content = <Article title="Welcome" body="Hello, WEB"></Article>
  } else if(mode === 'READ'){ // mode - 상태를 읽어온다
    let title, body = null;
    for(let i=0; i<topics.length; i++){
      console.log(topics[i].id, id); // id - 상태를 읽어온다
      if(topics[i].id === id){ // id - 상태를 읽어온다
        title = topics[i].title;
        body = topics[i].body;
      }
    }
    content = <Article title={title} body={body}></Article>
  }
  return (
    <div className='App-header'>
      <Header title="WEB" onChangeMode={()=>{
        setMode('WELCOME'); // 값을 변경해야하는 경우이므로, setMode를 사용
      }}></Header>

      <Nav topics={topics} onChangeMode={(_id)=>{
        setMode('READ'); // 값을 변경해야하는 경우이므로, setMode를 사용
        setId(_id);
        }}></Nav>

      <div className='App-link'> 
        {content} 
      </div>
    </div>
  );
}
 
export default App;

 

나홀로 여기까지 재 정리 및 다시 코딩

여기까지 막힐경우 이 아래 코드를 보면서 다시 해보면 될듯하다.

 

순서1. App()안에 그냥 html 만들듯이 만들기

2. 컴포넌트처럼 꺼내기

3. props를 통해서 필요한 정보를 파라미터로 보내서 꺼내기

4. css 입히기

import logo from './logo.svg';
import './App.css';

function Header(props) { // 컴포넌트를 만들때는 무조건 대문자 시작, 파라미터로 속성받기
  return <header>
    <h1>
      {/* 이렇게 className을 이용해서 import해온 css 이용가능 */}
      <a className='App-header-text' href='/'>{props.title}</a> 
    </h1>
  </header>
}

function Nav(props){
  const lis = [];

  // 파라미터를 통해서 topics 속성을 가져온다
  for(let i=0; i<props.topics.length; ++i){
    // 각 인덱스에 들어있는 객체들을 t에 보관
    let t = props.topics[i];
    //객체들을 보관한 t에서 필요한 정보들을 꺼내옴, list는 유니크한 id값이 있어야한다
    lis.push(<li key={t.id} className='App-nav-text-list-first'>{t.title}</li>)
  }

  return <nav className='App-nav-text'>
    <ol>
      {lis}
    </ol>
  </nav>
}

function Content(props){
  return <content className='App-content-text'>
    <h3>{props.title}</h3>
    <p>{props.first_p}</p>
    <p>{props.second_p}</p>
  </content>
}

function App() {
  // li 태그에 넣을 자료들을 객체로 만들어서 배열로 관리, 이 배열을 속성을 통해 위로 넘겨줄거임
  const ob_nav = [
    {id:1, title:'List', content:'first list'},
    {id:2, title:'List', content:'second list'},
    {id:3, title:'List', content:'third list'},
  ]
    
  return (
    <div className='App-header'>  {/* 여기에도 css 추가 가능 */}
      <Header title="First Solo Work with React"></Header>
      <Nav topics={ob_nav}></Nav> {/*아까 만든 배열을 topics 속성으로 만듬 */}
      <Content title='WOW!' first_p='This is an awesome work!' second_p='First Step'></Content>
    </div>
  );
}
 
export default App;

 

2. 종합반 2주차

Jquery 테스트

input 값 받아오기, 받아온값에 includes로 체크, split으로 나누기

append()하기, empty() 하기

<script>
        function q1() {
            // 1. input-q1의 입력값을 가져온다. $('# .... ').val() 이렇게!
          let answer = $('#input-q1').val();
            // 2. 만약 입력값이 빈칸이면 if(입력값=='')
          if(answer === ''){
            // 3. alert('입력하세요!') 띄우기
            alert('입력하세요!')
          }else{
            // 4. alert(입력값) 띄우기
              alert(answer)
          }
        }

        function q2() {
            // 1. input-q2 값을 가져온다.
           let answer = $('#input-q2').val();
            // 2. 만약 가져온 값에 @가 있으면 (includes 이용하기 - 구글링!)
          if(answer.includes('@')){
            // 3. info@gmail.com -> gmail 만 추출해서 ( .split('@') 을 이용하자!)
            let domainWithDot = answer.split('@')[1];
            let domain = domainWithDot.split('.')[0];
            // 4. alert(도메인 값);으로 띄우기
            alert(domain);
          }else{
            // 5. 만약 이메일이 아니면 '이메일이 아닙니다.' 라는 얼럿 띄우기
            alert('이메일이 아닙니다.')
          }
        }

        function q3() {
            // 1. input-q3 값을 가져온다. let txt = ... q1, q2에서 했던 걸 참고!
          let answer = $('#input-q3').val();
            // 2. 가져온 값을 이용해 names-q3에 붙일 태그를 만든다. (let temp_html = `<li>${txt}</li>`) 요렇게!
          let temp_html = `<li>${answer}</li>`
            // 3. 만들어둔 temp_html을 names-q3에 붙인다.(jQuery의 $('...').append(temp_html)을 이용하면 굿!)
          $('#names-q3').append(temp_html);
        }

        function q3_remove() {
            // 1. names-q3의 내부 태그를 모두 비운다.(jQuery의 $('....').empty()를 이용하면 굿!)
          $('#names-q3').empty();
        }
    </script>

2주차 팬명록

온도만 추가하라했지만, api에 있는 모든 정보를 추가해 보았다.

내친김에.. 사진도 변경..

3. 종합반 3주차

3주차 숙제는 지니뮤직을 크롤링 하는거다.

크롤링만 하는건 뭔가 쉬운거 같아서, 크롤링된 데이터를 mongo DB에 저장해 보았다.

# 크롤링 - requests, bs4 패키지
import requests
from bs4 import BeautifulSoup

# mongoDB - pymongo, dnspython 패키지
from pymongo import MongoClient

# sparta@cluster0 (내 db폴더이름@내클러스터이름)
client = MongoClient('mongodb+srv://test:sparta@cluster0.m7jzf.mongodb.net/Cluster0?retryWrites=true&w=majority')
db = client.dbsparta

# 타겟 URL을 읽어서 HTML를 받아오고,
headers = {'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'}
data = requests.get('https://www.genie.co.kr/chart/top200?ditc=M&rtm=N&ymd=20210701',headers=headers)

# soup이라는 변수에 "파싱 용이해진 html"이 담긴 상태가 됨
# 이제 코딩을 통해 필요한 부분을 추출하면 된다.
soup = BeautifulSoup(data.text, 'html.parser')

#크롤링중에 공통되는부분: body-content > div.newest-list > div > table > tbody > tr 을 하나로 묶음
trs = soup.select('#body-content > div.newest-list > div > table > tbody > tr')

# db를 일단 새로 날리고 시작 - db에 계속 stack처럼 쌓이지 않음
db.genieMusic.drop()

# for loop 돌면서 필요한 데이터 빼온다음 db에 저장
for tr in trs:
    title = tr.select_one('td.info > a.title.ellipsis').text.strip() #strip() - 공백 지워줌
    rank = tr.select_one('td.number').text[0:2].strip() # 0~2까지의 텍스트만 가져옴
    artist = tr.select_one('td.info > a.artist.ellipsis').text
    print(rank, artist, title) # db에 넣을 자료 print
    doc = {
        'title': title,
        'rank': rank,
        'artist': artist
    }
    db.genieMusic.insert_one(doc) # db에 insert - save

#db에서 읽어오기(이무진의 노래 다 가져오기)
leemujin_musics = list(db.genieMusic.find({'artist':'이무진'},{'_id':False}))
print(leemujin_musics)

#db에서 업데이트(aespa next level을 this level로 변경)
db.genieMusic.update_one({'title':'Next Level'},{'$set':{'title':'This Level'}})
aespa_music = db.genieMusic.find_one({'artist':'aespa'},{'_id':False})
print(aespa_music)

#db에서 rank가 1위인거 지우기
db.genieMusic.delete_one({'rank':'1'})

 

4. 종합반 4주차

숙제가 flask를 이용해서 post, get을 하는거다

comment를 client에서 server로 보내온걸 MongoDB에 post 하고

페이지가 새로고침될때는 MongoDB에서 server로 데이터를 가져온걸 다시 client로 보내서 보여주는 방식이다.

결과는 아래와 같다.

 

5. 종합반 5주차

버킷리스트 - SAVE, DONE 기능만 구현하도록 되있길래 CANCEL, DELETE까지 해봤다

깃헙 커밋: https://github.com/kevinkim910408/-Web-BucketList/commits/main

중간에 .count() 때문에 오류가 있었는데, 오류페이지에 정리해뒀다. 

https://devkevin0408.tistory.com/76?category=1046905

 

지금부터가 이제 서버에 내 fan site를 올리는 방법이다.

AWS에서 EC2서버를 구매했다는 가정하에

나는 window 유저라서 git bash를 이용해서 접속해야한다.

git bash를 열고,

ssh -i 받은키페어를끌어다놓기 ubuntu@AWS에적힌내아이피

 

나의 경우는 이렇게 나온다.

$ ssh -i/c/Users/kevin/Desktop/WEB/keypairname.pem ubuntu@xx.xxx.xxx.xxx

 

명령어 정리
명령내릴때 python3라고 안치고, python이라고 치고 명령 내리기 
# python3 -> python
sudo update-alternatives --install /usr/bin/python python /usr/bin/python3 10

 패키지를 설치할때 필요한거. (flast, pymongo 등)
# pip3 -> pip
sudo apt-get update
sudo apt-get install -y python3-pip
sudo update-alternatives --install /usr/bin/pip pip /usr/bin/pip3 1

 로컬호스트:5000에서 5000을 떼는 명령어 - 80 -j REDIRECT --to-port 5000// 80으로 들어오는애를 5000으로 바꿔줘라
# port forwarding
sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 5000

############# 명령어################
ls - 현재폴더 확인
cd 폴더명 - 폴더로 진입
cd .. - 폴더 밖으로 나가기
mkdir: 내 위치 아래에 폴더를 하나 만든다.
python app.py - 앱 실행
nohup python app.py & - 서버 깃배시로 안키고도 계속 켜두기

계속 켜둔 서버 강제 종료하기
ps -ef | grep 'python app.py' 라고 치면 내 pid가 나옴 켜져있는거
kill -9 내pid 쳐주면 종료

 

파일질라

new Site로 하나 만들고, 프로토콜은 STFP로, 호스트는 AWS에서 가져온거 가져오고 포트는 22(고정이라고한다)

키파일은 AWS에서 받은거 넣어줘야하는데, 그냥 들어가면 없다, 찾을 파일 종류를 PEM file로

1. 우리가 만든 폴더로 진입

2. 내가 필요한 데이터 drag해서 넘기기 - static, templates, app.py

3. 성공이라고 뜨는지 확인하고

4. AWS에서 준 퍼블릭 IPv4 주소로 들어가서 확인하기

 

 

6. 토이프로젝트 기획, 설명, Flowchart

토이프로젝트 1 - 날씨를 알려줘 이다.

OPEN SOURCE 날씨 API를 가져와서 필요한 정보를 DB에 저장해서 

그 도시의 날씨정보를 보는 웹사이트를 만드는 목표이다.

스파르타에서 배운 기술을 그대로 사용할 예정이다.

좌) 토이프로젝트 기획, 우) 토이프로젝트에서 현재 공부하는 점, 추후에 배울수 있는점
토이프로젝트의 FLOWCHART

7. 생활코딩의 Redux

Redux

- 예측가능한 자바스크립트 상태의 저장소

 

Redux의 핵심은 store이다. - 정보가 저장되는곳

store안에는 state라고 실제 정보가 저장되는 곳이있다.

그런데 실제 정보에 접근하기 위해서는 바로는 못하고 reducer를 통해야만 접근가능하다.

그다음에 상황에따라서 dispatch, subscribe, getState를 통해서 외부에 접근가능하다.

외부에는 render라는 친구가 이제 데이터를 받아서 그려낸다.

*getState - state값을 가져와서 render에게 전해줌

*subscribe - render값을 등록한다 라는 느낌, state가 바뀔때 알아서 render함수를 호출해서 바꿔줌

*dispatch - 무언가 action이 취해지면, dispatch에 전달이되고,

얘는 reducer한테 현재의 state값 그리고 action data를 전달한다.

그리고 reducer가 새로운값을 state한테 전해준다.

 

 

Redux는 npm을 통해서 설치해도 되고 cdn을 가져와도 된다.cdn

<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.0.1/redux.js"></script>

 

store 만들면 내부적인 값으로 state가 생성됨.

state 값을 가져오려면 getState가 필요.

reducer 통해서 state 값을 만들어야 한다.


기존 state 값이 undefined일 경우, 
초기화를 위해서 최초로 실행되는 reducer 호출이므로,


reducer 호출 시 원하는 초기값을 return에 넣으면 초기값이 지정됨.

<script>
        // reducer 함수 - state와 action을 받아온다
        function reducer(state, action){
            if(state===undefined){ // state가 undefined면, 초기값을 설정하라는거다
                return {color:'yellow'};
            }
        }

        let store = Redux.createStore(reducer);

        function red() {
            let state = store.getState(); // 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="
            document.querySelector('#component_red').style.backgroundColor = 'red';
            ">
        </div>
    `;
        }
        red();

       
    </script>

 

Reducer와 action으로 새로운 state 만들기

Reducer 함수가 하는 역활: store의 state값을 변경해준다. 

action의 값과 이전의 state값을 이용해서 새로운 state값을 return 해준다.

원본을 바꾸는게 아니라, 이전의 값을 복사해야지만 redux 효율을 최대한 사용가능.

<script>
        // reducer 함수 - 이전의 state와 action을 받아온다
        function reducer(state, action){
            if(state===undefined){ // state가 undefined면, 초기값을 설정하라는거다
                return {color:'yellow'};
            }
            
            let newState;
            if(action.type ==='CHANGE_COLOR'){
                newState = Object.assign({}, state, {color:'red'}); // 빈객체, 빈객체에 복사될 state, state에 줄 값 
            }
            return newState; // 다음의 action 을 return - state를 복제하고 복제한 state에 color를 red로 준 값을 return
        }

        let store = Redux.createStore(reducer);

        function red() {
            let state = store.getState(); // 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>
    `;
        }
        red();

       
    </script>

 

subscribe에 render 등록하기

   <script>
        // reducer 함수 - 이전의 state와 action을 받아온다
        function reducer(state, action){
            if(state===undefined){ // state가 undefined면, 초기값을 설정하라는거다
                return {color:'yellow'};
            }
            
            let newState;
            if(action.type ==='CHANGE_COLOR'){
                newState = Object.assign({}, state, {color: action.color}); // 빈객체, 빈객체에 복사될 state, state에 줄 값 
            }
            return newState; // 다음의 action 을 return - state를 복제하고 복제한 state에 color를 red로 준 값을 return
        }

        let store = Redux.createStore(reducer);

        function red() {
            let state = store.getState(); // 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>
    `;
        }
        store.subscribe(red); // subscribe에 red 함수를 등록해놓는다 - render를 등록해서 state가 바뀔때마다 알아서 바뀜
        red();

        // 새로운 코드를 등록해도 관리가 쉽다. - store라는 한 곳에서 상태를 변경하기만하면, 나머지 코드는 알아서 자기 할일만 하므로 유지관리도 쉽다.
        function blue() {
            let state = store.getState(); // getState로 데이터를 가져올 수 있음
            document.querySelector('#blue').innerHTML = `
        <div class="container" id="component_red" 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); // subscribe에 red 함수를 등록해놓는다 - render를 등록해서 state가 바뀔때마다 알아서 바뀜
        blue();

    </script>

 

React와 Redux로 CRUD를 완벽하게 하는 강의까지 하기에는 시간이 없었고, 

오늘은 React와 Redux 가 대충 무엇인지만 알고 넘어가게 되었다.

아직 정확하게 와닿지는 않지만,

토이프로젝트까지 끝나고 다시 마무리를 지어야겠다.

 

 

728x90