웹/Node.js & React.js

[React.js] 리액트를 이용해서 회원가입 페이지 만들기

팽팽 2022. 2. 13. 15:10

- React는 module과 비슷한 component로 이루어지고 재사용이 뛰어남

- Virtual DOM

: RealDOM : 한 부분이 바뀌어도 전체 리스트를 reload 해야 함 

: Virtual DOM : 한 부분이 바뀌어도 바뀐 부분 리스트만 update 해도 됨, snapshot을 이용해서 바뀐 부분을 관찰함

- create-react-app으로 리액트 시작

: 원래 리액트 앱을 처음 실행 하기 위해선 webpack이나 babel을 설정해야함

: babel - 최신 자바스크립트 문법을 지원하지 않는 브라우저들을 위해서 최신 자바스크립트 문법을 구형 브라우저에서도 돌수있게 변형시켜줌

: webpack - webpack을 이용해서 bundle화

- npx create-react-app . 

: 원래 npm을 이용하여 다운받을 때는 global 디렉토리에 다운받았음

: npx는 npm registry에서 create-react-app을 찾아서 다운로드 없이 실행시켜줌, disk space를 낭비하지 않고

항상 최신 버전을 사용할 수 있음

- 페이지 이동을 할때 React Router Dom을 사용함 

- 폴더별로 나누어 관리

App.js

- react-router-dom v6 버전에서 Switch 대신 Routes 사용

- 랜딩시키고자 하는 페이지들을 폴더별로 분류한 후 import해서 사용함

import './App.css';
import React from 'react'

import {
  BrowserRouter as Router,
  Routes,
  Route,
  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';

function App() {
  return (
    <Router>
    <div>
    <Routes>

      <Route path="/register" element={<RegisterPage />}/>
      <Route path="/login" element={<LoginPage />} />
      <Route path="/" element={<LandingPage />} />
    </Routes>
      
    </div>
  </Router>
  );
}



export default App;

 

LandingPage/LandingPage.js

- 다른 페이지도 같은 방식으로 구성됨

import React from 'react'

function LandingPage() {
    return (
    <div>
        LandingPage 랜딩페이지
    </div>
    )
}

export default LandingPage

<server -client 통신 test>

- Axios install

server/index.js

app.get('/api/hello', (req, res) => {

    res.send("안녕하세요 ~ ")
})

client : LandingPage/LandingPage.js

- 랜딩페이지 : react 키자마자 띄워지는 창 

import React, {useEffect} from 'react'
import axios from 'axios'
import { response } from 'express'

function LandingPage() {
    //랜딩페이지에 들어오자마자 실행 get request
    useEffect(() => {
        axios.get('/api/hello') //서버에 보냄
        .then(response => console.log(response.data)) //서버에서 돌아오면 콘솔창에 받은것을 보여줌


    })
    return (
    <div>
        LandingPage 랜딩페이지
    </div>
    )
}

export default LandingPage

- 하지만! client와 server의 port번호가 다른데, 이는 Crocs 정책 때문에 통신이 불가능하다.

- 만약 다른곳(port번호 다름)에서 request가 들어오면 crocs 보안 정책 때문에 request를 받을 수 없다.

- 해결하는 방법은 다양하지만 , 여기서는 proxy방식을 이용함!

- npm install http-proxy-middleware --save

src/setupProxy.js

- 서버 port : 5000번

- 클라이언트 port : 3000번

- 3000번 포트에서 오는 req을 5000번 서버가 받도록 함

const { createProxyMiddleware }= require('http-proxy-middleware');
module.exports = function(app) {
    app.use(
        '/api',
        createProxyMiddleware({
            target: 'http://localhost:5000',
            changeOrigin:true,
        })
    )
}

client/LandingPage.js

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

function LandingPage() {
    //랜딩페이지에 들어오자마자 실행 get request
    useEffect(() => {
        axios.get('/api/hello') //서버에 보냄
        .then(response => console.log(response)) //서버에서 돌아오면 콘솔창에 받은것을 보여줌


    }, [])
    return (
    <div>
        LandingPage 랜딩페이지
    </div>
    )
}

export default LandingPage

server/index.js

- 서버가 /api/hello에서 req을 받으면 res로 해당 문장을 출력함

app.get('/api/hello', (req, res) => {

    res.send("안녕하세요 ~ ") //프론트로 responese 보냄
})

<Proxy Server>

<Concurrency 로 서버랑 프론트 한번에 켜기>

- 지금까지는 2개의 터미널에 따로 따로 켰음..

- npm install concurrently

- package.json 파일에 다음 값 입력하기

    "dev":"concurrently \"npm run backend\" \"npm run start --prefix client\""

<CSS Framework>

- 여러개 있지만, Ant Design 사용 예정

- install antd


<Redux>

- 상태 관련 라이브러리

- Props

property의 줄임말

컴포넌트 간 주고 받을때는 prop이용
부모 컴포넌트에서 자식 컴포넌트로 보낼수 있음
props는 변할 수 없음(변경하고 싶으면 부모에서 바꿔서 받아야함)

- State

부모 컴포넌트에서 자식에 전달하지 않음

컴노넌트 안에서 데이터를 전달 교환하려면 state쓰기
컴포넌트 안에서 state변하게 할 수 있음

훨씬 편한 state 관리
한방향으로만 흐름

- action은 무엇이 일어났는지 설명하는 객체 ( 상태를 알려줌 )

- reducer는 이전 state과 acton 객체를 받아, 변한 state를 리턴함

- store는 appplication의 state을 감싸주는 역할

- store안 여러 method 이용해 state을 관리함

- store의 state을 변경하고 싶으면 dispatch이용해서 action으로 변경시킴

- action은 객체 형식으로만 받는게 아니라 promise, function 형식으로 받을 수 있는데, redux-thunk, redux-promise

이용해서 받게 됨 (미들웨어)

client/index.js

- redux 와 react를 연결

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

import { Provider} from 'react-redux';
import 'antd/dist/antd.css';
import { applyMiddleware, createStore} from 'redux';
import promiseMiddleware from 'redux-promise';
import ReduxThunk from 'redux-thunk'
import Reducer from './_reducers'

//미들웨어 연결(promise, functions)
const createStoreWithMiddleware = applyMiddleware(promiseMiddleware,ReduxThunk)(createStore)


ReactDOM.render(
  <Provider
    store={createStoreWithMiddleware(Reducer,
      
      window.__REDUX_DEVTOOLS_EXTENSION__ && //툴이용해서 redux 편리하게 이용하기 위함
      window.__REDUX_DEVTOOLS_EXTENSION__()
      )}
  
  >
    <App />
  </Provider>,
  document.getElementById('root')
);

reportWebVitals();

_reducers/index.js

- combineReducer

: reducer는 state에 따라 여러가지로 나뉠 수 있다. 예를 들어 User Reducer, Post Reducer, Number Reducer .. 등등

모두 combineReduce 이용해서 하나로 합쳐주기

- reducer마다 폴더를 만들고 그 안에 파일을 만들어 import하면 됨

import { combineReducers } from 'redux';
import user from './user_reducer';
//import comment from './comment_reducer';

const rootReducer = combineReducers({
    user,
    //comment
})

export default rootReducer;

- funtional component 는 간단하고 빠르지만 대신 한계가 많음

- React Hooks 발표! functional component에서도 한계를 극복하게 됨