개발을 하다보면 프로그램이 종료가 안되는 경우가 간혹 있습니다.

 

그럴때 해결방법은 pid를 찾아서 taskkill로 죽여주면 되는데요

 

첫번째 방법은 작업관리자에서 PID 옵션을 켜주고 찾은다음 cmd에서 해당 명령을 실행해주면 됩니다.

 

1. 작업관리자에서 PID 체크

 

 

2. 종료시킬 프로그램 PID 확인 후 taskkill 명령 수행

taskkill /f /t /pid 21884

 

두번째 방법은 매번 찾기 귀찮으니 윈도우 배치파일로 만드는것입니다.

아래 코드를 복사해서 프로그램 이름만 바꿔서 "원하는파일명.bat"으로 저장해서 사용하면 됩니다.

 

@echo off



FOR  /F  "tokens=2  delims= "  %%a  IN  ('tasklist ^| findstr putty.exe')  DO  set  result=%%a

taskkill /f /t /pid %result%

echo %result%



timeout /t 5

 

만든 배치파일을 더블클릭하면 해당 프로그램의 PID를 찾아서 종료한것을 확인할 수 있습니다.

 

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

IntelliJ 설치  (0) 2020.03.26
[이클립스] 폰트 변경  (2) 2017.04.19
[이클립스] 개발환경 구축(설치)  (4) 2017.04.19

1. IntelliJ ?

 

  

IntelliJ IDEA는 JetBrains사에서 제작한 상용 통합 개발 환경으로 줄여서 IntelliJ 혹은 IDEA로도 부릅니다.


JVM언어인 JAVA, Kotlin, Scala, Grovy 등의 언어와 JavaScript, TypeScript등 스크립트 언어들을 사용가능합니다.



2. 다운로드

 

1) IntelliJ IDEA 공식 홈페이지

https://www.jetbrains.com/ko-kr/idea/



저는 코틀린 개발을 위해 무료 버전인 커뮤니티 버전을 설치했습니다.






3. 설치



설치 경로를 지정한 후 넘어갑니다.


1GB정도 공간이 필요 합니다.



바탕화면에 아이콘을 추가하는등의 설치 옵션을 선택하고 넘어갑니다.



시작메뉴에 폴더 이름을 정하고 인스톨 버튼을 클릭하면 설치가 시작됩니다.




설치가 완료된 화면입니다. 


체크 박스를 선택하면 바로 실행이됩니다.





4. 실행 및 프로젝트 생성


IDEA 설정을 임포트 할 수 있습니다.


전 최초 사용이기때문에 임포트 하지않고 진행 했습니다.



정책 동의를 하고 넘어갑니다.



테마를 선택하고 다음으로 넘어갑니다.



기본 플러그인 설정 화면입니다.


사용하지 않을 플러그인은 제거하고 진행 가능합니다.



추가 플러그인을 받을 수 있는 화면입니다.


필요한 플러그인 설치 후 진행 가능합니다.



기본적인 세팅이 끝나고나면 프로젝트를 생성 및 임포트 할 수 있습니다.



어떤 프로젝트로 생성할지 선택하는 화면입니다.




프로젝트 이름을 입력하는 화면입니다.



테스트 프로젝트를 생성한 화면입니다.





출처 및 참고 


IntelliJ 로고

IntelliJ 공식 홈페이지(https://www.jetbrains.com/ko-kr/)





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

(윈도우)프로그램 강제로 종료하는 방법  (0) 2021.11.06
[이클립스] 폰트 변경  (2) 2017.04.19
[이클립스] 개발환경 구축(설치)  (4) 2017.04.19
1. 코틀린(Kotlin)?
 

  

코틀린은 Andorid Studio 개발사인 Jet Brains에서 2011년에 공개한 언어로 Google I/O 2017 에서 안드로이드의 공식 개발 언어로 채택되며 계속해서 성장하고 있는 언어입니다.



2. 코틀린 사용 범위

 

1) 안드로이드 개발

2) 서버개발

코틀린 공부 전까지는 안드로이드 개발을 위해서만 사용하는 줄 알았으나 서버사이드 개발에서도 사용합니다.




3. 코틀린의 장점


1) 무료 오픈 소스

코틀린 언어와 컴파일러 라이브러리 및 코틀린과 관련된 도구는 모두 오픈소스이며 어떠한 목적에도 무료료 사용 가능합니다.


2) 정적 타입 지정언어

코틀린 컴파일러가 문백으로 타입을 자동으로 유추하기때문에 변수 선언 시 모든 변수의 타입을 명시할 필요가 없습니다. 


fun main(args: Array<String>) { val test =3 println("test >> "+test) println("test type >> "+ test.javaClass.name) }



3) 함수형 프로그래밍 & 객체지향 프로그래밍


코틀린은 자바처럼 객체지향 언어인 동시에 함수형 프로그래밍의 장점을 채택하는 언어입니다.


함수를 인자로 전달 한다던가 함수에서 새로운 함수를 만들어서 반환하는 등 함수형 프로그래밍의 장점을 활용 할 수 있습니다.



출처 및 참고 


코틀린 로고 

https://play.kotlinlang.org/?_ga=2.60276845.192411083.1583667055-667909187.1583667055#eyJ2ZXJzaW9uIjoiMS4zLjcwIiwicGxhdGZvcm0iOiJqYXZhIiwiYXJncyI6IiIsImpzQ29kZSI6IiIsIm5vbmVNYXJrZXJzIjp0cnVlLCJ0aGVtZSI6ImlkZWEiLCJjb2RlIjoiLyoqXG4gKiBZb3UgY2FuIGVkaXQsIHJ1biwgYW5kIHNoYXJlIHRoaXMgY29kZS4gXG4gKiBwbGF5LmtvdGxpbmxhbmcub3JnIFxuICovXG5cbmZ1biBtYWluKCkge1xuICAgIHByaW50bG4oXCJIZWxsbywgd29ybGQhISFcIilcbn0ifQ==


참고

Kotlin IN ACTION





리덕스를 사용한 상태 관리


왜 리덕스를 사용하는가?


컴포넌트를 프리젠테이셔널 컴포넌트컨테이너 컴포넌트로 나눠서 사용하면 사용자가 이용할 유저 인터페이스와 상태를 다루는 데이터가 분리되어 프로젝트를 이해하기 쉽고 컴포넌트 재사용률도 높습니다.


1) 프리젠테이셔널 컴포넌트
오직 뷰만 담당하는 컴포넌트로 UI 관련된 state외에는 state는 존재하면 안되며, props로만 데이터를 처리합니다.

2) 컨테이너 컴포넌트
프리젠테이셔널 컴포넌트들과 컨테이너 컴포넌트들의 관리를 담당하는 컴포넌트로 프리젠테이셔널 컴포넌트와 반대로 스타일은 존재하면 안됩니다.

리덕스

리덕스의 개념적인 부분은 아래 포스팅을 참고해주세요


예제


0) react-redux 라이브러리 설치

yarn을 사용하시는 분들은 yarn add react-redux
npm을 사용하시는 분들은 npm install react-redux로 설치 가능합니다.

1) 작업 디렉토리 생성

/actions : 액션타입, 액션 생성자 파일 
/components : 프리젠테이셔널 컴포넌트
/containers : 컨테이너 컴포넌트
/reducers : 스토어의 기본 상태값, 리듀서 파일
/lib : 일부 컴포넌트에서 함꼐 사용되는 파일

2) 프리젠테이셔널 컴포넌트 생성

좌클릭 시 증가, 우클릭 시 감소, 더블클릭 시 색 변경함수를 props로 전달받습니다.

/components/Counter.js

import React from 'react';
import PropTypes from 'prop-types';
import './Counter.css';

const Counter=({number, color, onIncrement, onDecrement, onSetColor})=>{
return (
<div
className = "Counter"
onClick={onIncrement}
onContextMenu={(e)=>{
e.preventDefault();
onDecrement();
}}
onDoubleClick={onSetColor}
style={{
backgroundColor : color
}}
>
{number}
</div>
);
};

Counter.propTypes ={
number : PropTypes.number,
color : PropTypes.string,
onIncrement : PropTypes.func,
onDecrement : PropTypes.func,
onSetColor : PropTypes.func
}
Counter.defaultProps ={
number : 0,
color : 'black',
onIncrement : ()=>console.warn('onIncrement not defined'),
onDecrement : ()=>console.warn('onDecrement not defined'),
onSetColor : ()=>console.warn('onSetColor not defined')
}

export default Counter;

/components/Counter.css

.Counter{
width: 10rem;
height: 10rem;
display: flex;
align-items: center;
justify-content: center;
margin:1rem;
color:white;
font-size:3rem;
border-radius:100%;
cursor:pointer;
user-select: none;
transition: background-color 0.75s;
}

3) 액션 생성

증가, 감소, 색상 변경 액션을 정의합니다.

/actions/ActionTypes.js

export const INCREMENT = 'INCREMENT';
export const DECREMENT = 'DECREMENT';
export const SET_COLOR = 'SET_COLOR';

정의한 액션을 만들어주는 함수를 만들어 줍니다.

/actions/index.js

import * as types from './ActionTypes';

export const increment = () => ({
type : types.INCREMENT
});
export const decrement = () => ({
type : types.DECREMENT
});
export const setColor = (color) => ({
type : types.SET_COLOR,
color
});


4) 리듀서 생성

액션의 type에 따라 변화를 일으키는 함수입니다. 최초 변화를 일으키기전에 가지고 있어야 하는 초기 상태(initai를 정의 해야합니다.

/reducers/index.js

import * as types from '../actions/ActionTypes';

const initialState = {
color : 'black'
, number : 0
};

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

export default counter;



5) 스토어 생성


리덕스에서 가장 핵심적인 인스턴스로 현재 상태가 내장되어 있고, 상태를 업데이트 할 떄마다 구독중인 함수를 호출합니다.


리덕스에서 createStore를 불러와서 리듀서를 파라미터로 넣어 스토어를 생성합니다.


/src/index.js


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

import {createStore} from 'redux';
import reducers from './reducers';

const store = createStore(reducers);

ReactDOM.render(
<App />
,document.getElementById('root')
);




6) Provider 컴포넌트로 리액트 앱에 store연동


Provider는 react-redux라이브러리에 내장된 리액트 애플리케이션에 손쉽게 스토어를 연동할 수 있도록 도와주는 컴포넌트 입니다.


Provider를 불러와서 최상위 컴포넌트를 감싸줍니다.


import {Provider} from 'react-redux';

ReactDOM.render(
<Provider store={store}>
<App />
</Provider>
,document.getElementById('root')
);




7) 컨테이너 컴포넌트 생성


react-redux의 connect 함수를 사용하여 스토어에 연결합니다.


connect([mapStateToProps], [mapDispatchToProps], [mergeProps])


mapStateToProps : store.getState() 결과 값인 state를 파라미터로 받아서 props로 사용할 객체를 반환

mapDispatchToProps : dispatch를 파라미터로 받아 액션을 디스패치하는 함수들을 객체 안에 넣어서 반환

mergeProps : state와 dispatch가 동시에 필요한 함수를 props로 전달해야할 때 사용(일반적으로 잘 사용하지는 않음)


/containers/CounterContainer.js


import Counter from '../components/Counter';
import * as actions from '../actions';
import { connect } from 'react-redux';

// 13가지 색상 중 랜덤으로 선택하는 함수
export function getRandomColor() {
const colors = [
'#495057',
'#f03e3e',
'#d6336c',
'#ae3ec9',
'#7048e8',
'#4263eb',
'#1c7cd6',
'#1098ad',
'#0ca678',
'#37b24d',
'#74b816',
'#f59f00',
'#f76707'
];

// 0부터 12까지 랜덤 숫자
const random = Math.floor(Math.random() * 13);

// 랜덤 색상 반환
return colors[random];
}

// store 안의 state 값을 props로 연결
const mapStateToProps = (state) => ({
color: state.color,
number: state.number
});

/*
액션 생성 함수를 사용하여 액션을 생성하고,
해당 액션을 dispatch하는 함수를 만든 후, 이를 props로 연결
*/
const mapDispatchToProps = (dispatch) => ({
onIncrement: () => dispatch(actions.increment()),
onDecrement: () => dispatch(actions.decrement()),
onSetColor: () => {
const color = getRandomColor();
dispatch(actions.setColor(color));
}
});

// Counter 컴포넌트의 Container 컴포넌트
// Counter 컴포넌트를 애플리케이션의 데이터 레이어와 묶는 역할
const CounterContainer = connect(
mapStateToProps,
mapDispatchToProps
)(Counter);

export default CounterContainer;


실행 결과





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



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

[React] 리덕스 개념  (0) 2019.05.24
[React] 함수형 컴포넌트  (0) 2019.05.21
[React] 라이프 사이클 함수  (0) 2019.05.07
[React] 컴포넌트 반복  (0) 2019.05.05
[React] Ref  (0) 2019.05.02

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

라이프 사이클 함수


라이프 사이클?

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


라이프 사이클 함수

총 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

+ Recent posts