0. 사전준비 사항


메일 발송하는 계정은 테스트 계정으로 새로 만들어서 테스트 하시는것을 추천합니다.

1) 보안 수준이 낮은 앱 엑세스 허용

보안 수준이 낮은 앱 허용을 해줘야 테스트 하는 어플리케이션에서 메일 발송이 가능합니다.

 

아래 URL을 클릭하시면 로그인 되어있는 계정으로 바로 설정 가능합니다.

 

https://myaccount.google.com/lesssecureapps

2) 내 Google 계정에 대한 액세스 허용

내 Google 계정에 대한 액세스 허용화면에서 계속 버튼을 클릭 해줍니다.

 

 

아래 URL을 클릭하시면 로그인 되어있는 계정으로 바로 설정 가능합니다.

https://accounts.google.com/DisplayUnlockCaptcha

1. nodemailer 모듈


nodemailer는 node 서버에서 메일을 보낼 수 있는 메일 전송 모듈입니다. 사용법이 간편하다는 장점이 있습니다.

nodemailer 공식문서는 하단 URL을 참고해주세요

https://nodemailer.com/about/

npm을 사용하시는 분들은 npm install nodemailer --save yarn을 사용하시는 분들은
yarn add nodemailer 명령으로 설치 가능합니다.

2. nodemailer을 이용한 발송 코드


1) nodemailer 발송 모듈

// nodemailer 모듈 요청
var nodemailer = require('nodemailer');

// 메일발송 객체
var mailSender = {
    // 메일발송 함수
    sendGmail : function(param){
        var transporter = nodemailer.createTransport({
            service: 'gmail'
            ,prot : 587
            ,host :'smtp.gmlail.com'
            ,secure : false
            ,requireTLS : true
            , auth: {
              user: '발송할 메일@gmail.com'
              ,pass: '패스워드'
            }
        });
        // 메일 옵션
        var mailOptions = {
                from: '발송할 메일@gmail.com',
                to: param.toEmail, // 수신할 이메일
                subject: param.subject, // 메일 제목
                text: param.text // 메일 내용
            };
        // 메일 발송    
        transporter.sendMail(mailOptions, function(error, info){
            if (error) {
            console.log(error);
            } else {
            console.log('Email sent: ' + info.response);
            }
        });

    }
}
// 메일객체 exports
module.exports = mailSender;

2) 메일 발송 함수 사용

let emailParam = {
    toEmail : loginId
    ,subject  : '메일 제목'
    ,text : '메일 내용'
};
mail.sendGmail(emailParam);

3.관련 오류

0. 사전 준비 사항을 하지 않아서 발생한 오류입니다.

Error: Invalid login: 535-5.7.8 Username and Password not accepted. Learn more at

2019-06-02T07:31:57.851494+00:00 app[web.1]: { Error: Invalid login: 535-5.7.8 Username and Password not accepted. Learn more at
2019-06-02T07:31:57.851514+00:00 app[web.1]: 535 5.7.8  https://support.google.com/mail/?p=BadCredentials n7sm6847779qkd.53 - gsmtp
2019-06-02T07:31:57.851516+00:00 app[web.1]: at SMTPConnection._formatError (/app/node_modules/nodemailer/lib/smtp-connection/index.js:781:19)
2019-06-02T07:31:57.851518+00:00 app[web.1]: at SMTPConnection._actionAUTHComplete (/app/node_modules/nodemailer/lib/smtp-connection/index.js:1516:34)
2019-06-02T07:31:57.851520+00:00 app[web.1]: at SMTPConnection._responseActions.push.str (/app/node_modules/nodemailer/lib/smtp-connection/index.js:554:26)
2019-06-02T07:31:57.851522+00:00 app[web.1]: at SMTPConnection._processResponse (/app/node_modules/nodemailer/lib/smtp-connection/index.js:940:20)essResponse (/app/node_modules/nodemailer/lib/smtp-connection/index.ta (/app/node_modules/nodemailer/lib/smtp-connection/index.js:746:14)js:940:20)                                                          tion._onSocketData (/app/node_modules/nodemailer/lib/smtp-connection/index.js:189:46)
2019-06-02T07:31:57.851524+00:00 app[web.1]: at SMTPConnection._onDats.js:198:13)ta (/app/node_modules/nodemailer/lib/smtp-connection/index.js:746:14adable.js:288:12))                                                                   tream_readable.js:269:11)
2019-06-02T07:31:57.851526+00:00 app[web.1]: at TLSSocket.SMTPConnecush (_stream_readable.js:224:10)tion._onSocketData (/app/node_modules/nodemailer/lib/smtp-connection [as onread] (internal/stream_base_commons.js:94:17)/index.js:189:46)
2019-06-02T07:31:57.851528+00:00 app[web.1]: at TLSSocket.emit (events.js:198:13)                                                        Password not accepted. Learn more at\n535 5.7.8  https://support.google.com/mail/?p=BadCredentials n7sm6842019-06-02T07:31:57.851530+00:00 app[web.1]: at addChunk (_stream_readable.js:288:12)
2019-06-02T07:31:57.851533+00:00 app[web.1]: at readableAddChunk (_stream_readable.js:269:11)
2019-06-02T07:31:57.851535+00:00 app[web.1]: at TLSSocket.Readable.push (_stream_readable.js:224:10)
2019-06-02T07:31:57.851537+00:00 app[web.1]: at TLSWrap.onStreamRead [as onread] (internal/stream_base_commons.js:94:17)
2019-06-02T07:31:57.851540+00:00 app[web.1]: code: 'EAUTH',
2019-06-02T07:31:57.851542+00:00 app[web.1]: response:
2019-06-02T07:31:57.851545+00:00 app[web.1]: '535-5.7.8 Username and Password not accepted. Learn more at\n535 5.7.8  https://support.google.com/mail/?p=BadCredentials n7sm6847779qkd.53 - gsmtp',
2019-06-02T07:31:57.851547+00:00 app[web.1]: responseCode: 535,
2019-06-02T07:31:57.851549+00:00 app[web.1]: command: 'AUTH PLAIN' }

Error: Invalid login: 534-5.7.14 ...

2019-06-02T08:43:58.332064+00:00 app[web.1]: { Error: Invalid login: 534-5.7.14 <https://accounts.google.com/signin/continue?sarp=1&scc=1&plt=AKgnsbtx
2019-06-02T08:43:58.332078+00:00 app[web.1]: 534-5.7.14 eGlXewx2NWs2Zu-3kdbaSLCHppRwhG4UkU5oG1lS7Tz0CAbeu2Y16L6sCdjSCqUtjye2TW
2019-06-02T08:43:58.332081+00:00 app[web.1]: 534-5.7.14 QvrjSZZGajjBg8AB6CE4l49G2Rn5Voeky6d1T81hhfx8RkcRI6dmf1nDBbYr7U> Please
2019-06-02T08:43:58.332084+00:00 app[web.1]: 534-5.7.14 log in via your web browser and then try again.
2019-06-02T08:43:58.332086+00:00 app[web.1]: 534-5.7.14  Learn more at
2019-06-02T08:43:58.332088+00:00 app[web.1]: 534 5.7.14  https://support.google.com/mail/answer/78754 a6sm2076445qkn.14 - gsmtp
2019-06-02T08:43:58.332090+00:00 app[web.1]: at SMTPConnection._formatError (/app/node_modules/nodemailer/lib/smtp-connection/index.js:781:19)
2019-06-02T08:43:58.332092+00:00 app[web.1]: at SMTPConnection._actionAUTHComplete (/app/node_modules/nodemailer/lib/smtp-connection/index.js:1516:34)
2019-06-02T08:43:58.332095+00:00 app[web.1]: at SMTPConnection._responseActions.push.str (/app/node_modules/nodemailer/lib/smtp-connection/index.js:554:26)
2019-06-02T08:43:58.332098+00:00 app[web.1]: at SMTPConnection._processResponse (/app/node_modules/nodemailer/lib/smtp-connection/index.js:940:20)
2019-06-02T08:43:58.332100+00:00 app[web.1]: at SMTPConnection._onData (/app/node_modules/nodemailer/lib/smtp-connection/index.js:746:14)
2019-06-02T08:43:58.332102+00:00 app[web.1]: at TLSSocket.SMTPConnection._onSocketData (/app/node_modules/nodemailer/lib/smtp-connection/index.js:189:46)
2019-06-02T08:43:58.332104+00:00 app[web.1]: at TLSSocket.emit (events.js:198:13)
2019-06-02T08:43:58.332106+00:00 app[web.1]: at addChunk (_stream_readable.js:288:12)
2019-06-02T08:43:58.332109+00:00 app[web.1]: at readableAddChunk (_stream_readable.js:269:11)
2019-06-02T08:43:58.332111+00:00 app[web.1]: at TLSSocket.Readable.push (_stream_readable.js:224:10)
2019-06-02T08:43:58.332113+00:00 app[web.1]: at TLSWrap.onStreamRead [as onread] (internal/stream_base_commons.js:94:17)
2019-06-02T08:43:58.332115+00:00 app[web.1]: code: 'EAUTH',
2019-06-02T08:43:58.332118+00:00 app[web.1]: response:
2019-06-02T08:43:58.332123+00:00 app[web.1]: '534-5.7.14 <https://accounts.google.com/signin/continue?sarp=1&scc=1&plt=AKgnsbtx\n534-5.7.14 eGlXewx2NWs2Zu-3kdbaSLCHppRwhG4UkU5oG1lS7Tz0CAbeu2Y16L6sCdjSCqUtjye2TW\n534-5.7.14 QvrjSZZGajjBg8AB6CE4l49G2Rn5Voeky6d1T81hhfx8RkcRI6dmf1nDBbYr7U> Please\n534-5.7.14 log in via your web browser and then try again.\n534-5.7.14  Learn more at\n534 5.7.14  https://support.google.com/mail/answer/78754 a6sm2076445qkn.14 - gsmtp',
2019-06-02T08:43:58.332126+00:00 app[web.1]: responseCode: 534,
2019-06-02T08:43:58.332128+00:00 app[web.1]: command: 'AUTH PLAIN' }

'언어 > NodeJS' 카테고리의 다른 글

Express를 이용한 NodeJS 웹서버 구축  (0) 2018.12.07

리덕스 개념


리덕스?

리액트의 상태를 더 효율적으로 관리하는 데 사용하는 상태 관리 라이브러리로 상태 관리의 로직을 컴포넌트 밖에서 처리합니다.

리액트에서 사용하려고 만든 라이브러리지만, 리액트에 의존하지 않기때문에 리액트를 사용하지 않아도 리덕스 사용 가능 합니다.


리덕스 관련 용어
1) 스토어 : 애플리케이션의 상태 값들을 내장
2) 액션 : 상태 변화를 일으킬 때 참조하는 객체로 반드시 type을 가져야 함
3) 디스패치 : 액션을 스토어에 전달하는 것
4) 리듀서 : 상태를 변화시키는 로직이 있는 함수
5) 구독 : 스토어 값이 필요한 컴포넌트는 스토어를 구독

그림으로 표현하면 아래와 같습니다.

리덕스 규칙

리덕스 공식 메뉴얼에서도 안내하는 규칙 세가지가 있습니다.


1) 스토어는 단 한개만 존재

2) state는 읽기 전용

3) 변화는 순수 함수로 구성





리덕스 사용

리덕스 실습은 JSBin 사이트를 활용해서 리액트 환경이 아닌 환경에서 실습을 진행 했습니다.

1) HTML에 Redux 관련 <script>태그 추가

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/3.6.0/redux.js"></script>
</body>
</html>


2) console.log로 Redux 확인


아래와 같은 명령을 실행하면 정상적으로 추가했는지 확인 가능합니다.

console.log(Redux);


콘솔창 결과



3) action 추가


실습에서는 증가와 감소 액션을 만들어서 사용 했습니다.


const INCREMENT = 'INCREMENT';
const DECREMENT = 'DECREMENT';

const increment = (diff) => ({
type : INCREMENT
,diff : diff
});
const decrement = (diff) => ({
type : DECREMENT
,diff : diff
});


4) 리듀서 추가


리듀서는 변화를 일으키는 함수로 본 실습에서는 실질적으로 증·감하는 역할을 합니다.


state값을 초기화하는 함수도 같이 추가 했습니다.


const initialState = {
number : 0
};

function counter(state = initialState, action){
switch(action.type){
case INCREMENT:
return {number:state.number + action.diff};
case DECREMENT:
return {number:state.number - action.diff};
default :
return state;
}
}


5) 스토어 생성


파라미터로 리듀서를 넘겨줍니다.


const {createStore} = Redux;

const store = createStore(counter);


6) 구독

리액트에서 구독하는 작업은 react-defux의 connect 함수가 대신 하지만, 본 실습에서는  subscribe함수를 직접 사용 했습니다.


스토어의 상태가 변화할 때마다 호출 되고, unsubscribe함수를 반환하기 때문에 unsubscribe 함수를 호출하면 구독 취소가 가능합니다.


const unsubscribe = store.subscribe(()=>{
console.log(store.getState());
});


7) 수행


dispatch함수를 통해 액션을 넘겨줍니다.


store.dispatch(increment(1));
store.dispatch(increment(10));
store.dispatch(decrement(5));


콘솔창 결과




참고 : 리액트를 다루는 기술(저:VELOPERT)


'언어 > ReactJS' 카테고리의 다른 글

[React ]리덕스를 사용한 상태 관리  (3) 2019.06.14
[React] 함수형 컴포넌트  (0) 2019.05.21
[React] 라이프 사이클 함수  (0) 2019.05.07
[React] 컴포넌트 반복  (0) 2019.05.05
[React] Ref  (0) 2019.05.02

함수형 컴포넌트


함수형 컴포넌트?

지금까지 리액트에서 컴포넌트를 작성할 때 class 문법을 이용해서 정의를 했습니다. 라이프 사이클 API와 State를 사용할 필요가 없을경우, props만 전달받아 뷰를 렌더링 해서 간단하게 정의하는 컴포넌트를 의미합니다.


특징

1) 라이프사이클, State등 불필요한 기능을 제거한 상태이기 때문에 일반 클래스형 컴포넌트보다 메모리 소모량이 적고 성능도 조금 더 빠릅니다.

2) ES6의 화살표, 비구조화 할당 문법도 사용 가능합니다.


비교

일반 컴포넌트


import React, { Component } from 'react';

class test extends Component {
render() {
return (
<div>
TEST {this.props.number}
</div>
);
}
}

export default test;


함수형 컴포넌트


import React from 'react';

function Test(props){
return (
<div>
TEST {props.number}
</div>
);
}

export default Test;


함수형 컴포넌트 - ES6


import React from 'react';

const Test = ({num}) => (
<div>Test {num}</div>
)

export default Test;




참고 : 리액트를 다루는 기술(저:VELOPERT)

'언어 > ReactJS' 카테고리의 다른 글

[React ]리덕스를 사용한 상태 관리  (3) 2019.06.14
[React] 리덕스 개념  (0) 2019.05.24
[React] 라이프 사이클 함수  (0) 2019.05.07
[React] 컴포넌트 반복  (0) 2019.05.05
[React] Ref  (0) 2019.05.02

1. 마크다운?


마크다운(Markdown)은 2004년 John Gruber에 의해 만들어진 마크업 언어로 쉽게 사용할 수 있다는 장점이 있는 언어입니다.

깃허브(Github), 벨로그(velog), 티스토리(thistory) 등 다양한 블로그 플랫폼에서 지원하고 있습니다.


2. 마크다운 작성법


2-1. 제목

  • 제목
제목 테스트
=======

제목 테스트

  • 부제목
부제목 테스트
-------------

부제목 테스트

  • 글머리
    # H1
    ## H2
    ### H3
    #### H4
    ##### H5
    ###### H6

    H1

    H2

    H3

    H4

    H5
    H6

2-2. 본문

본문 내용은 그대로 출력 됩니다.

2-3. 인용

인용은 ">" 를 붙여서 사용합니다.

> 인용1
>> 인용2
>>> 인용3

인용1

인용2

인용3

2-4. 목록

  • 순서가 없는 목록

"*" 또는 "-" 를 붙여서 사용합니다.

* 과일
    * 사과
    * 배
    - 바나나
        - 노란색
  • 과일

    • 사과
    • 바나나
      • 노란색
  • 순서가 있는 목록

숫자와는 상관없이 "숫자." 을 붙여 사용합니다.

1. 수박
1. 포도
    1. 주스
    1. 청포도
1. 배
    1. 배즙
  1. 수박
  2. 포도
    1. 주스
    2. 청포도
    1. 배즙

2.5 구분선

아래와 같이 사용 가능합니다.

* * *
***
******************
- - -
------------------





2.6 코드블럭

코드는 한줄의 경우 "`"로 감싸서 사용합니다.

`var test = 10;`

var test = 10;

여러 줄의 경우에는 "```" 를 이용해서 감싸줍니다.

function test(){
    console.log('test');
}

2.7 강조

  • 굵게
*중요*한 텍스트
**중요**한 텍스트

중요한 텍스트
중요한 텍스트

  • 취소선
~~취소~~한 텍스트

취소한 텍스트

2.8 이미지

오사카에 놀러갔을 때 찍은 사진입니다.

![파일명.확장자](이미지경로/파일명.확장자)

universal.jpg

2.9 링크

URL 제목은 생략 가능합니다.

[텍스트](URL "URL 제목")

완벽한 코드는 없다


참고

존 그루버의 마크다운
ihoneymon님의 마크다운 사용법

라이프 사이클 함수


라이프 사이클?

모든 리액트 컴포넌트에는 라이프 사이클(수명 주기)이 존재합니다. 라이프 사이클은 컴포넌트가 생성되고 소멸될 때까지 일련의 과정을 의미 합니다.


라이프 사이클 함수

총 10가지의 함수가 존재하며, will이 붙은 함수는 어떤 작업을 하기 전에 실행되고, did가 붙은 함수는 작업을 한 후에 실행됩니다.


라이프 사이클 함수를 사용 하는 경우

어떤 작업을 수행할 때 렌더링 할 때 처리해야 하는 경우가 있고 업데이트 전후로 처리해야 하는 경우가 있는데 이럴 경우 라이프 사이클 함수를 이용해서 처리합니다.


컴포넌트의 라이프 사이클

마운트(페이지에 컴포넌트가 나타남) -> 업데이트(리렌더링) -> 언마운트(페이지에서 컴포넌트가 사라짐)


마운트?

DOM이 생성되고 웹 브라우저상에 나타는 과정


업데이트? 

컴포넌트를 업데이트 하는 경우로 아래와 같은 경우에 동작합니다.

1) Props가 바뀔 경우

2) state가 바뀔 경우

3) 부모 컴포넌트가 리렌더링 할 경우

4) this.forceUpdate로 강제로 렌더링을 트리거 할 경우


언마운트?

마운트의 반대 과정으로 DOM에서 컴포넌트를 제거하는 과정


관련 함수

1) render()

컴포넌트 모양새를 정의

이 함수 안에서 this.props, this.state에 접근

리액트 요소를 반환, 아무것도 보여주지 않는다면 null이나 false를 반환

state를 변형하면 안되고 웹 브라우저에 접근해서도 안됨 => DOM 정보를 가져오거나 변화를 줄 떄에는 componentDidMount에서 처리해야 함

2) Constructor()

Constructor(props) {...}

컴포넌트를 처음 만들 때 사용

초기 state설정

3) getDerivedStateFormProps()

리액트 v16.3 이후에 새로 만든 라이프사이클 함수

props로 받아온 값을 state에 동기화 시키는 용도로 사용

컴포넌트를 마운트하거나 props를 변경할 때 호출

4) componentDidMount()

componentDidMount(){...}

컴포넌트를 만들고 첫 렌더링을 마친 후 실행

다른 자바스크립트 라이브러리나 프레임워크의 함수 호출, 이벤트 등록, setTimeout, setInterval, 네트워크 요청 등 비동기 작업 처리

5) shouldComponentUpdate()

shouldComponentUpdate(nextProps, nextState) {...}

props또는 state 변경 시 리렌더링을 시작할지 여부를 지정하는 함수

반드시 true & false 반환 해야함

현재 props, state 변경은 this키워드를 붙이고 새로 설정할 props, state는 nextProps, nextState로 접근

  6) getSnapshotBeforeUpdate()

v16.3 이후 만든 메소드

ender 메소드를 호출한 후 DOM에 변화를 반영하기 바로 직전에 호출하는 함수

componentDidUpdate에서 세번 째 파라미터인 snapshot 값으로 전달 받을 수 있는데 주로 업데이트 하기 직전의 값을 참고할일이 있을 때

  7) componentDidUpdate()

componentDidUpdate(prevProps, prevState, snapshot) {...}

prevProps, prevState 사용하여 이전에 가졌던 데이터에 접근

getSnapshotBeforeUpdate에서 반환한 값이 있다면 여기서 snapshot 값을 전달 받을 수 있음

8) componentWillUnmount()

componentWillUnmount(){...}

DOM에서 제거할 때 실행

componentDidMount에서 등록한 이벤트, 타이머, 직접 생성한 DOM이 있다면 여기에서 제거 작업



예제

아래 예제는 함수가 언제 동작하는 지 확인해보기 위해 작성한 예제입니다.


색을 랜덤으로 업데이트 하는 버튼과 숫자를 올려주는 버튼 두개로 구성됩니다.


숫자가 4로 끝날 경우에만 리렌더링 되지않고, 나머지 숫자일 때에는 업데이트가 발생하면 리렌더링 됩니다.


LifeCylce.js

import React, { Component } from 'react';

class LifeCycle extends Component {
state ={
number : 0,
color : null
}
myRef = null;
constructor(props){
super(props);
console.log('constructor()');
}

static getDerivedStateFromProps(nextPorps, prevState){
if(nextPorps.color !== prevState.color){
return {
color:nextPorps.color
};
}
return null;
}
componentDidMount(){
console.log('componentDidMount()');
}
shouldComponentUpdate(nextPorps, nextState){
console.log("shouldComponentUpdate(),", nextPorps,",", nextState);
return nextState.number %10 !==4;
}

componentWillUnmount(){
console.log("componentWillUnmount()");
}

handleClick = () =>{
this.setState({
number : this.state.number +1
});
}

getSnapshotBeforeUpdate(prevProps, prevState){
console.log('getDerivedStateFromProps()');
if(prevProps.color !== this.props.color){
return this.myRef.style.color;
}
return null;
}

componentDidUpdate(prevProps, prevState, snapshot){
console.log('componentDidUpdate()');
if(snapshot){
console.log('업데이트 되기 직전 색상 : ',snapshot);
}
}

render() {
console.log('render()');
const style={
color:this.props.color
}
return (
<div>
<h1 style = {style} ref={ref=>this.myRef=ref}>
{this.state.number}
</h1>
<p>color : {this.state.color}</p>
<button onClick={this.handleClick}>plus</button>
</div>
);
}
}

export default LifeCycle;



app.js


import React, { Component } from 'react';
import './App.css';
import LifeCycle from './component/LifeCycle';

function getRandomColor(){
return '#'+Math.floor(Math.random()*16777215).toString(16);
}

class App extends Component {
state = {
color : '#000000'
}
handleClick = () =>{
this.setState({
color : getRandomColor()
});
}
render() {
return (
<div>
<button onClick={this.handleClick}>Random Color</button>
<LifeCycle color={this.state.color}/>
</div>
);
}
}

export default App;


동작결과


처음 렌더링 된 후 찍힌 결과입니다. 생성자 함수, getDerivedStateFromProps함수, render함수 componentDidMount 함수가 차례대로 실행 됩니다.



초기 렌더링 후 화면입니다.


랜덤 버튼과 플러스 버튼을 클릭했을 때의 결과 입니다. 숫자가 4로 끝나는 경우에만 리 렌더링 되지않고 나머지의 경우에는 리 렌더링 됩니다.


랜덤버튼 클릭


플러스 버튼 클릭


두 버튼을 클릭했을 때 바뀌는 화면입니다.



참고 : 리액트를 다루는 기술(저:VELOPERT)


'언어 > ReactJS' 카테고리의 다른 글

[React] 리덕스 개념  (0) 2019.05.24
[React] 함수형 컴포넌트  (0) 2019.05.21
[React] 컴포넌트 반복  (0) 2019.05.05
[React] Ref  (0) 2019.05.02
[React] 이벤트 핸들링  (2) 2019.04.25

컴포넌트 반복


리액트의 반복

JSTL의 <forEach>, AngularJS의 <ng-repeat>처럼 리액트에도 반복을 처리할 수 있는 방법이 있습니다.

리액트에서는 자바스크립트 배열 객체의 내장 함수인 map()함수를 이용합니다.


Map()

Map()

- 자바스크립트 배열 객체의 내장함수

- 파라미터로 전달된 함수를 사용해서 배열 내 각 요소를 프로세싱 한 후 그 결과를 새로운 배열로 생성해주는 함수

형태

arr.map(callback, [thisArg])

callback

      - currentValue: 현재 처리하고 있는 요소

      - index : 현재 처리하고있는 요소의 index

      - array : 현재 처리하고있는 원본 배열

thisArg(선택사항)

callback 함수 내부에서 사용할 this 레퍼런스

Key

-  리액트에서 컴포넌트 배열을 렌더링 했을 때 어떤 원소에 변동이 있는지 알아내려고 사용
- 단순히 출력만 하는 경우에는 Key가 필요하지 않지만, 게시판의 글을 수정, 삭제하는 등 고유 값이 필요한 경우에는 꼭 사용해야 합니다.
- props 설정과 유사


예제


아래 예제는 fruits 배열을 map함수를 이용해서 렌더링하는 예제입니다.


render() {
const fruits = ['사과','배','바나나','포도','수박'];
const fruitsList = fruits.map(
(fruit) => (<li>{fruit}</li>)
);

return (
<div>
<ul>
{fruitsList}
</ul>
</div>
);
}


동작 결과



정상적으로 렌더링 되지만, 아래와 같이 "key" prop이 없다는 경고가 뜨게 됩니다.



위의 예제에 Key를 추가하면 경고는 사라집니다.

index를 key로넘겨주면 index를 이용해서 쉽게 접근이 가능합니다.


const fruits = ['사과','배','바나나','포도','수박'];
const fruitsList = fruits.map(
(fruit,index) => (<li key={index}>{fruit}</li>)
);



참고 : 리액트를 다루는 기술(저:VELOPERT)




'언어 > ReactJS' 카테고리의 다른 글

[React] 함수형 컴포넌트  (0) 2019.05.21
[React] 라이프 사이클 함수  (0) 2019.05.07
[React] Ref  (0) 2019.05.02
[React] 이벤트 핸들링  (2) 2019.04.25
[React] State  (0) 2019.04.12

합병 정렬(Merge Sort)




합병 정렬? 

합병 정렬은 병합 정렬이라고도 불리며, 배열을 여러개로 분할해서 병합하면서 정렬하는 방법입니다.


특징

1) 메모리 내부에서 정렬하는 방법

2) 연결 리스트와 같은 순차적인 접근이 가능한 자료구조에 유일한 정렬 방법


어떠한 방법?

예제는 정렬할 배열과 임시로 담아놓을 배열 2개를 이용해서 정렬을 진행했습니다.


아래와 같은 배열이 있을 때



배열을 나눠서 정렬을 한 뒤 병합하면서 정렬을 진행합니다.





배열을 이용한 합병 정렬 예제


배열 출력 함수


void print_array(int array[], int size){
for(int i=0; i<size; i++){
printf("%-4d",array[i]);
}
printf("\n");
}

병합 정렬 함수


- size : 2씩 곱해지면서 정렬할 항의 수를 결정

- first, second : 하나의 배열을 두개처럼 사용하기위한 변수 각각 비교할 항 앞과 뒤를 가리킴

- i, j : 각각 비교할 앞의 항과 뒤의 항

- k : 임시로 담을 배열의 인덱스


void merge_sort(int a[], int n){
int i, j, k;
int first, second, size;
int *b;
b = (int*)malloc(sizeof(int)*n);
for(size = 1; size<n; size *=2){
first = -2 * size; // 초기 값
second = first + size;
while(second + size*2 < n){
first = second + size;
second = first + size;

i = k = first;
j = second;
while(i<first+size || (j<second+size && j<n)){
if(a[i]<=a[j]){
if(i<first + size)
b[k++] = a[i++];
else
b[k++] = a[j++];
}else{
if(j<second+size && j<n)
b[k++] = a[j++];
else
b[k++] = a[i++];
}
printf(" b[%d]=%d\t",k-1,b[k-1]);
}
printf("\n############################\n");
}
for(i=0; i<n; i++)
a[i] = b[i];
}
free(b);
}



메인 함수


void main(){
int array[] = {6,8,5,2,7,3,1,4};
int size = sizeof(array)/sizeof(int);
printf("########### Sorting before ###########\n");
print_array(array, size);
printf("######################################\n");
merge_sort(array, size);
printf("########### Sorting after ###########\n");
print_array(array, size);
}



실행 결과




참고 : C로 배우는 알고리즘 (이재규)

위키백과(합병 정렬)



관련 포스팅


[DataStructure] 기수 정렬(Radix Sort)

[DataStructure] 퀵 정렬(Quick Sort)

[DataStructure] 셸 정렬(Shell Sort)

[DataStructure] 버블 정렬(Bubble Sort)

[DataStructure] 삽입 정렬(Insertion Sort)

[DataStructure] 선택 정렬(Selection Sort)



'언어 > Data Strcuture' 카테고리의 다른 글

[C] 힙 정렬(Heap Sort)  (0) 2019.05.01
[C] 기수 정렬(Radix Sort)  (1) 2019.04.30
[C] 퀵 정렬(Quick Sort)  (0) 2019.04.24
[C] 셸 정렬(Shell Sort)  (2) 2019.04.23
[C] 버블 정렬(Bubble Sort)  (0) 2019.04.20

Ref


Ref(reference) ? 

HTML에서 id를 이용해서 DOM에 이름을 다는 것처럼 리액트 프로젝트 내부에서 DOM에 이름을 다는 개념입니다.


Ref를 사용하는 이유 ? 

ref는 DOM을 직접 건드려야 하는경우 사용합니다.

id를 사용할 수는 있지만, 같은 컴포넌트를 여러번 사용할 경우 유일해야하는 id가 중복이 발생 할 수 있습니다.


State로는 대체 불가능 한가?

아래와 같은 경우는 state만으로 해결이 불가능 합니다.

   1) 특정 <input>태그에 포커스를 주는 경우

   2) 스크롤 박스를 조작하는 경우

   3) <Canvas>태그에 그림을 그리는 경우


리액트에서 id는 사용 불가?

다른 라이브러리나 프레임워크를 사용할 경우 id를 꼭 사용해야만 하는 경우라면 중복 방지를 위해 뒤에 추가 텍스트를 붙여서 사용합니다.

예) button01, button02

 


Ref 사용 방법

props를 설정하는 방법과 유사하며 , ref 값으로 콜백 함수를 전달합니다.



<input ref="{(ref)=> {this.input.ref}}" />


Ref사용 예제(Scroll)


Ref를 이용해서 자식 컴포넌트인 ScrollBox의 스크롤을 아래, 위로 이동하는 예제입니다.


ScrollBox컴포넌트에서 <div>태그에 ref를 넘겨줍니다.


ScrollBox.js

import React, { Component } from 'react';

class ScrollBox extends Component {
scrollToChange =(param) =>{
const{scrollHeight, clientHeight} = this.box;
if(param==='d'){
this.box.scrollTop = scrollHeight - clientHeight;
}else{
this.box.scrollTop = 0;
}
}

render() {
const style={
border : '1px solid black'
, height : '300px'
, width : '300px'
, overflow : 'auto'
, position : 'relative'
};
const innerStyle ={
width : '100%'
,height : '500px'
,background : 'linear-gradient(white, black)'
}

return (
<div
style = {style}
ref={(ref)=>{this.box=ref}}>
<div style = {innerStyle}/>
</div>
);
}
}

export default ScrollBox;


ScrollBox에서 box를 넘겨받은 후 ScrollBox에서 정의한 함수 scrollToChange() 함수를 사용할 수 있습니다.


App.js

import React, { Component } from 'react';
import './App.css';
import ScrollBox from './component/ScrollBox';

class App extends Component {
state = {
upDown : 'd'
,value : 'To Bottom'
}
updownChange =() =>{
if(this.state.upDown === 'd'){
this.setState({
upDown:'u'
,value : 'To Top'
});
}else{
this.setState({
upDown:'d'
,value : 'To Bottom'
});
}
};
render() {
return (
<div>
<ScrollBox ref={(ref)=>this.ScrollBox=ref}/>
<button
onClick={
()=>{
this.ScrollBox.scrollToChange(this.state.upDown);
this.updownChange();
}
}
>
{this.state.value}
</button>
</div>
);
}
}

export default App;


동작 결과


참고 : 리액트를 다루는 기술(저:VELOPERT)





'언어 > ReactJS' 카테고리의 다른 글

[React] 라이프 사이클 함수  (0) 2019.05.07
[React] 컴포넌트 반복  (0) 2019.05.05
[React] 이벤트 핸들링  (2) 2019.04.25
[React] State  (0) 2019.04.12
[React] Props  (1) 2019.04.11

힙 정렬(Heap Sort)




힙(Heap) ?  

최대값, 최소값을 찾아내는 연산을 빠르게 하기위해 고안된 완전트리를 기본으로 한 자료구조


힙정렬

힙 정렬은 분할정복 알고리즘으로 최대 힙 트리나 최소 힙 트리를 구성해 정렬 하는 방법 입니다.


어떠한 방법?

예제는 배열을 이용해서 트리구조를 구성했습니다.


배열을 이용한 트리구조에서 주의할 점은 균형 잡히지 않은 노드의 경우 실제로 없는 노드를 위해 배열 공간을 확보해야 하기 때문에 균형잡힌 노드에 한해서 사용 가능합니다.



아래와 같은 이진트리가 있을 때


A노드부터 1번부터 12번까지 숫자를 매기면 아래 그림과 같습니다.



이 때 i노드의 부모번호는 i/2

i노드의 왼쪽 자식노드는 2i 오른쪽 자식노드는 2i+1을 만족합니다.


예) 5번 노드의 부모노드 번호는 5/2=2(버림)

4번 노드의 왼쪽 자식노드는 4*2=8 오른쪽 자식도느는 4*2+1 = 9


이 개념을 이용하면 배열을 이용해서 트리를 구성할 수 있습니다.



배열을 이용한 힙 정렬 예제


upHeap함수


아래에서 위로 올라가면서 자리를 바꾸는 함수입니다.


void upHeap(int array[], int k){
int v;
v = array[k];
array[0] = MAX;
while (array[k/2]<=v) // 부모 <= 자식
{
array[k] = array[k/2];
k/=2;
}
array[k] = v;
}


downHeap함수


upHeap함수와 반대로 아래로 내려가면서 비교하는 함수입니다.

자식노드 왼쪽과 오른쪽 노드를 비교해서 더 큰 노드를 이용합니다.


void downHeap(int array[], int n, int k){
int i;
int v = array[k];
while(k<=n/2){
i = k<<1; // 2*k
if(i<n && array[i]<array[i+1]) i++; //왼쪽, 오른쪽 노드 비교
if(v>=array[i]) break;
array[k] = array[i];
k=i;
}
array[k] = v;
}


insert, delete함수


insert는 입력받은 배열을 트리구조로 사용하기 위해 입력하는 함수

delete는 정렬된 데이터를 받아오는 함수 입니다.


void insert(int array[], int *hn, int v){
array[++(*hn)] = v;
upHeap(array, *hn);
}

int delete(int array[], int *n){
int v = array[1];
array[1] = array[(*n)--];
downHeap(array, *n, 1);
return v;
}


힙 정렬 함수


입력받은 배열을 정렬하는 함수입니다.


첫번 째 for문 : 배열을 순차적으로 삽입

두번 째 for문 : 정렬된 데이터를 꺼냄

마지막 for문 : 정렬시에 0번째에는 큰 수를 넣어놓고

1번째 인덱스부터 이용했기 때문에 

한칸씩 당겨주는 for문


void heap_sort(int array[], int n){
int hn = 0;
int i= 0;
for(i=1; i<=n; i++)
insert(array, &hn, array[i]);
for(i=hn; i>=1; i--){
array[i] = delete(array, &hn);
}
for(int j=0; j<n; j++){
array[j] = array[j+1];
}
}


배열 출력 함수


void print_array(int array[], int size){
for(int i=0; i<size; i++){
printf("%-4d",array[i]);
}
printf("\n");
}


메인 함수


정렬 전 배열과 위의 기준대로 정렬한 결과를 출력합니다.

정렬을 하고나면 배열의 크기가 변하기 때문에
oldSize변수에 초기 크기를 저장해두고 진행했습니다.

void main(){
int array[] = {11,1,83,202,55,4,119,81,15,47,19,28};
int oldSize = sizeof(array)/sizeof(int);
int size = sizeof(array)/sizeof(int);
printf("########### Sorting before ###########\n");
print_array(array, size);
heap_sort(array, size);
printf("########### Sorting after ###########\n");
print_array(array, oldSize);
}

실행 결과




참고 : C로 배우는 알고리즘 (이재규)

  위키백과(힙 ,힙 정렬)



관련 포스팅


[DataStructure] 기수 정렬(Radix Sort)

[DataStructure] 퀵 정렬(Quick Sort)

[DataStructure] 셸 정렬(Shell Sort)

[DataStructure] 버블 정렬(Bubble Sort)

[DataStructure] 삽입 정렬(Insertion Sort)

[DataStructure] 선택 정렬(Selection Sort)





'언어 > Data Strcuture' 카테고리의 다른 글

[C] 합병 정렬(Merge Sort)  (0) 2019.05.04
[C] 기수 정렬(Radix Sort)  (1) 2019.04.30
[C] 퀵 정렬(Quick Sort)  (0) 2019.04.24
[C] 셸 정렬(Shell Sort)  (2) 2019.04.23
[C] 버블 정렬(Bubble Sort)  (0) 2019.04.20

기수 정렬(Radix Sort)




기수정렬?

기수정렬은 자리수별로 비교하여 정렬하는 방법입니다.


비교연산은 하지않고, 정수와 같은 자료의 정렬 속도가 매우 빠릅니다.


복잡도

가장 큰 숫자의 자리수가 d라고할 때 복잡도는 아래와 같습니다.





아래와 같은 배열이 있을 때 


가장 큰 숫자의 자리수는 3이므로 정렬을 3번 진행합니다.


각 자리수에 해당하는 큐에 순서대로 데이터를 삽입합니다.


가장먼저 1의자리 정렬입니다.



1의자리를 기준으로 정렬된 데이터를 

10의자리 기준으로 정렬합니다.



마지막으로 10의자리 기준으로 정렬된 데이터를

100의자리 기준으로 정렬합니다.


정렬한 데이터를 큐에서 전부 꺼내주면 정렬이 완료됩니다.



큐를 이용한 기수 정렬 예제


많은 예제들을 찾아봤는데, 0~9 총 10개의 큐를 만들어서 진행하는 예제가 많았습니다.


굳이 10개의 큐가 필요할까? 라는 생각을 하게 되었고, 큐 하나만 이용해서 정렬을 진행해 봤습니다.



Queue put(),get()함수 


Queue관련 내용은 생략하겠습니다.


Queue관련 내용은 아래 포스팅 참고바랍니다.


[Data Strcuture] 큐(Queue)



#include <stdio.h>
#define MAX 20
// QUEUE

int queue[MAX];
int front, rear = 0;

int put(int k){
if((rear+1) % MAX == front){
printf("QUEUE OVER FLOW!\n\n");
return -1;
}else{
queue[rear] = k;
rear = ++rear % MAX;
return 1;
}
}

int get(){
int k;
if(front == rear){
printf("QUEUE UNDER FLOW!\n\n");
return -1;
}else{
k = queue[front];
front = ++front % MAX;
return k;
}
}

// ARRAY
void print_array(int array[], int size){
for(int i=0; i<size; i++){
printf("%-4d",array[i]);
}
printf("\n");
}


기수정렬 함수


가장 큰 숫자를 찾아서 자리수를 구한 뒤


0~9까지 각 자리에 맞는 숫자가 나올때 큐에 삽입하고


반복이 끝나면 큐에서 배열에 담고 큐를 초기화 하는 방법으로 진행 했습니다.


void radix_sort(int array[], int size){
int max = array[0];
int digit = 0;
int factor = 1;
for(int i=1; i<size; i++){
if(max<array[i]) max = array[i];
}
for(int i=max; i>0;i/=10){
digit++;
}

for(int i =0; i<digit; i++){
for(int j=0; j<10; j++){ // 0~9
for(int k=0; k<size; k++){
if((array[k]/factor)%10==j){
put(array[k]);
}
}
}
factor *=10;
for(int i=front; i!=rear; i++){
array[i] =get();
}
printf("########### %d ROUND ###########\n",i+1);
print_array(array,size);
front=rear=0;
}
}


배열 출력 함수


void print_array(int array[], int size){
for(int i=0; i<size; i++){
printf("%-4d",array[i]);
}
printf("\n");
}


실행 함수


void main(){
int array[] = {11,1,83,202,55,4,119,81,15,47,19,28};
int size = sizeof(array)/sizeof(int);
printf("########### Sorting before ###########\n");
print_array(array, size);
radix_sort(array, size);
}


실행 결과




참고 : 위키백과(기수 정렬)




관련 포스팅


[DataStructure] 기수 정렬(Radix Sort)

[DataStructure] 퀵 정렬(Quick Sort)

[DataStructure] 셸 정렬(Shell Sort)

[DataStructure] 버블 정렬(Bubble Sort)

[DataStructure] 삽입 정렬(Insertion Sort)

[DataStructure] 선택 정렬(Selection Sort)



'언어 > Data Strcuture' 카테고리의 다른 글

[C] 합병 정렬(Merge Sort)  (0) 2019.05.04
[C] 힙 정렬(Heap Sort)  (0) 2019.05.01
[C] 퀵 정렬(Quick Sort)  (0) 2019.04.24
[C] 셸 정렬(Shell Sort)  (2) 2019.04.23
[C] 버블 정렬(Bubble Sort)  (0) 2019.04.20

+ Recent posts