728x90
728x90

Step 1) 화씨 온도를 섭씨로 바꾸기

  • API->Current Wather->API doc->좌측의 Other features->Units format을 클릭한다.

  • &units=metric 을 추가한다. 그 후 시뮬레이터를 실행시키고 콘솔 로그를 확인해보면 아래와 같이 temp가 섭씨 온도(14도)로 바뀐것을 확인할 수 있다.

 

Step 2) Temperature Component 생성

  • Weather.js 파일을 새로 만든다.
  • props가 필요하므로 prop-types를 install 하기 위해 vscode terminal에

$ npm install prop-types

를 입력한다.

  • Weather.js 파일에 아래와 같이 코드를 작성한다.

  • App.js파일에 작성한 Weather.js 를 아래의 방법으로 import 한다.

import Weather from "./Weather";

  • temperature 정보를 가져오기 위해

우리는 data.main.temp 가 필요하다.

  • 위와 같이 App.js 코드를 수정한다.
  • 수정 후 시뮬레이터를 실행하면

이렇게 온도 (temperature) 가 스크린에 출력된다.

  • 그런데 이 과정에서 간단한 문제로 오류가 나서 애를 먹었다.

 

[오류 해결]

  • Invariant Violation : Element type is invalid : expected a string (for built- in components) or a ~ (이하 생략) 이라는 오류가 발생했다.
  • 문제는 자동으로 Weather가 import 되지 않고 수동으로 import ~ 라고 타이핑해서 링크가 되지 않아 발생한 것이었다.
  • App.js 파일의 맨 아래 부분에 render() 안에서 ‘null’을 <Weather /> 로 바꿀 때, 하나씩 수동으로 타이핑하면 코드를 인식하지 못하는 것 같다. <Weather></Weather> 로 자동 생성 되도록 하면 자동으로 App.js 파일의 상단에 Weather가 import 됨을 확인할 수 있다. 그럼 오류가 해결된다.

 

Step 3) condition name (날씨 종류) 정보 가져오기

Weather.js

 

App.js (line 23 추가)

 

App.js (line 47–48 추가)

 

  • 그러나 이 방법은 condition name을 얻는 최선의 방법이 아니다.
  • 콘솔 로그를 보면 딱 하나의 Array 가 있는걸 확인할 수 있는데

객체 하나를 가진 Array가 하나 있다. 이 배열안의 객체 안의 main이 우리가 얻고자 하는 condition name 이다.

  • 그럼 weather 배열로부터 main 부분을 가져와보자.

  • 코드를 조금 더 보기 쉽게 살짝 수정하였다.
  • line 28을 보면 weather 배열의 첫번째 요소(객체 Object)로부터 main 값을 가져왔음을 볼 수 있다.

 

Step 4) import vector-icon

import { Ionicons } from '@expo/vector-icons';

  • 아이콘 디렉토리를 살펴보자 (https://expo.github.io/vector-icons/)
  • condition name에 각각 맞는 아이콘을 찾는다.
  • MaterialCommunityIcons Family 중에 골라보자.
  • 위에서 작성한 코드에서 중괄호에 있는 Ionicons를 MaterialCommunityIcons 로 바꾼다.

import { MaterialCommunityIcons } from '@expo/vector-icons';

  • 이제 아이콘을 가져와보자.

예시

  • 비오는 날씨를 예로 들면, 우리는 위의 화면에서 제일 하단에 위치한 ‘MaterialCommunityIcons Family’ 의 ‘weather-lightning-rainy’ 를 가져올것이다.

line 9 수정

 

결과

 

 

728x90
728x90

 

출처 : 노마드코더 - React Native로 날씨앱 만들기

 

 

<Getting the Weather>

Step 1) API KEY 가져오기

  • API keys를 클릭한다.
  • API keys 가 없으면 새로 생성한다.
  • API key를 복사해서 App.js 파일에 붙여넣자. (line 7)

 

 

Step 2) API 호출하여 정보 얻기

  • 우리가 사용할 것은 ‘By geographic coordinates’방식이며 위의 방법으로 api 를 호출해주면 된다.
  • 먼저 API call을 참고하여 브라우저에서 시도해보면 결과는 아래와 같다.

Invalid API

 

  • API Key를 포함해서 다시 시도해보자.
  • API Key를 포함하여 테스트하는 방법은 API 탭을 클릭한 후 하단으로 스크린을 내리고 ‘How to start -> Example of using API key in API call’에 나와있다.

  • &APPID = {APIKEY}를 브라우저 주소창에 추가하여 결과를 보면 아래와 같다.
  • 날씨에 관한 전반적인 정보를 얻을 수 있다.

 

Step 3) App 내부에 URL fetch하기

  • fetch를 위해 Axios를 설치한다.
  • vscode terminal 에 아래의 명령을 실행한다.
$npm install axios

  • 그 후 코드를 아래와 같이 수정한다.(line 6, 13–17, 27)

  • 이때 주의할 점은, 변수를 문자열에 포함시키기 위해 URL을 백틱(`)으로 감싸야한다는 것이다(line 15). 참고로 백틱은 맥에서 option키를 누르고 숫자 1 옆에 있는 ₩ 를 누르면 된다.
728x90
728x90

출처 : 노마드코더 - React Native로 날씨앱 만들기

Step 1) expo application 실행

$ npm start
  • vscode 터미널에 위와 같이 입력하면 자동으로 ‘export DEV tools’ 창이 크롬에 열린다.

  • 안드로이드 폰 유저는 폰의 expo앱을 열어 QR code 를 스캔하면 폰에서 앱을 테스트할 수 있다.
  • ios 유저는 폰의 expo앱에 로그인하고 vs code terminal에 아래와 같이 입력한다.
$ expo login

 

 

 

 

  • 폰으로 실행시키면 위의 화면을 볼 수 있다.
  • 이때 폰, 맥은 같은 wi-fi에 연결되어 있어야한다.

 

ERROR: Node.js version 6.10.1 is no longer supported.

expo-cli supports following Node.js versions:
* >=8.9.0 <9.0.0 (Maintenance LTS)
* >=10.13.0 <11.0.0 (Active LTS)
* >=12.0.0 (Current Release)
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! @ start: `expo start`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the @ start script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.npm ERR! A complete log of this run can be found in:
npm ERR! /Users/kimnan-young/.npm/_logs/2019-10-28T08_37_43_452Z-debug.log
  • 만약 위와 같은 오류가 뜬다면
$ nvm install node
  • 위와 같은 명령 실행 후 다시 $npm start를 하면 문제가 해결됨을 확인할 수 있다.

 

Step 2) Loading 화면 작성하기

  • 새파일 버튼을 눌러 Loading.js 컴포넌트를 추가한다.
  • 아래와 같이 코드를 작성한다. (Loading.js)
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
export default function Loading(){
 return (
  <View style={styles.container}>
    <Text style={styles.text}>Getting the weather</Text>
  </View>
 );
}
const styles = StyleSheet.create({
 container: {
   flex: 1, 
   justifyContent: "flex-end",
   paddingHorizontal: 30,
   paddingVertical: 100,
   backgroundColor: "#FDF6AA"
},
text :{
 color: "#2c2d2c",
 fontSize: 30
 }
});

 

 

(Loading.js)

 

 

  • App.js
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import Loading from "./Loading";
export default function App() {
  return <Loading />;
}

App.js

 

 

<결과 화면>

 

 

728x90
728x90

시작하기에 앞서,

모바일 어플리케이션을 개발하기 위해서 보통 Android app 개발자들은 ‘java’를 ios app 개발자들은 Swift 혹은 Objective-c를 이용한다. 그러나 동시에 Android와 iOS를 개발할 수 있는 방법이 있다고 한다.

 


React란?

- 사용자 인터페이스를 구축하기 위한 선언적이고 효율적이며 유연한 JavaScript 라이브러리이다. “컴포넌트”라고 불리는 작고 고립된 코드의 파편을 이용하여 복잡한 UI를 구성하도록 돕는다.

- 페이스북과 개별 개발자 및 기업들 공동체에 의해 유지 보수된다.

- 리액트는 싱글 페이지나 모바일 애플리케이션의 개발 시 토대로 사용될 수 있다. 복잡한 리액트 애플리케이션들은 상태 관리, 라우팅, API와의 통신을 위한 추가 라이브러리의 사용이 일반적으로 요구된다.

 -2011년 페이스북의 뉴스피드에 처음 적용되었다가 2012년 인스타그램에 적용되었다.

(출처 : 위키백과, https://ko.reactjs.org/tutorial/tutorial.html )

 

React-Native란?

React의 식으로 동시에 ios와 android 모바일 어플리케이션 개발을 할 수 있는 페이스북의 오픈 소스 프레임워크이다.

 

React-Native의 장점

JavaScript만을 이용해서 보다 쉽게 앱을 개발할 수 있기 때문에 개발 초보자인 나에게는 이 점이 큰 장점으로 다가왔다.

또한 코드를 작성하면서 실시간으로 그 결과를 확인할 수 있는 Live Reload 기능과 변환된 코드 부분만 렌더링해주는 Hot Reload 기능을 지원하며 컴파일 과정을 거치지 않아 빠른 속도로 개발을 진행할 수 있다.

 

React-Native의 단점

간단한 퍼포먼스를 구현하기에는 적합하지만 비즈니스 로직히 복잡해지거나 뷰 스택이 쌓일수록 속도가 느려진다.

잦은 업데이트로 모듈이 변경되어 갑자기 에러가 뜨는 상황이 생기고 바뀐 문법을 새로 적용해야 하는 경우가 있다.

 

 

 

728x90
728x90

이번 포스팅은

[React Native로 날씨앱 만들기 (by 노마드코더) ]

이란 강좌를 수강하기에 앞서 처음에 expo를 인스톨하는것부터 에러가 나는 바람에 이를 해결하는 방법을 포스팅해보았다.

 

 

 

Step 1) Nodejs 설치하기

nodejs.org/ko/download/

 

다운로드 | Node.js

Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine.

nodejs.org

 

사양에 맞게 다운로드를 한다.

  • node를 설치하면 npm은 default 로 설치된다.

 

Step 2) version 확인하기

$ node -v
$ npm -v

  • node는 12.13.0으로, npm은 6.12.0으로 설치되었음을 확인할 수 있다.

 

Step 3) expo cli 설치하기(에러 발생 단계)

$ npm install -g expo-cli

(Step 1 에서 다운을 받을 때 관리자암호를 입력하라는 창이 떴는데 그게 root 권한 permission을 요구한건가 싶다.)

 

Step 4) 기존에 설치된 node 삭제하기

$ sudo npm uninstall npm -g
  • 기존에 설치된 node는 root 권한으로 설치된 것이므로 uninstall 해준다.

 

Step 5) NVM(Node Version Manager) 설치하기

nvm은 root 권한 없이 node를 설치할 수 있게 해준다고 한다.

 

1. 설치하기

$ sudo curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.1/install.sh | bash

2. 확인하기

$ nvm ls

nvm ls를 터미널에 입력하면

-bash: nvm: command not found

위의 문장이 출력된다.

 

3. vi 에디터 열기

$ vi ~/.bash_profile
  • 빈 에디터에 아래의 문장을 복사해서 붙여넣은 후 :wq 로 저장하고 에디터를 나온다.
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" # This loads nvm

4. 재시작하기

$ source ~/.bash_profile

5. 다시 확인하기

$ nvm ls-
> system
iojs -> N/A (default)
node -> stable (-> N/A) (default)
unstable -> N/A (default)

터미널 캡쳐 화면

 

 

Step 6) node 재설치하기

1. 최신 버전 설치

$ nvm install 6.10.1

(2019년 10월 23일 기준으로 6.12.0이 최신버전이지만 참고한 링크에서 버전 6.10.1을 설치해서 필자도 6.10.1 버전을 설치해보았다.)

 

2. 확인하기

$ nvm ls
-> v6.10.1
system
default -> 6.10.1 (-> v6.10.1)
node -> stable (-> v6.10.1) (default)
stable -> 6.10 (-> v6.10.1) (default)
iojs -> N/A (default)
unstable -> N/A (default)
lts/* -> lts/erbium (-> N/A)
lts/argon -> v4.9.1 (-> N/A)
lts/boron -> v6.17.1 (-> N/A)
lts/carbon -> v8.16.2 (-> N/A)
lts/dubnium -> v10.16.3 (-> N/A)
lts/erbium -> v12.13.0 (-> N/A)

$ node -v
v6.10.1



 

 

Step 6) expo 설치

$ npm install -g expo-cli
  • Step 3 단계와는 달리 접근 오류가 뜨지 않고 성공적으로 설치되었다.

터미널 캡쳐 화면

 

 

 

 

728x90
728x90

출처 : 인프런_따라하며 배우는 노드, 리액트 시리즈 — 기본 강의

 

 

이번 시간에는 권한에 따라 페이지 접근 제한을 두기 위해 회원 인증 단계를 구현해보자.

페이지 접근은 다음과 같이 나눌 수 있다. 

 

 

페이지 접근 뿐 아니라 댓글 작성, 파일 전송 및 업로드 등에 관련해서도 인증 과정이 필요하다.

 

들어갈 수 있는 페이지에 대한 관리는 HOC를 쓸 것이다.

 

HOC이란?

-function으로서 다른 컴포넌트를 받아 새로운 컴포넌트를 리턴한다.

 

 

 

Auth 컴포넌트는 backend에 request를 날리고 상태를 가져올 것이다. 

 

우리가 가지고 있는 페이지(LandingPage, LoginPage, RegisterPage)를 모두 Auth 에 넣은 다음 Auth에서 처리를 하는 방식이다.

 

예를 들어 LandingPage를 넣으면 Auth는 Backend에 Request를 날린다. 현재 LandingPage에 들어와있는 사람의 상태 정보(로그인이 되어 있는지 아닌지, Admin인지 아닌지 등)를 Auth로 가져온다. 

 

 

 

Step 1) 클라이언트는 서버쪽으로 요청을 보낸다. 

 

/client/src/components/views/hoc/auth.js 파일을 새로 생성한 뒤 아래와 같이 작성한다.

여기서 서버쪽의 API로 request를 보낼 것이다. 보내기 위해 redux를 사용했다.  dispatch로 action(action이름은 auth)을 날리자. 

 

페이지가 이동할 때마다 dispatch로 계속 서버에 request를 주고 있는 것이다. 

 

파라미터 설명

- SpecificComponent : LandingPage

- option : null (아무나 출입 가능한 페이지) , true(로그인한 유저만 출입 가능), false(로그인한 유저 출입 불가능)

- adminRoute : true(관리자만 들어갈 수 있는 페이지)

import React, {useEffect} from 'react';
import axios from 'axios';
import {useDispatch} from 'react-redux'
import {auth} from '../_actions/user_action'
export default function (SpecificComponent, option, adminRoute = null){


    function AuthenticationCheck(props){

        const dispatch = useDispatch();

        useEffect(() => {
            
            dispatch(auth()).then(response => { //backend에서 처리한 정보들이 response안에 다 들어있음 
                console.log(response)
            })
            
        }, [])
        
         return (
            <SpecificComponent/>
        )
        
    }


    return AuthenticationCheck
}

 

 

Step 2) 서버에서는 미들웨어로 이동 

 

 

서버 쪽에 구현해놓은 API 를 보자.

index.js에 이미 구현해놓았다. 

get request로 요청을 받으면 미들웨어 auth가

여기로 그 요청이 넘어온다.  여기서는 토큰을 사용해서 쿠키 안에 토큰을 집어 넣는다. 그 쿠키를 보고 로그인 한 유저인지 아닌지를 판단하고 그 결과를 리액트에 넘겨준다. 

 

 

 

Step 1)-1 Action 구현

 

그리고 user_action.js에도 아래와 같이 인증 기능을 하는 함수를 추가해준다.

export function auth() {

    const request = Axios.get('/api/users/auth')        //endpoint로 get request , get이니까 login과 다르게 get 이니까 body 파라미터 필요 없음 
        .then(response => response.data)                     


        return {                    //Action 했으니까 이제 Reducer로 보냄
            type: AUTH_USER,
            payload: request
        }
    

}

 

 

Step 1)-2 Reducer 구현

 

action에 따라 결과를 리턴해주는 곳이다. AUTH_USER 케이스를 추가해준다. 

import { 
    LOGIN_USER, REGISTER_USER, AUTH_USER
} from '../_actions/types';


export default function (state={}, action){  //state 는 이전 상태 

    switch(action.type){        //Action에는 여러 타입 존재함. 이 타입에 따라 다르게 반응하도록 작성
        case LOGIN_USER:
            return {...state, loginSuccess: action.payload}       //... : spread operator은 파라미터 state를 그대로 가져온 것으로 빈 상태를 의미 
            break;

        case REGISTER_USER:
            return { ...state, register: action.payload}
            break;

        case AUTH_USER:
        return { ...state, userData: action.payload}
        break;

        default:
            return state;

    }

}

 

 

 

Step 4) 컴포넌트를 Auth HOC에 넣기

 각 컴포넌트를 Auth로 감싸주고 파라미터를 지정해서 넘겨준다. 파라미터 설명은 Step1) 에 기재했다. 

import React from 'react'

import {
  BrowserRouter as Router,
  Switch,
  Route,
  // eslint-disable-next-line
  Link  
} from "react-router-dom"; 



import LandingPage from './components/views/LandingPage/LandingPage';
import LoginPage from './components/views/LoginPage/LoginPage';
import RegisterPage from './components/views/RegisterPage/RegisterPage';
import Auth from './hoc/auth'

function App() {
  return (
    <Router>
      <div>
         
        {/*
          A <Switch> looks through all its children <Route>
          elements and renders the first one whose path
          matches the current URL. Use a <Switch> any time
          you have multiple routes, but you want only one
          of them to render at a time
        */}


{         /* 로그인한 유저는 로그인 페이지에 못들어감 */}
        <Switch>
          <Route exact path="/" component={Auth(LandingPage, null)} />
          <Route exact path="/login" component={Auth(LoginPage, false)} />  
          <Route exact path="/register" component={Auth(RegisterPage, false)} />
        </Switch>
      </div>
    </Router> 
  );
} 

export default App;


 

 

 

Step 5) 기능 확인하기

 

이제 실행해서 결과를 확인해보자.

 

1) 로그인 전 LandingPage

 

 

2)로그인 페이지 

isAuth 가 false이다. 

 

 

3) 로그인 후 LandingPage

 

 

3) 로그아웃 후 로그인 페이지 

 

 

 

 

 

Step 6) 페이지 접근 관리하기

위에 있는 payload.isAuth는 로그인 된 상태이고 아래 있는 payload.isAuth는 로그아웃된 상태이다. 각각 true, false 이므로 이에 맞게 코드를 작성하자. 

 

 

auth.js를 다음과 같이 수정해서 로그인 한 사람은 로그인 페이지나 회원가입 페이지에 접근하지 못하도록 하는 등 페이지 접근을 관리한다. 

import React, {useEffect} from 'react';
import axios from 'axios';
import {useDispatch} from 'react-redux'
import {auth} from '../_actions/user_action'
export default function (SpecificComponent, option, adminRoute = null){


    function AuthenticationCheck(props){

        const dispatch = useDispatch();

        useEffect(() => {
                    //auth는 action이름 
            dispatch(auth()).then(response => { //backend에서 처리한 정보들이 response안에 다 들어있음 
                console.log(response)


                //로그인 하지 않은 상태인데 
                if(!response.payload.isAuth) {  //option이 true이면 즉 로그인 된 유저만 들어갈 수 있어야하면 
                    if(option){
                        props.history.push('/login')
                    }
                } else{ //로그인 된 상태인데 
                    if(adminRoute && !response.payload.isAdmin){
                        props.history.push('/')
                    }
                    else{
                        if(option===false){ //option이 false면 로그인한 유저는 출입 불가능함. 로그인 페이지 or 회원가입 페이지
                            props.history.push('/')
                        }
                    } 
                }

            })
            
        }, [])

        return (
            <SpecificComponent/>
        )
    }


    return AuthenticationCheck
}

 

 

 

 

 

 

참고) 

Page 이동에 사용되는 history는 react-router-dom을 이용해서 쓰고 있는 것임. 

withRouter 로

export default withRouter(LandingPage)

코드 맨 아래에 위와 같이 처리를 해줘야 오류가 안 난다. 

 

 

 

 

 

 

 

 

여기까지 리엑트 노드를 이용한 로그인, 로그아웃, 회원가입 페이지 구현을 해 보았다.

 

직접 코드를 작성하면서 웹사이트 구현을 위한 기초를 다질 수 있었고, 이를 통해 서버 및 클라이언트의 전체적인 동작 원리 및 흐름과 MongoDB 사용법 또한 익힐 수 있었다. 

728x90
728x90

출처 : 인프런_따라하며 배우는 노드, 리액트 시리즈 — 기본 강의

 

Step 1) 회원가입 페이지 구현

 

client/src/components/views/RegisterPage/RegisterPage.js

 

import React, { useState } from 'react'
import {useDispatch} from 'react-redux';
import {loginUser} from '../../../_actions/user_action'
import {registerUser} from '../../../_actions/user_action'
import { withRouter} from 'react-router-dom'

function RegisterPage(props) {


    const dispatch = useDispatch();

    const [Email, setEmail] = React.useState(" ")
    const [Password, setPassword] = React.useState(" ")
    const [Name, setName] = React.useState(" ")
    const [ConfirmPassword, setConfirmPassword] = React.useState(" ")

    const onEmailHandler = (event) => {
        setEmail(event.currentTarget.value)
    }

    const onNameHandler = (event) => {
        setName(event.currentTarget.value)
    }

    const onPasswordHandler = (event) => {
        setPassword(event.currentTarget.value)
    }
    const onConfirmPasswordHandler = (event) => {
        setConfirmPassword(event.currentTarget.value)
    }


    const onSubmitHandler = (event) => {
        event.preventDefault(); //리프레시 방지-> 방지해야 이 아래 라인의 코드들 실행 가능 

        // console.log('Email', Email);
        // console.log('Password', Password);

        //비밀번호와 비밀번호 확인 같을띠 회원가입 되게 함
        if(Password !== ConfirmPassword){
            return alert('비밀번호와 비밀번호 확인은 같아야 합니다.')
        }   //여기서 걸리면 아래로 못감 



        let body={
            email: Email,
            password: Password,
            name: Name
        }


    //디스패치로 액션 취하기
    dispatch(registerUser(body))
    .then(response => {
        if(response.payload.success) {
            props.history.push('/login')
        } else {
            alert('Failed to sign up')
        }
        
    })


    
    }



    return (
        <div style={{
            display: 'flex', justifyContent: 'center', alignItems: 'center',
            width: '100%', height: '100vh'
        }}>
            
            
            <form style={{display: 'flex', flexDirection: 'column'}}
                onSubmit={onSubmitHandler}
            >

                <label>Email</label>
                <input type="email" value={Email} onChange={onEmailHandler}/>   
                
                <label>Name</label>
                <input type="text" value={Name} onChange={onNameHandler}/>


                <label>Password</label>
                <input type="password" value={Password} onChange={onPasswordHandler}/>
                
                <label>Confirm Password</label>
                <input type="password" value={ConfirmPassword} onChange={onConfirmPasswordHandler}/>

                <br />
                <button>
                    회원 가입 
                </button>
            </form>

        </div>
    )
}

//export default RegisterPage


export default withRouter(RegisterPage)

 

 

 

 

Step 2) Action 기능 구현

import Axios from 'axios';
import {
    LOGIN_USER, REGISTER_USER
} from './types';


export function loginUser(dataTosubmit) {

    const request = Axios.post('/api/users/login', dataTosubmit)        //서버에 리퀘스트 날리고 
        .then(response => response.data)                     //받은 데이터를 request에 저장


        return {                    //Action 했으니까 이제 Reducer로 보냄
            type: LOGIN_USER,
            payload: request
        }
    

}


export function registerUser(dataTosubmit) {

    const request = Axios.post('/api/users/register', dataTosubmit)        //서버에 리퀘스트 날리고 
        .then(response => response.data)                     //받은 데이터를 request에 저장


        return {                    //Action 했으니까 이제 Reducer로 보냄
            type: REGISTER_USER,
            payload: request
        }
    

}


 

 

 

Step 3) type 지정

//action의 타입들만 관리하는 파일
export const LOGIN_USER = "login_user";
export const REGISTER_USER = "register_user";

 

 

Step 4) Reducer 작성

 

user_reducer.js

import { LOGIN_USER, REGISTER_USER } from '../_actions/types';


export default function(state={}, action){  //state 는 이전 상태 

    switch(action.type){        //Action에는 여러 타입 존재함. 이 타입에 따라 다르게 반응하도록 작성
        case LOGIN_USER:
            return {...state, loginSuccess: action.payload}       //... : spread operator은 파라미터 state를 그대로 가져온 것으로 빈 상태를 의미 
            break;

        case REGISTER_USER:
            return { ... state, register: action.payload}
            break;

        default:
            return state;

    }

}

 

 

 

구현이 완료됐으니 회원가입을 해보자. 성공한 것을 볼 수 있다.

 

 

 

728x90
728x90

출처 : 인프런_따라하며 배우는 노드, 리액트 시리즈 — 기본 강의

 

Step 1) 시작 페이지 화면 구성

 

LandingPage.js 화면 구성하기 

div 태그 안에 style을 지정해주자.

import React, {useEffect} from 'react'
import axios from 'axios';

 function LandingPage(){//Functional Component 만들기
     
    
    useEffect(() => {
        axios.get('/api/hello')      //endpoint. getRequest를 server 즉 index.js로 보내질 것
        .then(response => {console.log(response)})   //server 에서 돌아온 response를 콘솔창에 출력해봄
    }, [])
    
    
    return(
         <div style={{
             display: 'flex', justifyContent: 'center', alignItems: 'center',
             width: '100%', height: '100vh'
         }}>
          
          <h2> 시작 페이지 </h2>
          


         </div>
     )
 }

 export default LandingPage

 

 

 

그럼 첫 시작 화면이 아래와 같이 뜬다.

 

 

 

 

Step 2) 로그인 페이지 작성

 

onChange에 함수를 지정해줌으로써 이메일이나 비밀번호를 입력할 때, 실시간으로 state가 변하게 해준다. 

 

 

//client/src/components/views/LoginPage/LoginPage.js


import React, { useState } from 'react'
import Axios from 'axios'
import {useDispatch} from 'react-redux';
import {loginUser} from '../../../_actions/user_action'

function LoginPage(props) {     //파라미터로 props 넣어줘야함! 로그인 완료된 후 처음 화면으로 돌아가게 하기 위함 

    const dispatch = useDispatch();

    const [Email, setEmail] = React.useState(" ")
    const [Password, setPassword] = React.useState(" ")

    const onEmailHandler = (event) => {
        setEmail(event.currentTarget.value)
    }
    
    const onPasswordHandler = (event) => {
        setPassword(event.currentTarget.value)
    }

    const onSubmitHandler = (event) => {
        event.preventDefault(); //리프레시 방지-> 방지해야 이 아래 라인의 코드들 실행 가능 

        // console.log('Email', Email);
        // console.log('Password', Password);


        let body={
            email: Email,
            password: Password
        }

        //디스패치로 액션 취하기
        dispatch(loginUser(body))
        .then(response => {
            if(response.payload.loginSuccess) {
                props.history.push('/')             //리액트에서 페이지 이동하기 위해서는 props.history.push() 이용.
               										// 로그인 완료된 후 처음 화면(루트 페이지-landingpage로)으로 돌악가게 하기 
            } else{
                alert(' Error')
            }
        })


        
    }

    return (
        <div style={{
            display: 'flex', justifyContent: 'center', alignItems: 'center',
            width: '100%', height: '100vh'
        }}>
            
            
            <form style={{display: 'flex', flexDirection: 'column'}}
                onSubmit={onSubmitHandler}
            >

                <label>Email</label>
                <input type="email" value={Email} onChange={onEmailHandler}/>   
                <label>Password</label>
                <input type="password" value={Password} onChange={onPasswordHandler}/>

                <br />
                <button>
                    Login
                </button>
            </form>

        </div>
    )
}

export default LoginPage

 

 

 

Step 3) Action 기능 구현 

Login버튼을 누르면 디스패치가 action을 수행할 수 있도록 기능을 구현한다. 그 기능들은 _action/user_action.js 를 새로 생성해서 아래와 같이 코드를 작성하자. 

- Server 에 보낼 때 Axios.post() 를 이용한다. 

//client/src/_actions/user_action.js

import Axios from 'axios';
import {
    LOGIN_USER
} from './types'
export function loginUser(dataTosubmit) {

    const request = Axios.post('/api/users/login', dataTosubmit)        //서버에 리퀘스트 날리고 
        .then(response => response.data)                     //받은 데이터를 request에 저장


        return {                    //Action 했으니까 이제 Reducer로 보냄
            type: LOGIN_USER,
            payload: request
        }
    

}

 

 

 

Step 4) Reducer 기능 구현 

 

이 다음은 Reducer 차례로, (previousState, action) 을 받아서 nextState를 리턴해주는 역할을 할것이다.

 

 

Action의 여러가지 type들을 쉽게 관리하기 위해 client/src/_actions/types.js파일을 새로 만들어서 아래와 같이 코드를 작성한다.

//action의 타입들만 관리하는 파일
export const LOGIN_USER = "login_user";
 

 

 

 

그리고 client/src/_reducers/user_reducer.js 파일도 아래와 같이 작성해준다.

import { LOGIN_USER } from '../_actions/types';


export default function(state={}, action){  //state 는 이전 상태 

    switch(action.type){        //Action에는 여러 타입 존재함. 이 타입에 따라 다르게 반응하도록 작성
        case LOGIN_USER:
            return {...state, loginSuccess: action.payload}       //... : spread operator은 파라미터 state를 그대로 가져온 것으로 빈 상태를 의미 
            break;

        default:
            return state;

    }

}

 

 

 

로그인 결과 화면 

 

MongoDB에 저장해놓은 데이터에 맞게 로그인 시도를 했는데 로그인에 실패했다.

 

터미널을 보니 아래와 같은 메세지가 떠서 구글링해보았다.

message: "Could not connect to any servers in your MongoDB Atlas cluster. One common reason is that you're trying to access the database from an IP that isn't whitelisted. Make sure your current IP address is on your Atlas cluster's IP whitelist:docs.atlas.mongodb.com/security-whitelist/",

 

 

아래 사이트를 참고해서 Network Access 문제를 해결했다. 처음 MongoDB에 접속했던 곳과 다른 곳에서 접속해서 IP 주소가 달라져서 접근 문제가 있는 것 같았다. 

 

stackoverflow.com/questions/62859081/error-could-not-connect-to-any-servers-in-your-mongodb-atlas-cluster

 

Error : “Could not connect to any servers in your MongoDB Atlas cluster”

i have a issue that i tried to fix it for a long time. i try to connect to mongo atlas cloud from nodejs with mongoose npm. now, its not my first time but i just can't find the answer my mongoose v...

stackoverflow.com

 

그러나 문제는 해결되지 않았고 포트번호를 이미 쓰고 있어서 오류가 난것이었다.

위와 같이 터미널에서 kill을 해주니 정상적으로 로그인이 된 것을 확인할 수 있었다.

 

 

로그인에 성공했고 시작페이지로 돌아갔다.

 

 

 

 

 

728x90

+ Recent posts