<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>City At Night</title>
    <link>https://wuny-dev.tistory.com/</link>
    <description>베이스가 중요하더라
</description>
    <language>ko</language>
    <pubDate>Fri, 14 Aug 2026 00:56:33 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>Wuny</managingEditor>
    <image>
      <title>City At Night</title>
      <url>https://tistory1.daumcdn.net/tistory/4172897/attach/829456f369a844cdaaa7cde32ac8f68d</url>
      <link>https://wuny-dev.tistory.com</link>
    </image>
    <item>
      <title>[MernStack] Blog 만들기 18. [React] 로그인Modal 만들기.</title>
      <link>https://wuny-dev.tistory.com/48</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;한 5~6개월만에 다시 블로그 포스팅을 시작한다. ㅜㅜ&lt;br /&gt;이직이라는 변명으로 포스팅을 못했다..&amp;nbsp;&lt;br /&gt;이직은 성공했고 연봉폭은 높아졌지만 ... 정신과 마음은 더 힘들어졌다.&lt;br /&gt;연봉은 만족스럽지만 그 외 만족스럽지 못해 스트레스다&lt;br /&gt;개발보단.. 사무업무와 운영업무가 더 많은 업이다...&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SM회사다 보니...그렇다...&lt;br /&gt;개발회사로 이직을 준비하련다...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(이번편 포스팅 작성완료 시간 : 2022.01.24 00:16)&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저, 로그인 기능을 만들기전 로그인Modal창 먼저 구현해보겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. componets/auth/LoginModal.js&amp;nbsp; 생성&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1642949208469&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const LoginModal = () =&amp;gt; {
  return (
    &amp;lt;div&amp;gt;
      &amp;lt;NavLink onClick={''} href=&quot;#&quot;&amp;gt;
        Login
      &amp;lt;/NavLink&amp;gt;
      &amp;lt;Modal isOpen={'modal'} toggle={''}&amp;gt;
        &amp;lt;ModalHeader toggle={''}&amp;gt;Login&amp;lt;/ModalHeader&amp;gt;
        &amp;lt;ModalBody&amp;gt;
          &amp;lt;Form onSubmit={''}&amp;gt;
            &amp;lt;FormGroup&amp;gt;
              &amp;lt;Label&amp;gt;Email&amp;lt;/Label&amp;gt;
              &amp;lt;Input /&amp;gt;
              &amp;lt;Label&amp;gt;Password&amp;lt;/Label&amp;gt;
              &amp;lt;Input /&amp;gt;
              &amp;lt;Button color=&quot;dark&quot;&amp;gt;Login&amp;lt;/Button&amp;gt;
            &amp;lt;/FormGroup&amp;gt;
          &amp;lt;/Form&amp;gt;
        &amp;lt;/ModalBody&amp;gt;
      &amp;lt;/Modal&amp;gt;
    &amp;lt;/div&amp;gt;
  );
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #222426;&quot;&gt;LoginModal창 구성도는 이렇다.&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1642949560321&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;Modal&amp;gt;
     &amp;lt;ModalHeader&amp;gt;&amp;lt;/ModalHeader&amp;gt;
     &amp;lt;ModalBody&amp;gt;
     	&amp;lt;FormGroup&amp;gt;
        	&amp;lt;Input/&amp;gt;  //Email
            &amp;lt;Input/&amp;gt; //Password
        &amp;lt;/FormGroup&amp;gt;
     &amp;lt;/ModalBody&amp;gt;
&amp;lt;Modal&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #222426;&quot;&gt;Modal이라는 큰 틀안에 Header와 Body가 있다.&lt;br /&gt;Body안에 Email과 Password를 적는 Input이 있는데 이 Input들을 FormGroup으로 감싼다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1642949867448&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import {
  FormGroup,
  Modal,
  ModalBody,
  ModalHeader,
  NavLink,
  Label,
  Button,
  Form,
  Input,
} from 'reactstrap';&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #222426;&quot;&gt;Modal창 작성할때&amp;nbsp; Import할 reactstrap 모듈들이다.&lt;br /&gt;굳이 먼저 Import할 필요는 없고 태그를 작성하다보면 자동으로 작성되는데&lt;br /&gt;나는 Button, Label들 몇개는 자동으로 import가 안되어 수동으로 적어줬다.&lt;br /&gt;(에러코드에 다 알려주니 그때그때 불러주면 된다.)&lt;/span&gt;&lt;span style=&quot;color: #222426;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #222426;&quot;&gt;마지막으로 export해주어 모듈화 시킨다.&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1642950105918&quot; class=&quot;routeros&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export default LoginModal;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #222426;&quot;&gt;&lt;b&gt;2. Components/AppNabar.js&lt;br /&gt;&lt;/b&gt;먼저 페이지가 열리면 자동으로 LoginModal창 나오게끔 테스트를 할 것이다.&lt;br /&gt;기존 코드를 수정한다.&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1642950390184&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const AppNavbar = () =&amp;gt; {
  return (
    &amp;lt;Fragment&amp;gt;
      &amp;lt;Navbar color=&quot;dark&quot; dark expand=&quot;lg&quot; className=&quot;sticky-top&quot;&amp;gt;
        &amp;lt;Container&amp;gt;
          &amp;lt;Link to=&quot;/&quot; className=&quot;text-white text-decoration-none&quot;&amp;gt;
            Side Project's Blog(Wuny)
          &amp;lt;/Link&amp;gt;
          &amp;lt;NavbarToggler /&amp;gt;
          &amp;lt;Collapse isOpen={true} navbar&amp;gt;
            &amp;lt;Nav className=&quot;ml-auto d-flex justify-content-around&quot; navbar&amp;gt;
              {false ? (
                &amp;lt;h1 className=&quot;text-white&quot;&amp;gt;authLink&amp;lt;/h1&amp;gt;
              ) : (
                &amp;lt;LoginModal /&amp;gt;   &amp;lt;- 수정한 코드
              )}
            &amp;lt;/Nav&amp;gt;
          &amp;lt;/Collapse&amp;gt;
        &amp;lt;/Container&amp;gt;
      &amp;lt;/Navbar&amp;gt;
    &amp;lt;/Fragment&amp;gt;
  );
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;기존 &lt;span style=&quot;letter-spacing: 0px;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;className&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;&quot;text-white&quot;&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;authLink&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;&amp;gt; 를 삭제하고&amp;nbsp;&lt;br /&gt;1번에서 작성한 &amp;lt;LoginModal/&amp;gt;을 넣어준다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;3. React Server 실행&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1914&quot; data-origin-height=&quot;363&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ceMTMU/btrrqZnL130/fod5e76DOX3zY82TWr5NlK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ceMTMU/btrrqZnL130/fod5e76DOX3zY82TWr5NlK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ceMTMU/btrrqZnL130/fod5e76DOX3zY82TWr5NlK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FceMTMU%2FbtrrqZnL130%2Ffod5e76DOX3zY82TWr5NlK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1914&quot; height=&quot;363&quot; data-origin-width=&quot;1914&quot; data-origin-height=&quot;363&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #222426;&quot;&gt;&amp;nbsp;React 서버 실행한 모습이다. 기능은 구현 안했기에 로그인 버튼을 눌러도 아무 반응이 없다.&lt;/span&gt;&lt;span style=&quot;color: #222426;&quot;&gt;이 전 포스팅까진 Linux에서&amp;nbsp; 개발했지만 이번 포스터부턴 Windows10기반이다.&lt;br /&gt;&lt;br /&gt;다음 포스팅에선 이제 기능을 구현해보겠다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #222426;&quot;&gt;Linux에서 VScode 사용시 한글 받침 안써지는 이슈 해결법.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #222426;&quot;&gt;File -&amp;gt; Preferences -&amp;gt; Settings -&amp;gt; Text Editor -&amp;gt; Font -&amp;gt; Font Family 에서 'Droid Sans Fallback' 을 제거한다&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>MernStack</category>
      <category>frontend</category>
      <category>javascript</category>
      <category>MernStack</category>
      <category>node.js</category>
      <category>react</category>
      <category>노드</category>
      <category>블로그만들기</category>
      <author>Wuny</author>
      <guid isPermaLink="true">https://wuny-dev.tistory.com/48</guid>
      <comments>https://wuny-dev.tistory.com/48#entry48comment</comments>
      <pubDate>Wed, 30 Jun 2021 01:43:47 +0900</pubDate>
    </item>
    <item>
      <title>[MernStack] Blog 만들기 17. [React] Login API 만들기.</title>
      <link>https://wuny-dev.tistory.com/47</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;b&gt;1. axios 다운로드 및 authSaga 작성&lt;/b&gt;&lt;br /&gt;로그인은 서버와 통신을 하는 작업이므로 서버와 통신을 도와주는 'axios' 라는 라이브러리를 다운로드한다.&lt;/p&gt;
&lt;pre id=&quot;code_1624294414797&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$&amp;gt; npm i axios &lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;client 루트에서 다운로드하는걸 까먹지 말자.&lt;br /&gt;redux/sagas/authSaga.js생성한다.&lt;br /&gt;&lt;br /&gt;[authSaga.js]&lt;/p&gt;
&lt;pre id=&quot;code_1624294298649&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import axios from 'axios';

//Login Api만들기
const loginUserAPI = (loginData) =&amp;gt; {
    console.log(loginData, &quot;loginData&quot;) //loginData가 어떤값으로 들어오는지 console.log를 찍어 확인한다
    const config = {
        headers: {
            &quot;Content-Type&quot; : &quot;application/json&quot;
        }
    }
    return axios.post('api/auth', loginData, config)
}

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;loginUserAPI라는 함수를 만들고 loginData를 파라미터값으로 받는다.&lt;br /&gt;headers: {~} 이 부분은 우리가 서버작업을 할때 포스트맨드로 테스트할때 그 형식이다.(기억이 가물가물)&lt;br /&gt;로그인은 서버로 데이터를 전송하기때문에&amp;nbsp;&lt;br /&gt;return axios.post 를 적어주고 3개의 정보를 보낸다. (api/auth,loginData,config)&lt;br /&gt;1. 'api/auth' 인증정보의 주소 (현재는 localhost:3000)&lt;br /&gt;2. loginData&amp;nbsp;&lt;br /&gt;3. config 데이터의 형식.(?) // 사실 이건 잘 감이 안온다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2.로그인에 관한 generator함수 작성&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;[authSaga.js]&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1624295870453&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { all, put, takeEvery,call,fork } from 'redux-saga/effects';
import { LOGIN_FAILURE, LOGIN_REQUEST, LOGIN_SUCCESS } from &quot;../types&quot;;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다음 all,put,takeEvery,call,fork를&amp;nbsp; 불러와주다.&lt;br /&gt;(all,put,takeEvery,call,fork 에 대한 설명_ &lt;a href=&quot;https://simsimjae.medium.com/%EB%A6%AC%EB%8D%95%EC%8A%A4-%EC%82%AC%EA%B0%80-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0-8e573de9786e&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;클릭&lt;/a&gt;)&amp;nbsp;&lt;br /&gt;&lt;br /&gt;저번 포스팅에서 만들어놓은 로그인에 관한 처리 type도 import 해준다.&lt;/p&gt;
&lt;pre id=&quot;code_1624295139017&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function* loginUser(action) { 
    try{
        const result = yield call(loginUserAPI,action.payload) //action.payload??가 뭐지?
        console.log(result)
        yield put({
            type : LOGIN_SUCCESS,
            payload: result.data
        })
    }catch(e){
        yield put({
            type: LOGIN_FAILURE,
            payload: e.response
        })
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;function* 은 generator함수인데&amp;nbsp; yeild함수를 사용할 수 있다.&lt;br /&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Statements/function*&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Statements/function*&lt;/a&gt;&lt;br /&gt;yeild를 사용하여 여러개의 값을 순서에따라 반환 할 수 있다.&lt;br /&gt;&lt;br /&gt;try문 안에는 로그인에 성공했을때 catch문 안에는 로그인에 실패했을때 처리를 해준다.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 로그인 상황을 처리하는 함수 작성&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;[authSaga.js]&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1624295269725&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function* watchLoginUser(){
    yield takeEvery(LOGIN_REQUEST, loginUser)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;watchLoginUser 라는제네레이터 함수를 작성한다.&amp;nbsp;&lt;br /&gt;이 함수는 계속 로그인 요청을 기다리다 takeEvery 메서드를 사용하여 &lt;br /&gt;LOGIN_REQUEST가 들어오면 loginUser를 실행시킨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;지금까지 작성했던 authSaga.js는&amp;nbsp; 리덕스 패턴으로 많이 사용된다.&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&amp;lt;지금까지 패턴&amp;gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;1.&amp;nbsp; watchLoginUser함수가 LOGIN_REQUEST를 받고 loginUser함수로 던져준다.&lt;/b&gt;&lt;br /&gt;&lt;b&gt;2.&amp;nbsp; loginUser함수는 &amp;nbsp;LOGIN_REQUEST를 받고 성공 또는 실패에 대한 처리를 한다.&lt;/b&gt;&lt;br /&gt;&lt;b&gt;3.&amp;nbsp; 성공일시 loginUserAPI 함수로 던져준다.&lt;/b&gt;&lt;br /&gt;&lt;b&gt;4.&amp;nbsp; loginUserAPI는 서버로&amp;nbsp; 로그인한 정보를 뿌려준다.&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;br /&gt;4. 모듈로 내보내기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[authSaga.js]&lt;/p&gt;
&lt;pre id=&quot;code_1624295937742&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export default function* authSaga() {
    yield all([
        fork(watchLoginUser) //fork 함수
    ])
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;fork함수를 사용하여 모듈화한다.&lt;br /&gt;//fork함수가 뭔지 봐보자.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;5. sagas/index.js함수 작성&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[sagas/index.js]&lt;/p&gt;
&lt;pre id=&quot;code_1624982791413&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import {all,fork} from 'redux-saga/effects'
import axios from 'axios'

import authSaga from './authSaga'
import dotenv from 'dotenv'
dotenv.config()

axios.defaults.baseURL = process.env.REACT_APP_BASIC_SERVER_URL



export default function* rootSaga(){ //제네레이터 함수 .. 여러값을 반환할수 있음 .
    yield all([
        fork(authSaga)
    ]);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;8번째 줄 axios.defaults.baseURL = process.env.REACT_APP_BASIC_SERVER_URL&lt;br /&gt;이 부분은 .env로 작성하였다.&lt;br /&gt;만약 .env로 작성 안하고 바로 서버 주소를 노출하게 된다면&lt;br /&gt;axios.defaults.baseURL = http://localhost:7000 처럼 작성할 수 있다.&lt;br /&gt;&lt;/span&gt;(지금은 로컬주소라 상관없지만 추후 배포시 문제가 생길 수 있다)&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;주소가 적나라게 보이면 보안에 취약할 수 있으니 닷엔브파일을 만들어 작성한다.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;[client/.env]&lt;/p&gt;
&lt;pre id=&quot;code_1624982845796&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;REACT_APP_BASIC_SERVER_URL = &quot;http://localhost:7000&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;react로 만든 앱은 반드시 REACT_APP으로 시작한 다음 이름을 지어야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[authSaga.js]&amp;nbsp; 전체 코드&lt;/p&gt;
&lt;pre id=&quot;code_1624983186158&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import axios from 'axios';
import { all, put, takeEvery,call,fork } from 'redux-saga/effects';
import { LOGIN_FAILURE, LOGIN_REQUEST, LOGIN_SUCCESS } from &quot;../types&quot;;

//Login Api만들기
const loginUserAPI = (loginData) =&amp;gt; {
    console.log(loginData, &quot;loginData&quot;) //파라미터 체크
    const config = {
        headers: {
            &quot;Content-Type&quot; : &quot;application/json&quot;
        }
    }
    return axios.post('api/auth', loginData, config)
}

function* loginUser(action) { //function* 을 사용하면 yeild함수를 사용할 수 있다?
    try{
        const result = yield call(loginUserAPI,action.payload) //action.payload??가 뭐지?
        console.log(result)
        yield put({
            type : LOGIN_SUCCESS,
            payload: result.data
        })
    }catch(e){
        yield put({
            type: LOGIN_FAILURE,
            payload: e.response
        })
    }
}

function* watchLoginUser(){
    yield takeEvery(LOGIN_REQUEST, loginUser)
}
// 계속 로그인 리퀘스트를 받을 함수를 작성함
// takeEvery 계속 실행됨 
// LOGIN_REQUEST가 들어오면 loginUser를 실행시켜라

//여기까지가 리덕스 패턴으로 많이 사용됨

export default function* authSaga() {
    yield all([
        fork(watchLoginUser) //fork 함수
    ])
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>MernStack</category>
      <category>es6</category>
      <category>javascript</category>
      <category>리액트</category>
      <category>블로그만들기</category>
      <author>Wuny</author>
      <guid isPermaLink="true">https://wuny-dev.tistory.com/47</guid>
      <comments>https://wuny-dev.tistory.com/47#entry47comment</comments>
      <pubDate>Tue, 22 Jun 2021 02:23:19 +0900</pubDate>
    </item>
    <item>
      <title>[MernStack] Blog 만들기 16. [React] 로그인구현을 위한 Reducer setting</title>
      <link>https://wuny-dev.tistory.com/46</link>
      <description>&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제는 로그인 기능을 구현하겠다.&lt;br /&gt;로그인의 기능을 대충 세분화하면&lt;br /&gt;&lt;br /&gt;1. 아이디와 비밀번호등 인증을 서버로 &lt;span style=&quot;color: #009a87;&quot;&gt;요청&lt;/span&gt;하고&lt;br /&gt;2. 서버에서는 인증에대한 &lt;span style=&quot;color: #006dd7;&quot;&gt;성공&lt;/span&gt; 또는 &lt;span style=&quot;color: #ee2323;&quot;&gt;실패&lt;/span&gt;에 관한 결과를 응답해준다.&lt;br /&gt;&lt;br /&gt;이번 포스팅에선 &lt;br /&gt;클라이언트쪽에서 서버로 인증을 서버로 &lt;span style=&quot;color: #009a87;&quot;&gt;요청&lt;/span&gt;할때 상태,&lt;br /&gt;서버에서 인증에대한 &lt;span style=&quot;color: #006dd7;&quot;&gt;성공&lt;/span&gt; 응답에 대한 상태&lt;br /&gt;&amp;nbsp;또는&lt;br /&gt;서버에서 인증에대한 &lt;span style=&quot;color: #ee2323;&quot;&gt;실패&lt;/span&gt; 응답에 대한 상태 관리를&amp;nbsp; 기능적으로 구현하겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;&lt;b&gt;1.로그인상태 및 에러 클리어 Type 설정&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;redux폴더에 types.js를 생성한다.&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;[redux/types.js]&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1624031471540&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//LOGIN
export const LOGIN_REQUEST = &quot;LOGIN_REQUEST&quot;
export const LOGIN_SUCCESS = &quot;LOGIN_SUCCESS&quot;
export const LOGIN_FAILURE = &quot;LOGIN_FAILURE&quot; 

// CLEAR ERROR
export const CLEAR_ERROR_REQUEST = &quot;CLEAR_ERROR_REQUEST&quot;
export const CLEAR_ERROR_SUCCESS = &quot;CLEAR_ERROR_SUCCESS&quot;
export const CLEAR_ERROR_FAILURE = &quot;CLEAR_ERROR_FAILURE&quot; &lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;types.js에서는 로그인 요청,성공, 실패에 대한 타입과 에러를 클리어했을때의 타입을 정의한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 상황에 맞는 상태관리 작성&lt;br /&gt;&lt;br /&gt;&lt;/b&gt;[redux/reducers/authReducer.js ]&lt;/p&gt;
&lt;pre id=&quot;code_1624033029397&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const initialState = {
    token:localStorage.getItem('token'),
    isAuthenticated: null,
    isLoading: false,
    user: &quot;&quot;,
    userId:&quot;&quot;,
    userName:&quot;&quot;,
    userRole:&quot;&quot;,
    errorMsg:&quot;&quot;,
    successMsg:&quot;&quot;,
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이부분은 현재 상태 기본값을 설정하는 부분이다.&lt;br /&gt;기본값은 다 null 또는 빈값으로 넣어준다.&lt;br /&gt;store.js 에서 선언한 initialState를 사용한다.&lt;br /&gt;strore.js는 웹에 모든 상태를 담고 있는 초기값을 저장하는 부분이다.&lt;br /&gt;자세한 내용은 11번 포스팅 &lt;a href=&quot;https://wuny-dev.tistory.com/41&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;참고&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1624033674680&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const authreducer = (state = initialState, action) =&amp;gt; {
    switch(action.type){
        case LOGIN_REQUEST:
            return {}
        case LOGIN_SUCCESS:
			return {}
        case LOGIN_FAILURE:
			return {}
        case CLEAR_ERROR_REQUEST:
			return {}
        case CLEAR_ERROR_SUCCESS:
            return {}
        case CLEAR_ERROR_FAILURE:
            return {}
        default:
            return state
    }
}
export default authreducer&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;authreducer함수를 만들고 state라는 변수에 현재 상태 기본값을 넣어준 initialState로 초기화 시켜주고&lt;br /&gt;switch문으로 위에서 작성했던 로그인 상태에 관한 type들 받아준다.&lt;br /&gt;(Login_Success,Failure.. 등등..)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 타입마다 동작할 return값을 작성한다.&lt;/p&gt;
&lt;pre id=&quot;code_1624034127140&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const authreducer = (state = initialState, action) =&amp;gt; {
    switch(action.type){
        case LOGIN_REQUEST:
            return {
                ...state, //... 은 얕은 복사를 의미함
                errorMsg:&quot;&quot;,
                isLoading: true 
            }
        case LOGIN_SUCCESS:
            localStorage.setItem(&quot;token&quot;, action.payload.token) //서버에서 인증토큰값을 가져온다(jwt)
            return{
                ...state,
                ...action.payload,
                isAuthenticated: true,
                isLoading: false,
                userId: action.payload.user.userId,
                userRole : action.payload.user.role,
                errorMsg:&quot;&quot;
            }

        case LOGIN_FAILURE:
            localStorage.removeItem(&quot;token&quot;) // 로그인이 실패하였으므로 token을 제거함
            return{
                ...state,
                ...action.payload,
               token : null,
               user : null,
               userId: null,
               isAuthenticated: false,
               isLoading : false,
               userRole: null,
               errorMsg: action.payload.data.msg
            }
        case CLEAR_ERROR_REQUEST:
            return{
                ...state,
                ERRORmSG: null,
            }
        case CLEAR_ERROR_SUCCESS:
            return{
                ...state,
                ERRORmSG: null,
            }
        case CLEAR_ERROR_FAILURE:
            return{
                ...state,
                ERRORmSG: null,
            }
        default:
            return state
    }
}
export default authreducer&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;...state에서 ...은 얉은 복사를 의미한다.&lt;br /&gt;state값을 복사하는 이유는 기존의 state값과 현재 바뀐 state값을 비교하여&amp;nbsp;&lt;br /&gt;바뀐 부분만 반영하기 위해서이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[redux/reducers/authReducer.js ] 전체코드&lt;/p&gt;
&lt;pre id=&quot;code_1624031502721&quot; class=&quot;javascript&quot; style=&quot;display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; margin: 20px auto 0px; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { NULL } from 'node-sass'
import { CLEAR_ERROR_FAILURE, CLEAR_ERROR_REQUEST, CLEAR_ERROR_SUCCESS, LOGIN_FAILURE, LOGIN_REQUEST, LOGIN_SUCCESS } from '../types'

const initialState = {
    token:localStorage.getItem('token'),
    isAuthenticated: null,
    isLoading: false,
    user: &quot;&quot;,
    userId:&quot;&quot;,
    userName:&quot;&quot;,
    userRole:&quot;&quot;,
    errorMsg:&quot;&quot;,
    successMsg:&quot;&quot;,
}

const authreducer = (state = initialState, action) =&amp;gt; {
    switch(action.type){
        case LOGIN_REQUEST:
            return {
                ...state, 
                errorMsg:&quot;&quot;,
                isLoading: true 
            }
        case LOGIN_SUCCESS:
            localStorage.setItem(&quot;token&quot;, action.payload.token) 
            return{
                ...state,
                ...action.payload,
                isAuthenticated: true,
                isLoading: false,
                userId: action.payload.user.userId,
                userRole : action.payload.user.role,
                errorMsg:&quot;&quot;
            }

        case LOGIN_FAILURE:
            localStorage.removeItem(&quot;token&quot;)
            return{
                ...state, 
                ...action.payload,
               token : null,
               user : null,
               userId: null,
               isAuthenticated: false,
               isLoading : false,
               userRole: null,
               errorMsg: action.payload.data.msg
            }
        case CLEAR_ERROR_REQUEST:
            return{
                ...state,
                ERRORmSG: null,
            }
        case CLEAR_ERROR_SUCCESS:
            return{
                ...state,
                ERRORmSG: null,
            }
        case CLEAR_ERROR_FAILURE:
            return{
                ...state,
                ERRORmSG: null,
            }
        default:
            return state
    }
}
export default authreducer&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;이제는 로그인시 발생할 상황에 대해 기능적으로 구현을 했으니&amp;nbsp;&lt;br /&gt;다음 포스팅에서는 모달창이라는 것을 활용하여 로그인창을 띄워 로그인기능과 연동 시켜보겠다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>MernStack</category>
      <category>express</category>
      <category>javascript</category>
      <category>js</category>
      <category>MernStack</category>
      <category>Node js</category>
      <category>react</category>
      <category>노드js</category>
      <category>리액트</category>
      <category>블로그 만들기</category>
      <category>자바스크립트</category>
      <author>Wuny</author>
      <guid isPermaLink="true">https://wuny-dev.tistory.com/46</guid>
      <comments>https://wuny-dev.tistory.com/46#entry46comment</comments>
      <pubDate>Fri, 18 Jun 2021 01:39:45 +0900</pubDate>
    </item>
    <item>
      <title>[MernStack] Blog 만들기 15. [React]  Navigator 작업</title>
      <link>https://wuny-dev.tistory.com/45</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;components/AppNavbar.js 생성을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[AppNavbar.js ]&lt;/p&gt;
&lt;pre id=&quot;code_1622735464194&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React, { Fragment } from 'react';
import {Navbar, Container} from 'reactstrap';
import { Link } from &quot;react-router-dom&quot;;
// 크롬확장자 page Ruler Redux설치하여 웹의 픽셀을 구할 수 있다.
const AppNavbar = () =&amp;gt;{
    return(
        &amp;lt;Fragment&amp;gt;
    &amp;lt;Navbar&amp;gt;
        &amp;lt;Container&amp;gt;
            &amp;lt;Link to=&quot;/&quot; className=&quot;&quot;&amp;gt;
                Side Project's Blog(Wuny)
            &amp;lt;/Link&amp;gt;
        &amp;lt;/Container&amp;gt;
    &amp;lt;/Navbar&amp;gt;
&amp;lt;/Fragment&amp;gt;
    )
}

export default AppNavbar;&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&amp;lt;Link to =&quot;/&quot; className=&quot;&quot;&amp;gt;&amp;nbsp; 에서 to는 어디로 이동할지를 나타낸다.&lt;br /&gt;LInk to의 &quot;/&quot; 는 홈으로 가게한다.&lt;br /&gt;그 다음 className을 적어 줄것인데 우선 잘 작동하는지 테스트를 위해 아무것도 작성하지 않는다.&lt;br /&gt;(아래서 작성함)&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;i&gt;//크롬 확장도구인 Page Ruler Redux 를 설치하면 웹사이트의 컨테이너 픽셀을 구할 수 있다.&lt;/i&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[Routes/Router.js]&lt;/p&gt;
&lt;pre id=&quot;code_1622735660289&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const MyRoter = () =&amp;gt; (
  &amp;lt;Fragment&amp;gt; 
    &amp;lt;AppNavbar/&amp;gt;
      &amp;lt;Header/&amp;gt;
      &amp;lt;h2&amp;gt;Hello Body&amp;lt;/h2&amp;gt;
      &amp;lt;Footer/&amp;gt;
  &amp;lt;/Fragment&amp;gt;  
);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 우리가 작성한 AppNavbar를 Header위에 불러준다.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-origin-width=&quot;1918&quot; data-origin-height=&quot;426&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IsUks/btq6sdmFadK/rWmgKdkxk8fDkx9zKyUS1k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IsUks/btq6sdmFadK/rWmgKdkxk8fDkx9zKyUS1k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IsUks/btq6sdmFadK/rWmgKdkxk8fDkx9zKyUS1k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIsUks%2Fbtq6sdmFadK%2FrWmgKdkxk8fDkx9zKyUS1k%2Fimg.png&quot; data-origin-width=&quot;1918&quot; data-origin-height=&quot;426&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;헤더위에 우리가 작성한 글씨가 보인다.&lt;br /&gt;마우스를 가져가면 밑줄이 생겨 하이퍼 링크가 생긴걸 알 수 가 있다.&lt;br /&gt;우린 디자인상 밑줄을 안보이게 작업하겠다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[AppNavbar.js ]&lt;/p&gt;
&lt;pre id=&quot;code_1622736542238&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React, { Fragment } from 'react';
import {Navbar, Container, NavbarToggler, Col, Collapse, Nav} from 'reactstrap';
import { Link } from &quot;react-router-dom&quot;;
// 크롬확장자 page Ruler Redux설치하여 웹의 픽셀을 구할 수 있다.
const AppNavbar = () =&amp;gt;{
    return(
        &amp;lt;Fragment&amp;gt;
    &amp;lt;Navbar color=&quot;dark&quot; dark expand=&quot;lg&quot; className=&quot;sticky-top&quot;&amp;gt;
        &amp;lt;Container&amp;gt;
            &amp;lt;Link to=&quot;/&quot; className=&quot;text-white text-decoration-none&quot;&amp;gt;
                Side Project's Blog(Wuny)
            &amp;lt;/Link&amp;gt;
            &amp;lt;NavbarToggler/&amp;gt;
            &amp;lt;Collapse isOpen={true} navbar&amp;gt;
                &amp;lt;Nav className=&quot;ml-auto d-flex justify-content-around&quot; navbar&amp;gt;
                //ml : 왼쪽 마진.. margin left
                {true ? &amp;lt;h1 className=&quot;text-white&quot;&amp;gt;authLink&amp;lt;/h1&amp;gt; : &amp;lt;h1 className=&quot;text-white&quot;&amp;gt;guestLink&amp;lt;/h1&amp;gt;}
                &amp;lt;/Nav&amp;gt;
            &amp;lt;/Collapse&amp;gt;
        &amp;lt;/Container&amp;gt;
    &amp;lt;/Navbar&amp;gt;
&amp;lt;/Fragment&amp;gt;
    )
}

export default AppNavbar;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Container태그의 ClassName을 text-white text-decoration-none 으로 설정해준다.&lt;br /&gt;NavbarToggler라는 것을 달아준다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; width=&quot;181&quot; height=&quot;348&quot; data-origin-width=&quot;504&quot; data-origin-height=&quot;968&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDBPkX/btq7uTTHWzm/QHM40iR8K2S188JvkqwM90/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDBPkX/btq7uTTHWzm/QHM40iR8K2S188JvkqwM90/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDBPkX/btq7uTTHWzm/QHM40iR8K2S188JvkqwM90/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDBPkX%2Fbtq7uTTHWzm%2FQHM40iR8K2S188JvkqwM90%2Fimg.png&quot; width=&quot;181&quot; height=&quot;348&quot; data-origin-width=&quot;504&quot; data-origin-height=&quot;968&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;Toggler는 창을 최소화 하였을시(또는 모바일) 네비게이션 메뉴들이 아래 사진의 세줄메뉴 버튼으로 합쳐져&lt;br /&gt;저 버튼을 누르면(Collapse) 네비게이션 메뉴들이 나오것을 말한다.&lt;br /&gt;&lt;br /&gt;Collapse태그가 방금 말한 버튼을 나오면 네베게이션이 나오게 해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #eeffff;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;lt;Collapse isOpen={true} navbar&amp;gt;&lt;br /&gt;상태를 기본값으로 true로 설정한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; letter-spacing: 0px;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #000000; letter-spacing: 0px;&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color: #000000; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #000000; letter-spacing: 0px;&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color: #000000; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&amp;lt;h1 className=&quot;text-white&quot;&amp;gt;authLink&amp;lt;/h1&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #000000; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #000000; letter-spacing: 0px;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #000000; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&amp;lt;h1 className=&quot;text-white&quot;&amp;gt;guestLink&amp;lt;/h1&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #000000; letter-spacing: 0px;&quot;&gt;}&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;만약 Collapse가&amp;nbsp; &lt;span style=&quot;color: #006dd7;&quot;&gt;true&lt;/span&gt;이면 &lt;span style=&quot;color: #006dd7;&quot;&gt;&amp;lt;h1&amp;nbsp;className=&quot;text-white&quot;&amp;gt;authLink&amp;lt;/h1&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&amp;gt;&lt;/span&gt; 가 출력되고&lt;br /&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;false&lt;/span&gt;이면 &lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&amp;lt;h1&amp;nbsp;className=&quot;text-white&quot;&amp;gt;guestLink&amp;lt;/h1&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&amp;gt;&lt;/span&gt;가 출력이 된다.&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;우린 true로 박아뒀기에 authLink가 나오는 걸 볼 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-origin-width=&quot;1921&quot; data-origin-height=&quot;433&quot; width=&quot;585&quot; height=&quot;132&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b66N4L/btq7trDz5W5/r58VsnfUBLZgIWxFSSmHQ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b66N4L/btq7trDz5W5/r58VsnfUBLZgIWxFSSmHQ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b66N4L/btq7trDz5W5/r58VsnfUBLZgIWxFSSmHQ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb66N4L%2Fbtq7trDz5W5%2Fr58VsnfUBLZgIWxFSSmHQ1%2Fimg.png&quot; data-origin-width=&quot;1921&quot; data-origin-height=&quot;433&quot; width=&quot;585&quot; height=&quot;132&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;화면 사이즈를 줄였을시 NavbarToggler로 바뀐다.&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-origin-width=&quot;953&quot; data-origin-height=&quot;458&quot; width=&quot;593&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xwq68/btq7uuNmJYe/Yd1zaBHE3OuNHtToqssoE1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xwq68/btq7uuNmJYe/Yd1zaBHE3OuNHtToqssoE1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xwq68/btq7uuNmJYe/Yd1zaBHE3OuNHtToqssoE1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fxwq68%2Fbtq7uuNmJYe%2FYd1zaBHE3OuNHtToqssoE1%2Fimg.png&quot; data-origin-width=&quot;953&quot; data-origin-height=&quot;458&quot; width=&quot;593&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;lt;Nav className=&quot;ml-auto d-flex justify-content-around&quot; navbar&amp;gt;를 보면 d-flex라는 것을 사용했는데&lt;br /&gt;flexbox를 의미한다.&lt;br /&gt;flexbox는 레이아웃을 배치를 좀 더 쉽게 하기위해 사용되는 것이다.&lt;br /&gt;자세한 내용은 &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Learn/CSS/CSS_layout/Flexbox&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;클릭&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1623855174443&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Flexbox - Web 개발 학습하기 | MDN&quot; data-og-description=&quot;flexbox는 행과 열 형태로 항목 무리를 배치하는 일차원 레이아웃 메서드입니다. 항목은 부족한 공간에 맞추기 위해 축소되거나 여분의 공간을 채우기 위해 변형된다. 이 문서는 근간이 되는 내용&quot; data-og-host=&quot;developer.mozilla.org&quot; data-og-source-url=&quot;https://developer.mozilla.org/ko/docs/Learn/CSS/CSS_layout/Flexbox&quot; data-og-url=&quot;https://developer.mozilla.org/ko/docs/Learn/CSS/CSS_layout/Flexbox&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/wadZd/hyKAlSu7LD/nJgt20L2VKEcTj9iNtIakk/img.png?width=1920&amp;amp;height=1080&amp;amp;face=0_0_1920_1080,https://scrap.kakaocdn.net/dn/1yUSm/hyKAnbJvdG/eMOJNCkGKl3HQpB0ndi4Rk/img.png?width=800&amp;amp;height=646&amp;amp;face=418_211_681_307,https://scrap.kakaocdn.net/dn/1eBjB/hyKAqM2iOL/EMkVIquLJ5eO9nT1gdze2k/img.png?width=800&amp;amp;height=646&amp;amp;face=0_0_800_646&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Learn/CSS/CSS_layout/Flexbox&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.mozilla.org/ko/docs/Learn/CSS/CSS_layout/Flexbox&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/wadZd/hyKAlSu7LD/nJgt20L2VKEcTj9iNtIakk/img.png?width=1920&amp;amp;height=1080&amp;amp;face=0_0_1920_1080,https://scrap.kakaocdn.net/dn/1yUSm/hyKAnbJvdG/eMOJNCkGKl3HQpB0ndi4Rk/img.png?width=800&amp;amp;height=646&amp;amp;face=418_211_681_307,https://scrap.kakaocdn.net/dn/1eBjB/hyKAqM2iOL/EMkVIquLJ5eO9nT1gdze2k/img.png?width=800&amp;amp;height=646&amp;amp;face=0_0_800_646');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Flexbox - Web 개발 학습하기 | MDN&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;flexbox는 행과 열 형태로 항목 무리를 배치하는 일차원 레이아웃 메서드입니다. 항목은 부족한 공간에 맞추기 위해 축소되거나 여분의 공간을 채우기 위해 변형된다. 이 문서는 근간이 되는 내용&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developer.mozilla.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;부트스트랩 flexbox 사용법 &lt;a href=&quot;https://getbootstrap.com/docs/5.0/utilities/flex/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;클릭&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1623855577961&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Flex&quot; data-og-description=&quot;Quickly manage the layout, alignment, and sizing of grid columns, navigation, components, and more with a full suite of responsive flexbox utilities. For more complex implementations, custom CSS may be necessary.&quot; data-og-host=&quot;getbootstrap.com&quot; data-og-source-url=&quot;https://getbootstrap.com/docs/5.0/utilities/flex/&quot; data-og-url=&quot;https://getbootstrap.com/docs/5.0/utilities/flex/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cMuhAr/hyKAhP4UL7/1cF60WMfzz34npRhG5iJ0K/img.png?width=1000&amp;amp;height=500&amp;amp;face=0_0_1000_500,https://scrap.kakaocdn.net/dn/bqm704/hyKAfkrsmu/t2QgKmz2kdgl1tUgnuvS2k/img.png?width=1000&amp;amp;height=500&amp;amp;face=0_0_1000_500&quot;&gt;&lt;a href=&quot;https://getbootstrap.com/docs/5.0/utilities/flex/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://getbootstrap.com/docs/5.0/utilities/flex/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cMuhAr/hyKAhP4UL7/1cF60WMfzz34npRhG5iJ0K/img.png?width=1000&amp;amp;height=500&amp;amp;face=0_0_1000_500,https://scrap.kakaocdn.net/dn/bqm704/hyKAfkrsmu/t2QgKmz2kdgl1tUgnuvS2k/img.png?width=1000&amp;amp;height=500&amp;amp;face=0_0_1000_500');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Flex&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Quickly manage the layout, alignment, and sizing of grid columns, navigation, components, and more with a full suite of responsive flexbox utilities. For more complex implementations, custom CSS may be necessary.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;getbootstrap.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>MernStack</category>
      <author>Wuny</author>
      <guid isPermaLink="true">https://wuny-dev.tistory.com/45</guid>
      <comments>https://wuny-dev.tistory.com/45#entry45comment</comments>
      <pubDate>Fri, 4 Jun 2021 01:09:15 +0900</pubDate>
    </item>
    <item>
      <title>[MernStack] Blog 만들기 14. [React] Header 작업</title>
      <link>https://wuny-dev.tistory.com/44</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;너무 급하게 마음을 먹지않고 천천히 공부하니 프론트딴에 재미가 들렸다.&lt;br /&gt;요즘 회사에서도 틈틈히 공부를 하고 있지만 턱 없이 부족하다 ㅜㅜ&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;footer까지 작성했고 이제&amp;nbsp; head를 작성할 차례이다.&lt;br /&gt;head는 내 블로그의 이름이 들어가고 이미지를 박아둘 수 있다.&lt;br /&gt;사용차 관점에서 Header부분은 아주 중요하다. &lt;br /&gt;만약 사용자가 내 블로그를 방문했다가 디자인이 너무 딱딱하고 보잘것 없다면 바로 창을 닫아버릴게 뻔하다.&lt;br /&gt;사람을 처음 볼때 첫 이미지와 같은 느낌이랄까..?&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1.Header 작성&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[components/Header.js]&lt;/p&gt;
&lt;pre id=&quot;code_1622649691895&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React from 'react';
import {Row,Col} from 'reactstrap'

const Header = () =&amp;gt; {
    return (
        &amp;lt;div id=&quot;page-header&quot; className=&quot;mb-3&quot;&amp;gt;
            &amp;lt;Row&amp;gt;
                &amp;lt;Col md=&quot;6&quot; sm=&quot;auto&quot; className=&quot;text-center m-auto&quot;&amp;gt;
                    &amp;lt;h1&amp;gt;Read Our Blog&amp;lt;/h1&amp;gt;
                    &amp;lt;p&amp;gt;Wuny's side project Work Blog&amp;lt;/p&amp;gt;
                &amp;lt;/Col&amp;gt;
            &amp;lt;/Row&amp;gt;
        &amp;lt;/div&amp;gt;
        )
    
};

export default Header;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt;Col md=&quot;6&quot; sm=&quot;auto&quot; className=&quot;text-center m-auto&quot;&amp;gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;midium size일땐 6&lt;br /&gt;small size일땐 auto로 자동으로 반응형으로 사이즈를 잡아준다.&lt;br /&gt;여기서 기준은 12이다.&lt;br /&gt;ex )&amp;nbsp; 6일때&amp;nbsp;&lt;br /&gt;&amp;nbsp;웹 가로 크기(colums)는&amp;nbsp; 12가 기준이므로 12칸 중&lt;br /&gt;1 2 3 &lt;b&gt;|&lt;/b&gt; &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;4 5 6 7 8 9 &lt;span style=&quot;color: #000000;&quot;&gt;|&lt;/span&gt;&lt;/b&gt;&amp;nbsp;&lt;/span&gt;10 11 12&amp;nbsp;&amp;nbsp;&lt;br /&gt;4~9 사이에 우리가 작성한 UI가 보여진다.&lt;br /&gt;자세한 내용은 &lt;a href=&quot;https://reactstrap.github.io/components/layout/#app&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;클릭&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;b&gt;2. Header의 Css작성&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;[assets/custom.scss]&lt;/p&gt;
&lt;pre id=&quot;code_1622649718116&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#page-header {
    height : 230px;
    background:url('../assets/img/LoadView_At_night.jpg');
    background-position: 50% 72%;
    background-attachment: fixed; //고정
    color : #fff;
    border-bottom: 1px #eee solid;
    padding-top: 60px;
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;assets에 img 폴더생성 후 마음에 드는 이미지 로드한 후 background url로 불러온다.&lt;br /&gt;unsplash라는 사이트에서 많은 고화질의 이미지를 무료로 다운로드 할 수 있다.&lt;/li&gt;
&lt;li&gt;background-position:&amp;nbsp; 가로 시작지점% 세로 시작지점%&amp;nbsp; 이다.&lt;br /&gt;(이 포인트는 이미지에 맞게 설정해주자)&lt;/li&gt;
&lt;li&gt;border-bottom :&amp;nbsp; 경계선을 bottom에만 그린다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1921&quot; data-origin-height=&quot;1081&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c0BY0J/btq6vw6CXrE/41QquY8XN7ZlRF6DfdptI0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c0BY0J/btq6vw6CXrE/41QquY8XN7ZlRF6DfdptI0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c0BY0J/btq6vw6CXrE/41QquY8XN7ZlRF6DfdptI0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc0BY0J%2Fbtq6vw6CXrE%2F41QquY8XN7ZlRF6DfdptI0%2Fimg.png&quot; data-origin-width=&quot;1921&quot; data-origin-height=&quot;1081&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>MernStack</category>
      <category>javascript</category>
      <category>MernStack</category>
      <category>nodejs</category>
      <category>react</category>
      <category>리액트</category>
      <category>블로그 만들기</category>
      <category>자바스크립트</category>
      <author>Wuny</author>
      <guid isPermaLink="true">https://wuny-dev.tistory.com/44</guid>
      <comments>https://wuny-dev.tistory.com/44#entry44comment</comments>
      <pubDate>Thu, 3 Jun 2021 01:04:26 +0900</pubDate>
    </item>
    <item>
      <title>[MernStack] Blog 만들기 13. [React]Footer 작업하기</title>
      <link>https://wuny-dev.tistory.com/43</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;React자체를 처음부터 공부하느라 많이 늦어졌다.&lt;br /&gt;하루에 한 강의를 잡고.. 한 강의당 포스팅 하나 하려니 진도가 너무 안나간다...&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹은 크게 header, body, footer 로 나눌 수 있다.(더 세분화하면 무수히 많다)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-origin-width=&quot;351&quot; data-origin-height=&quot;433&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bulkkx/btq5Yp7V6HA/gOKEUYl09N95DDZvn7vnQ0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bulkkx/btq5Yp7V6HA/gOKEUYl09N95DDZvn7vnQ0/img.jpg&quot; data-alt=&quot;https://helpx.adobe.com/kr/dreamweaver/how-to/make-website-pt3-add-html5-elements.html&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bulkkx/btq5Yp7V6HA/gOKEUYl09N95DDZvn7vnQ0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbulkkx%2Fbtq5Yp7V6HA%2FgOKEUYl09N95DDZvn7vnQ0%2Fimg.jpg&quot; data-origin-width=&quot;351&quot; data-origin-height=&quot;433&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://helpx.adobe.com/kr/dreamweaver/how-to/make-website-pt3-add-html5-elements.html&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금까진 &amp;lt;div&amp;gt;태그를 사용하여 웹에 글자만 박아 뒀다.&lt;br /&gt;이젠 Footer라고 써진곳을 꾸밀 단계이다.&lt;br /&gt;이제 footer 작업을 하겠다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-origin-width=&quot;1340&quot; data-origin-height=&quot;763&quot; width=&quot;432&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cw1KaN/btq5YpGR1eR/xJmfCBL4ujI7fU27OrJrTK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cw1KaN/btq5YpGR1eR/xJmfCBL4ujI7fU27OrJrTK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cw1KaN/btq5YpGR1eR/xJmfCBL4ujI7fU27OrJrTK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcw1KaN%2Fbtq5YpGR1eR%2FxJmfCBL4ujI7fU27OrJrTK%2Fimg.png&quot; data-origin-width=&quot;1340&quot; data-origin-height=&quot;763&quot; width=&quot;432&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1.footer 작업&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;[components/footer.js]&lt;/p&gt;
&lt;pre id=&quot;code_1622129176175&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React from 'react';
import {Row, Col} from &quot;reactstrap&quot;;

const Footer = () =&amp;gt; {
    const thisYear = () =&amp;gt; {
        const year = new Date().getFullYear();
        return year
    };

    return (
        &amp;lt;div&amp;gt;
            &amp;lt;Row&amp;gt;
                &amp;lt;Col&amp;gt;
                    &amp;lt;p&amp;gt;
                        Copyright &amp;amp;copy; &amp;lt;span&amp;gt;{thisYear()}&amp;lt;/span&amp;gt;
                        
                    &amp;lt;/p&amp;gt;
                &amp;lt;/Col&amp;gt;
            &amp;lt;/Row&amp;gt;
        &amp;lt;/div&amp;gt;
    )
};

export default Footer;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;new Date().getFullYear() 는 현재 년도를 가져오는 함수이다.&amp;nbsp;&lt;br /&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;리엑트스트랩을 사용하여 &amp;lt;Row&amp;gt; &amp;lt;Col&amp;gt; 태그를 사용한다&lt;br /&gt;&lt;/span&gt;그러면 보잘것 없는 footer가 완성이된다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-origin-width=&quot;443&quot; data-origin-height=&quot;46&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bCB9oo/btq5YqeIyfW/Hc06PSo0t1zY2aSn9HKJw0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bCB9oo/btq5YqeIyfW/Hc06PSo0t1zY2aSn9HKJw0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bCB9oo/btq5YqeIyfW/Hc06PSo0t1zY2aSn9HKJw0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbCB9oo%2Fbtq5YqeIyfW%2FHc06PSo0t1zY2aSn9HKJw0%2Fimg.png&quot; data-origin-width=&quot;443&quot; data-origin-height=&quot;46&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;너무 보잘것 없기에 css작업을 할 것 이다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. footer 수정&lt;br /&gt;&lt;br /&gt;&lt;/b&gt;[Footer.js]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;div태그에 id를 main-footer로 작성하고&amp;nbsp;&lt;br /&gt;className으로&amp;nbsp; text-center p-2로 해준다.&lt;br /&gt;(p는 패딩을 뜻함.. p-2대신 m-auto로 하여 마진값을 자동으로 맞춰주게끔 할 수 있지만 별로다.)&lt;br /&gt;className은 부트스트랩을 사용하는 편리한 프레임 워크이다.&lt;/p&gt;
&lt;pre id=&quot;code_1622130923953&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; return (
        // &amp;lt;div id=&quot;main-footer&quot; className=&quot;text-center p-2&quot;&amp;gt; 
        // m-auto 왼쪽오른쪽 여백 알아서 맞춰라. m : margin
        &amp;lt;div id=&quot;main-footer&quot; className=&quot;text-center p-2&quot;&amp;gt; 
            &amp;lt;Row&amp;gt;
                &amp;lt;Col&amp;gt;
                    &amp;lt;p&amp;gt;
                        Copyright &amp;amp;copy; &amp;lt;span&amp;gt;{thisYear()}&amp;lt;/span&amp;gt;
                    &amp;lt;/p&amp;gt;
                &amp;lt;/Col&amp;gt;
            &amp;lt;/Row&amp;gt;
        &amp;lt;/div&amp;gt;
    );&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. scss 작성&lt;/b&gt;&lt;br /&gt;&amp;nbsp;assets폴더에 custom.scss 파일 생성한다.&lt;br /&gt;npm i node-sass sass-loader&amp;nbsp; 설치 ( scss를&amp;nbsp; css로 바꿔주는 라이브러리)&lt;br /&gt;라이브러리를 설치후 서버를 재시작해줘라 꼭!!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[src/assets/custom.scss]&lt;/p&gt;
&lt;pre id=&quot;code_1622131099766&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#main-footer {
    background: #343a40;
    color : #fff;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;css&amp;nbsp; 또는 scss에서&amp;nbsp; {#}은 id를 나타내고 { .} 은 class 뜻한다.&lt;br /&gt;우린 div태그 id를&amp;nbsp; main-footer로 했기때문에 #main-footer를 적어줬다.&lt;br /&gt;scss 작성을 하였으니 웹에 반영해야한다.&lt;br /&gt;&lt;br /&gt;&amp;nbsp;app.js가서 방금 작성한 scss를 불러주자.&lt;br /&gt;&lt;br /&gt;[App.js]&lt;/p&gt;
&lt;pre id=&quot;code_1622131625065&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import &quot;./assets/custom.scss&quot;; &lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;확인을 해보면 어느정도 괜찮게&amp;nbsp; css작업이 된 것을 볼 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-origin-width=&quot;1928&quot; data-origin-height=&quot;238&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cFqA9U/btq5SdgOd15/ugp1uHDY8fySXZbzkD3paK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cFqA9U/btq5SdgOd15/ugp1uHDY8fySXZbzkD3paK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cFqA9U/btq5SdgOd15/ugp1uHDY8fySXZbzkD3paK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcFqA9U%2Fbtq5SdgOd15%2Fugp1uHDY8fySXZbzkD3paK%2Fimg.png&quot; data-origin-width=&quot;1928&quot; data-origin-height=&quot;238&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;컴파일 에러 뜨면 버전이 node-sass버전이 맞지 않은 문제이므로 삭제한 다음&lt;/p&gt;
&lt;pre id=&quot;code_1622131448731&quot; class=&quot;scala&quot; data-ke-language=&quot;scala&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ npm uninstall node-sass &lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;4.14.1 버전으로 재설치 해주세요.&lt;/p&gt;
&lt;pre id=&quot;code_1622131479816&quot; class=&quot;scala&quot; data-ke-language=&quot;scala&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ npm i node-sass@4.14.1 &lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;너네들이 찾는거 나왔다.&lt;span style=&quot;background-color: #fffaf0; color: #212529;&quot;&gt;↘&lt;/span&gt;&lt;span style=&quot;background-color: #fffaf0; color: #212529;&quot;&gt;↘&lt;/span&gt;&lt;/p&gt;</description>
      <category>MernStack</category>
      <category>es6</category>
      <category>javascript</category>
      <category>merstack</category>
      <category>react</category>
      <category>리액트</category>
      <category>블로그만들기</category>
      <author>Wuny</author>
      <guid isPermaLink="true">https://wuny-dev.tistory.com/43</guid>
      <comments>https://wuny-dev.tistory.com/43#entry43comment</comments>
      <pubDate>Fri, 28 May 2021 01:10:43 +0900</pubDate>
    </item>
    <item>
      <title>[MernStack] Blog 만들기 12. Front_Router세팅</title>
      <link>https://wuny-dev.tistory.com/42</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 이번 강의편은 에러가 너무 많이 발생하여서 노드를 삭제하고 LTS버전으로 재설치하고 이것저것 삽질하느라 나도 이해를 못했다..&lt;br /&gt;우선 흐름을 파악하고 추후에 수정하겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 차라리 Java로 짜는 Spring이나 JSP가 훨씬 더 쉬운것 같다..&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. component 폴더에 Header.js와 &lt;span style=&quot;color: #333333;&quot;&gt;Footer.js를 만든다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-origin-width=&quot;309&quot; data-origin-height=&quot;536&quot; width=&quot;165&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LKDve/btq4hHpOU9O/0DqBB6QBZVbAEZLflRRLU0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LKDve/btq4hHpOU9O/0DqBB6QBZVbAEZLflRRLU0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LKDve/btq4hHpOU9O/0DqBB6QBZVbAEZLflRRLU0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLKDve%2Fbtq4hHpOU9O%2F0DqBB6QBZVbAEZLflRRLU0%2Fimg.png&quot; data-origin-width=&quot;309&quot; data-origin-height=&quot;536&quot; width=&quot;165&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt;Header.js&amp;gt;&lt;/p&gt;
&lt;pre id=&quot;code_1620317848755&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React from 'react';

const Header = () =&amp;gt; {
    return &amp;lt;div&amp;gt;Header&amp;lt;/div&amp;gt;
};

export default Header;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt;Footer.js&amp;gt;&lt;/p&gt;
&lt;pre id=&quot;code_1620317863533&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React from 'react';

const Footer = () =&amp;gt; {
    return &amp;lt;div&amp;gt;Footer&amp;lt;/div&amp;gt;
};

export default Footer;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 라우터 세팅&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;routes폴더안에 2개의 폴더를 생성한다.&lt;br /&gt;&lt;br /&gt;첫 번째, 누구나 접근 할 수 있는 normalRoute폴더&lt;br /&gt;두 번째, 권한이 있는 사람만 접근 가능한 protectedRoute를 만든다&lt;br /&gt;&lt;br /&gt;접근제한 라우터는(protectedRoute) 게시글 수정은 글을 작성한 사람만이 가능하기에&amp;nbsp;&lt;br /&gt;게시글 수정 URL로 권한이 없는 자의 접근을 막는 역할을 한다.&lt;br /&gt;우선 폴더만 생성하고 추후에 작업할 것 이다.&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;2.1 routes폴더 안에 Roter.js 파일을 생성한다.&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt;Router.js&amp;gt;&lt;/p&gt;
&lt;pre id=&quot;code_1620318157537&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React, { Fragment } from 'react'
import Header from '../components/Header'
import Footer from '../components/Footer'

//{(retrun)} ...이고 {} 없이 ()사용하면 retrun을 생략한다.
const MyRoter = () =&amp;gt; (
  &amp;lt;Fragment&amp;gt; 
      &amp;lt;Header/&amp;gt;
      &amp;lt;h2&amp;gt;Hello Body&amp;lt;/h2&amp;gt;
      &amp;lt;Footer/&amp;gt;
  &amp;lt;/Fragment&amp;gt;  
);

export default MyRoter;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 &amp;lt;Fragment&amp;gt;~&amp;lt;/Fragment&amp;gt; 이러한 형식을&lt;br /&gt;&amp;lt;&amp;gt;~ &amp;lt;/&amp;gt; 으로 Fragment를 생략 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. src의 app.js 추가 및 수정&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;app.js&amp;gt;&lt;/p&gt;
&lt;pre id=&quot;code_1620318226776&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React from 'react'

import {Provider} from 'react-redux'
import {ConnectedRouter} from 'connected-react-router'
import store,{history} from './store'
import MyRoter from './routes/Router'

import &quot;bootstrap/dist/css/bootstrap.min.css&quot;


const App = () =&amp;gt; {
    return (
        &amp;lt;Provider store={store}&amp;gt;
            &amp;lt;ConnectedRouter history={history}&amp;gt;
                &amp;lt;MyRoter /&amp;gt;
            &amp;lt;/ConnectedRouter&amp;gt;
        &amp;lt;/Provider&amp;gt;
    );
}

export default App;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다음 터미널을 실행 후&amp;nbsp; client 폴더로 이동후 npm run start를 하여 react를 실행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막에 npm run start 했을시 에러가 뜬다면 아래 두 사이트를 참고하길.&lt;br /&gt;&lt;a href=&quot;https://stackoverflow.com/questions/39959900/npm-start-error-with-create-react-app&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://stackoverflow.com/questions/39959900/npm-start-error-with-create-react-app&lt;/a&gt;&lt;a href=&quot;https://stackoverflow.com/questions/16748737/grunt-watch-error-waiting-fatal-error-watch-enospc&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://stackoverflow.com/questions/16748737/grunt-watch-error-waiting-fatal-error-watch-enospc&lt;/a&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이거&amp;nbsp;괜찮겠는데..?&amp;nbsp;&lt;/p&gt;</description>
      <category>MernStack</category>
      <category>es6</category>
      <category>javascript</category>
      <category>MernStack</category>
      <category>react</category>
      <category>redux</category>
      <category>블로그만들기</category>
      <author>Wuny</author>
      <guid isPermaLink="true">https://wuny-dev.tistory.com/42</guid>
      <comments>https://wuny-dev.tistory.com/42#entry42comment</comments>
      <pubDate>Fri, 7 May 2021 01:31:48 +0900</pubDate>
    </item>
    <item>
      <title>[MernStack] Blog 만들기 11. Front에 사용할 라이브러리 설치(Redux)</title>
      <link>https://wuny-dev.tistory.com/41</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;아직 나는 Front쪽에 많이 약하다. 아니 처음이다.&lt;br /&gt;아직 공부중인걸 바탕으로 작성하니 많이 틀린 내용이 있을 수 있지만 현재 내가 듣고 있는 강의를 기반으로 작성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 잘못된 정보가 있으면 지적해주면 감사히 받아 들이겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;1.필요한 라이브러리를 설치&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;client폴더로 이동후 설치를 한다. &lt;b&gt;꼭 client폴더로 이동하자!&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1620225609742&quot; class=&quot;scala&quot; data-ke-language=&quot;scala&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$&amp;gt; npm&amp;nbsp;i&amp;nbsp;redux&amp;nbsp;react-redux&amp;nbsp;redux-saga&amp;nbsp;react-router-dom&amp;nbsp;connected-react-router&amp;nbsp;bootstrap&amp;nbsp;reactstrap&amp;nbsp;dotenv&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt;설치목록&amp;gt;&lt;br /&gt;-redux&lt;br /&gt;- react-redux&amp;nbsp;&lt;br /&gt;- react-saga&lt;br /&gt;- react-router-dom&lt;br /&gt;- connected-react-router&lt;br /&gt;- bootstrap&lt;br /&gt;- reactstrap&lt;br /&gt;- dotenv&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 작업할 폴더 생성&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;redux 폴더안에 reducers와 sagas라는 이름으로 폴더를 생성후&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;reducers폴더안에 index.js 파일 생성,&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;sagas폴더안에 index.js 파일 생성 한다.&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-origin-width=&quot;311&quot; data-origin-height=&quot;246&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/o2Drz/btq4eiJvHLz/tm1qDebjFAFkCBxXKPkGu0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/o2Drz/btq4eiJvHLz/tm1qDebjFAFkCBxXKPkGu0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/o2Drz/btq4eiJvHLz/tm1qDebjFAFkCBxXKPkGu0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fo2Drz%2Fbtq4eiJvHLz%2Ftm1qDebjFAFkCBxXKPkGu0%2Fimg.png&quot; data-origin-width=&quot;311&quot; data-origin-height=&quot;246&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;3. reducers의 index.js생성&lt;/b&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;lt; reducers- index.js&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1620225938925&quot; class=&quot;scala&quot; data-ke-language=&quot;scala&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import {combineReducers} from 'redux';
import {connectRouter} from 'connected-react-router'

const createRootReducer = (history) =&amp;gt; combineReducers(
    {router: connectRouter(history)}
);

export default createRootReducer;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;4. sagas의 index.js생성&lt;br /&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1624518088843&quot; class=&quot;scala&quot; data-ke-language=&quot;scala&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$&amp;gt; npm i morgan&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;log를 관리해주는 morgan이라는 라이브러리를 설치해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;lt; sagas- index.js&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1620225981993&quot; class=&quot;scala&quot; data-ke-language=&quot;scala&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { format } from &quot;morgan&quot;;
import {all} from 'redux-saga/effects'


export default function* rootSaga(){ //제네레이터 함수 .. 여러값을 반환할수 있음 .
    yield all([]);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;주석에 써진것처럼 function*함수는 제네레이터 함수로 일반함수와 다르게 여러값을 반환할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 여기서 reducers와 sagas가 하는일은&lt;br /&gt;reducers는 요청을 받고 처리하는 곳이라고 한다.( 예를 들면 로그인 실패,로그인 성공..등등)&lt;br /&gt;sagas는 reducers에서 요청을 받고 처리할때 사용하는 함수들을 정의 하는 곳이다.&lt;br /&gt;( 아직 돌려보지 않았으므로 자세하게 적지는 못한다. // 추후 추가 작성 )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;4. src의 store.js 생성&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1620226240284&quot; class=&quot;scala&quot; data-ke-language=&quot;scala&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$&amp;gt; npm i history&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;먼저 history를 설치한다.&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;lt; store.js&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1620226341490&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import {createStore, compose, applyMiddleware} from 'redux'
import createSagaMiddleware from 'redux-saga'
import {createBrowserHistory} from 'history'
import { routerMiddleware } from 'connected-react-router'

import createRootReducer from './redux/reducers/index'
import rootSaga from './redux/sagas'

export const history = createBrowserHistory()

const sagaMiddleware = createSagaMiddleware();

const initialState = {}

const middlewares = [sagaMiddleware, routerMiddleware(history)]
const devtools = window.__REDUX_DEVTOOLS_EXTENTION_COMPOSE__

const composeEnhancer = process.env.NODE_ENV === &quot;production&quot;
    ? compose
    : devtools || compose;           // 배포시 개발자 도구를 삭제 하기위한 코드 

const  store = createStore(
    createRootReducer(history),
    initialState, //웹에 모든 상태를 담고 있는 초기갑ㅅ // 모든 갑을 store에서 다 저장함.
    composeEnhancer(applyMiddleware(...middlewares))
)
sagaMiddleware.run(rootSaga)

export default store

&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;/span&gt;store의 역할은 모든 값을 store에서 저장후 필요할때 store에서 꺼내 쓴다고 한다.&lt;br /&gt;예를 들면... abcde&lt;br /&gt;E의 부모노드는 D이고&lt;br /&gt;D의 부모노드는 C이고&amp;nbsp;&lt;br /&gt;C의 부모노드는 B이고&lt;br /&gt;B의 부모노드는 A이다.&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;E에서 작업을 하고 있고 어떠한 값을 사용중이였다고 치자.&lt;br /&gt;그 값은 최상위 노드인 A에서 생성된 값인데&lt;br /&gt;그 값의 위치를 찾기위해 상위 노드 D를 찾아보고 D에 없으니 C를 찾아보고.. C에도 없으니 B를 찾아본다.&lt;br /&gt;이런 번거러움을 없애고 편의성을 위해 웹에 모든 상태를 담고 있는 값을 store에 담아 사용한다.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대박이네 여기..&lt;/p&gt;</description>
      <category>MernStack</category>
      <category>mern</category>
      <category>MernStack</category>
      <category>react</category>
      <category>리액트</category>
      <category>블로그만들기</category>
      <author>Wuny</author>
      <guid isPermaLink="true">https://wuny-dev.tistory.com/41</guid>
      <comments>https://wuny-dev.tistory.com/41#entry41comment</comments>
      <pubDate>Thu, 6 May 2021 00:03:22 +0900</pubDate>
    </item>
    <item>
      <title>[MernStack] Blog 만들기 10. Front작업, React  설치</title>
      <link>https://wuny-dev.tistory.com/40</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;저번달은 개인 사정으로 포스팅을 하지 못했습니다 !!&lt;br /&gt;다시 오랜만에 이어서 글을 쓸려고하니 뭐가 뭔지 하나도 모르겠지만 포스팅을 다시 처음부터 보고 이어서 작성하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제부터는&amp;nbsp; Front 작업 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1.React 설치&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;client폴더를 생성 후 client 경로로 이동하여 ( cd client)&lt;/p&gt;
&lt;pre id=&quot;code_1620220769855&quot; class=&quot;scala&quot; data-ke-language=&quot;scala&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$&amp;gt; npx create-react-app .  &lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리엑트 패키지를 설치한다.&lt;br /&gt;(&amp;nbsp; (.)의 의미는 현재 폴더에 설치하겠다는 뜻임)&lt;br /&gt;( 만약 npx create-react-app mert 라고 하면 mert라는 폴더에 설치가 된다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;1117&quot; data-origin-height=&quot;225&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/duyMV2/btq4bMecIjS/8yTBGnUiav84MJcofnkAMk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/duyMV2/btq4bMecIjS/8yTBGnUiav84MJcofnkAMk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/duyMV2/btq4bMecIjS/8yTBGnUiav84MJcofnkAMk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FduyMV2%2Fbtq4bMecIjS%2F8yTBGnUiav84MJcofnkAMk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1117&quot; height=&quot;225&quot; data-origin-width=&quot;1117&quot; data-origin-height=&quot;225&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설치가 성공적으로 완료 되었다면 &lt;span style=&quot;color: #333333;&quot;&gt;public , src폴더가 생긴다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 필요없는 파일 삭제 및 정리&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;src폴더에서 app.js와 index.js를 제외하고 나머지 파일들 삭제한다.&lt;br /&gt;추후에 작업할 assets, componets,redux,routes폴더 생성한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;317&quot; data-origin-height=&quot;595&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cTYWzv/btq4dkgLh4h/ypaVMrqvtHxlTkphw05Bs0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cTYWzv/btq4dkgLh4h/ypaVMrqvtHxlTkphw05Bs0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cTYWzv/btq4dkgLh4h/ypaVMrqvtHxlTkphw05Bs0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcTYWzv%2Fbtq4dkgLh4h%2FypaVMrqvtHxlTkphw05Bs0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;317&quot; height=&quot;595&quot; data-origin-width=&quot;317&quot; data-origin-height=&quot;595&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. src의&amp;nbsp; App.js와 index.js 코드 정리&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt;App.js&amp;gt;&lt;/p&gt;
&lt;pre id=&quot;code_1620221201689&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//import logo from './logo.svg'; //삭제
//import './App.css';  //삭제
import React from 'react' //추가


const App = ()=&amp;gt; {
  return (
    &amp;lt;div&amp;gt;
     Hello
    &amp;lt;/div&amp;gt;
  );
}

export default App;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;funtion부분을 const로 바꾸고 위와 같이 바꿔준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt;index.js&amp;gt;&lt;/p&gt;
&lt;pre id=&quot;code_1620221261731&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

ReactDOM.render(
  &amp;lt;React.StrictMode&amp;gt;
    &amp;lt;App /&amp;gt;
  &amp;lt;/React.StrictMode&amp;gt;,
  document.getElementById('root')
);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;index.js도 위와 같이 바꿔준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;App.js의 div태그안에 hello를 넣어줬기 때문에 React서버를 실행하면 hello가 나올것이다.&lt;/p&gt;
&lt;pre id=&quot;code_1620221411235&quot; class=&quot;scala&quot; data-ke-language=&quot;scala&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$&amp;gt; npm start&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;터미널에 실행하면&amp;nbsp; 로컬서버 주소로 웹이 실행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt;에러 발생시&amp;gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;i&gt;There might be a problem with the project dependency tree.&lt;/i&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;i&gt;It is likely not a bug in Create React App, but something you need to fix locally.&lt;/i&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;i&gt;The react-scripts package provided by Create React App requires a dependency:&lt;/i&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;i&gt;&amp;nbsp; &quot;babel-loader&quot;: &quot;8.1.0&quot;&lt;/i&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 에러가 발생한다면&amp;nbsp; 작업하고 있는 최상위 루트로 이동하여&lt;br /&gt;npm uni babel-loader 를 해주어 babel 을 삭제한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다음 8.1.0으로 설치 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;npm i babel-loader@8.1.0 -D&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 사이트가 있었다니..?&lt;/p&gt;</description>
      <category>MernStack</category>
      <category>javascript</category>
      <category>mern</category>
      <category>MernStack</category>
      <category>react</category>
      <category>리액트</category>
      <category>블로그만들기</category>
      <category>자바스크립트</category>
      <author>Wuny</author>
      <guid isPermaLink="true">https://wuny-dev.tistory.com/40</guid>
      <comments>https://wuny-dev.tistory.com/40#entry40comment</comments>
      <pubDate>Wed, 5 May 2021 22:33:03 +0900</pubDate>
    </item>
    <item>
      <title>[MernStack] Blog 만들기 9. auth Router (로그인 , 로그아웃 기능)</title>
      <link>https://wuny-dev.tistory.com/39</link>
      <description>&lt;p&gt;이제는 로그인과 관련된 라우터를 만들겠다.&lt;/p&gt;
&lt;p&gt;사용자가 입력한 아이디와 패스워드를 서버로 전송하고&lt;br /&gt;서버에서는 저장되어 있는 아이디와 패스워드를 비교하여&lt;br /&gt;일치하면 토큰값과 로그인 성공 응답을 보내주고,&lt;br /&gt;일치하지 않 으면 에러 메세지를 띄워 로그인 실패 응답을 보내준다.&lt;/p&gt;
&lt;p&gt;이에 관련한 auth Router를 만들겠다.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;1.auth.js 라우터 생성&lt;/b&gt;&lt;br /&gt;routes/api 폴더에 auth.js를 생성한다&lt;/p&gt;
&lt;p&gt;&amp;lt;auth.js&amp;gt;&lt;/p&gt;
&lt;pre id=&quot;code_1617034344632&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import express from &quot;express&quot;;
import bcrypt from &quot;bcryptjs&quot;;
import jwt from &quot;jsonwebtoken&quot;;
import auth from &quot;../../middleware/auth&quot;;
import config from  &quot;../../config/index&quot;;
import {JWT_SECRET} = config;

//model
import User from &quot;../../models/user&quot;;

const router = express.Router();

// @route    POST  api/auth
// @desc     Auth  user
// @access   Public

router.post(&quot;/&quot;, (req,res) =&amp;gt; {
    const {email, password } = req.body; // req.body에 사용자가 입력한 아이디와 패스워드를 보낸다.

    //Simple Validation
    if(!email || !password) {
        return res.status(400).json({msg : &quot;모든 필드를 채워주세요 &quot;});
    } // 둘중 하나라도 채우지 않으면 에러메세지를 띄운다
    
    //check for existing user
    User.findOne({email}).then((user) =&amp;gt; {
        if(!user) return res.status(400).json({msg: &quot;존재하지 않는 유저입니다. &quot;});
        
        //validate password
        bcrypt.compare(password, user.password).then(isMatch) =&amp;gt; {
            if(!isMatch) 
            return res.status(400).json({msg : &quot;비밀번호가 일치하지 않습니다. &quot;})
            
            // 로그인 성공시 ...
            jwt.sign(
                { id : user.id},
                JWT_SECRET,
                { expiresIn : &quot;2 days&quot;}, //토큰의 유효기간은 2달로 지정
                (err, token) =&amp;gt; {
                    if (err) throw err;
                    res.json({
                        token,
                        user:{
                            id: user.id,
                            name : user.name,
                            email : user.email,
                            role: user.role,
                        }
                    })
                }
                )
        }
    })
})

export default router;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;b&gt;2.&amp;nbsp; auth Router 사용하기위해 app.js에 등록&lt;/b&gt;&lt;br /&gt;&amp;lt;app.js&amp;gt;&lt;/p&gt;
&lt;pre id=&quot;code_1617034999091&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import authRoutes from  './routes/api/auth';
//....
app.use('/api/auth', authRoutes)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;3. 포스트맨으로 테스트&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdZTDu/btq1e7Fw9W5/QwaDb7uj8yaR1kdwPUmTBK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdZTDu/btq1e7Fw9W5/QwaDb7uj8yaR1kdwPUmTBK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdZTDu/btq1e7Fw9W5/QwaDb7uj8yaR1kdwPUmTBK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdZTDu%2Fbtq1e7Fw9W5%2FQwaDb7uj8yaR1kdwPUmTBK%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;전전 포스팅에서 가입한 아이디와 패스워드를 입력하고 auth 주소로 POST요청을 하면 토큰값과 user정보를 보내준다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;4.로그아웃 기능 만들기&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;auth.js&amp;gt;&lt;/p&gt;
&lt;pre id=&quot;code_1617035321902&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;router.get(&quot;/user&quot;, auth, async (req, res) =&amp;gt; {
  try {
    const user = await User.findById(req.user.id).select(&quot;-password&quot;);
    if (!user) throw Error(&quot;유저가 존재하지 않습니다&quot;);
    res.json(user);
  } catch (e) {
    console.log(e);
    res.status(400).json({ msg: e.message });
  }
});&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;export default router 위에 추가 해준다.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;5. 포스트맨에서 테스트&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bozHsn/btq1lbmSYZ9/aAMK2WxZAHchFJkwehAsJ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bozHsn/btq1lbmSYZ9/aAMK2WxZAHchFJkwehAsJ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bozHsn/btq1lbmSYZ9/aAMK2WxZAHchFJkwehAsJ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbozHsn%2Fbtq1lbmSYZ9%2FaAMK2WxZAHchFJkwehAsJ1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;로그인했을때 받은 토큰값을 넣어 &lt;span style=&quot;color: #333333;&quot;&gt;GET요청을 하면 아래와 같이 회원정보가 나오면 성공이다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>MernStack</category>
      <category>express</category>
      <category>javascript</category>
      <category>mern Stack</category>
      <category>Node js</category>
      <category>Router</category>
      <category>블로그만들기</category>
      <author>Wuny</author>
      <guid isPermaLink="true">https://wuny-dev.tistory.com/39</guid>
      <comments>https://wuny-dev.tistory.com/39#entry39comment</comments>
      <pubDate>Tue, 30 Mar 2021 01:33:56 +0900</pubDate>
    </item>
  </channel>
</rss>