Programming

Atmel Studio 7 설치 후 Atmega128 작동시키기

Atmel Studio 7 설치 후 Atmega128 작동시키기

C/C++
Click the link to read the original article: Here =================== AT128A-75B 라는 Atmega128 MCU을 사용한 제품을 구매해서 처음 구동시켜보려고 합니다. 아두이노만 사용하다가...
Read More
C++ 기초

C++ 기초

C/C++
Click the link to read the original article: TCPSchool.com ==== C++ 개요 C++ C++은 기존의 C언어에 여러 가지 기능을 추가하여...
Read More
11 Best PHP Frameworks for Modern Web Developers in 2018

11 Best PHP Frameworks for Modern Web Developers in 2018

PHP
Click the link to read the original article: Here ============= 11 Best PHP Frameworks for Modern Web Developers in 2018...
Read More
프레임워크(FRAMEWORK)란

프레임워크(FRAMEWORK)란

PHP
Click the link to read the original article: Here =========================== 프레임워크(FRAMEWORK)란 2011. 1. 7. 16:56  이웃추가 본문 기타 기능 프레임워크란...
Read More
ORM 프레임워크(Object-relational mapping)

ORM 프레임워크(Object-relational mapping)

C/C++
Click the link to read the original article: Here ============================================== ORM 프레임워크(Object-relational mapping) Jayzzz 2017.10.11 15:34  ORM은 데이터베이스와 객체 지향 프로그래밍...
Read More
ORM 이란 무엇인가?

ORM 이란 무엇인가?

C/C++
Click the link to read the original article: Here ========================= ORM(Object-Relational Mappings)라는 건 과연 무엇일까? 근래 많이 보고 듣는 단어이고 ORM...
Read More
AngularJS 란 무엇인가?

AngularJS 란 무엇인가?

angularJs
AngularJS 란 무엇인가? Click to the link to go to the site: =============== AngularJS 개념 AngularJS 는 SPA(Single Page Application)...
Read More
React와 불변객체

React와 불변객체

react.js
블로그 사이트 바로가기 이번에는 불변객체의 개념과 React에 그 개념을 적용했을 때 어떤 이점을 얻을 수 있는지 소개하고자 합니다. 불변객체란? 객체...
Read More
React.js를 이해하다(7)

React.js를 이해하다(7)

react.js
블로그 사이트 바로가기 읽기전에... 이 문서는 koba04님이 작성한 React.js Advent Calendar를 번역한 것입니다. 본래 원문서는 캘린더 형식으로 소개하지만 여기에서는 회를...
Read More
React.js를 이해하다(6)

React.js를 이해하다(6)

react.js
블로그 사이트 바로가기 읽기전에... 이 문서는 koba04님이 작성한 React.js Advent Calendar를 번역한 것입니다. 본래 원문서는 캘린더 형식으로 소개하지만 여기에서는 회를...
Read More
React.js를 이해하다(5)

React.js를 이해하다(5)

react.js
블로그 사이트 바로가기 읽기전에... 이 문서는 koba04님이 작성한 React.js Advent Calendar를 번역한 것입니다. 본래 원문서는 캘린더 형식으로 소개하지만 여기에서는 회를...
Read More
React.js를 이해하다(4)

React.js를 이해하다(4)

react.js
블로그 사이트 바로가기 읽기전에... 이 문서는 koba04님이 작성한 React.js Advent Calendar를 번역한 것입니다. 본래 원문서는 캘린더 형식으로 소개하지만 여기에서는 회를...
Read More
React.js를 이해하다(3)

React.js를 이해하다(3)

react.js
블로그 사이트 바로가기 읽기전에... 이 문서는 koba04님이 작성한 React.js Advent Calendar를 번역한 것입니다. 본래 원문서는 캘린더 형식으로 소개하지만 여기에서는 회를...
Read More
React.js를 이해하다(2)

React.js를 이해하다(2)

react.js
블로그 사이트 바로가기 읽기전에... 이 문서는 koba04님이 작성한 React.js Advent Calendar를 번역한 것입니다. 본래 원문서는 캘린더 형식으로 소개하지만 여기에서는 회를...
Read More
React.js를 이해하다(1)

React.js를 이해하다(1)

react.js
블로그 사이트 바로가기 읽기전에... 이 문서는 koba04님이 작성한 React.js Advent Calendar를 번역한 것입니다. 본래 원문서는 캘린더 형식으로 소개하지만 여기에서는 회를...
Read More
Ubuntu 14.04에 Node.js 설치 및 간단한 예제

Ubuntu 14.04에 Node.js 설치 및 간단한 예제

Node.js
Site 바로가기: Ubuntu 14.04에 Node.js 설치 및 간단한 예제 라즈베리파이나 아두이노를 Node.js로 제어하는 것을 보고는 흥미가 생겨서 좀 더 공부해보려고...
Read More
Python Features

Python Features

Pathon
Click the link to go to the original blog site: 블로그 내용보러가기   Python Features 파이썬 프로그래밍 언어는 많은 특징이 있습니다....
Read More
파이썬이란 무엇인가?

파이썬이란 무엇인가?

Pathon
Click the link to go to the original blog site: 블로그 내용보러가기   Python  파이선 혹은 파이썬 파이선은 간단하고, 배우기 쉽고,...
Read More
[JavaScript] 연산을 해보자  – 1

[JavaScript] 연산을 해보자 – 1

Javascript
Click the link to go to the original blog site: 블로그 내용보러가기   컴퓨터가 탄생하게된 이유를 생각하면 아주 쉽게 이해 할...
Read More
[JavaScript] 문자열을 다루어 보자

[JavaScript] 문자열을 다루어 보자

Javascript
Click the link to go to the original blog site: 블로그 내용보러가기   그럼 웹 스톰을 실행합니다.   Open을 눌러 어제...
Read More
[JavaScript] 데이터 타입에 대하서 알아보자

[JavaScript] 데이터 타입에 대하서 알아보자

Javascript
Click the link to go to the original blog site: 내용 보러가기   여기서 1과 0으로 인식하는 이유는 무엇일까요? 초기 컴퓨터는...
Read More
[JavaScript] 자바스크립터 소개

[JavaScript] 자바스크립터 소개

Javascript
Click the link to go to the original blog site: 블로그 내용보러가기 웹스톰 설치 방법 http://tworab.tistory.com/51   1. 자바스크립트에 대해서 JavaScript(이하...
Read More
[JavaScript] WebStrom 설치하기

[JavaScript] WebStrom 설치하기

Javascript
Click the link to go to the original blog site: 블로그 내용보러가기   JetBrains 홈페이지 접속하기 http://www.jetbrains.com   - 홈페이지 상단에...
Read More
[JavaScript] WebStrom과 함께

[JavaScript] WebStrom과 함께

Javascript
Click the link to go to the original blog site: 블로그 내용보러가기   오늘 소개드릴 내용은 WebStorm과 JavaScript입니다.     WebStorm은 JetBrain사에서 만든 IDE...
Read More
[node.js] socket.io를 이용한 간단한 웹 채팅 프로그램

[node.js] socket.io를 이용한 간단한 웹 채팅 프로그램

Node.js
1. 기본 환경은 셋팅되었다는 전제하에 시작하겠습니다.(node.js, eclipse, node plugin) 2. Node Project를 생성합니다.(여기선 이름이 ChatTest입니다.) 3. 생성되어진 package.json을 연후 아래와...
Read More
Angular란 무엇인가?

Angular란 무엇인가?

angularJs
AngularJS (앵귤러JS) _MVC 프레임워크 기본개념 Angular란 무엇인가? AngularJS란 동적인 웹앱을 구현하기 위해 구글에서 제작 배포하고 있는 구조적 프레임워크라고 합니다. 특히,...
Read More
[2015.06.28] 안드로이드 개발 참고 사이트 / 약간의 소스

[2015.06.28] 안드로이드 개발 참고 사이트 / 약간의 소스

Mobile App
Click the link to read the article: Read the article... ===== http://arabiannight.tistory.com/entry/%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9CAndroid-AsyncTask-%EC%82%AC%EC%9A%A9%EB%B2%95 - AsyncTaskhttp://pulsebeat.tistory.com/24 - 서버/클라이언트 소켓(Socket) 통신하기http://cafe.naver.com/aphone.cafe?iframe_url=/ArticleRead.nhn%3Fclubid=17198535%26page=19%26menuid=14%26boardtype=L%26articleid=3612%26referrerAllArticles=false - 죽지않는 서비스 만들기----------------------------------------------------------------------------------------------------<Android <->...
Read More
[React.js] props에 대해 알아보자! 리액트 데이터 흐름 매커니즘

[React.js] props에 대해 알아보자! 리액트 데이터 흐름 매커니즘

react.js
Click the link to read the article: 내용 보러가기 ==================== 컴포넌트를 조합할 때 기본이 되는 props(속성)에 대해 알아보겠습니다! 리액트에서는 컴포넌트의 조합과 재사용을...
Read More
[React.js] 리액트 시작하기! 새로운 리액트 프로젝트 만드는 법

[React.js] 리액트 시작하기! 새로운 리액트 프로젝트 만드는 법

react.js
Click the link to read the article: 내용 보러가기 ================ 첫 리액트 프로젝트를 시작해 봅시다! 제 개발 환경은 다음과 같습니다 ^ㅡ^...
Read More
[React.js] 리액트란? 프론트 엔드의 대세!! 페이스북 오픈소스 라이브러리

[React.js] 리액트란? 프론트 엔드의 대세!! 페이스북 오픈소스 라이브러리

react.js
Click the link to read the article: 내용 보러가기 =============== 리액트에 관심을 가지고 꾸준히 공부하고 있는 초보 개발자 염염2 입니다 ^ㅡ^ 앞으로 제가...
Read More
AngularJS 란 무엇인가?

AngularJS 란 무엇인가?

angularJs
Click the link to read the article: 내용 보러가기 ======================== AngularJS 개념 AngularJS 는 SPA(Single Page Application) 프레임워크라고 합니다. 예를 들어,...
Read More
1장 Express.js란 무엇인가?

1장 Express.js란 무엇인가?

Node.js
Click the link to read the article: 내용보러가기 =============================== 1장 Express.js란 무엇인가? Express.js는 Node.js의 핵심 모듈인 http와 Connect 컴포넌트를 기반으로 하는 웹 프레임워크다. 그러한...
Read More
노드제이에스(Node.JS)란 무엇인가?

노드제이에스(Node.JS)란 무엇인가?

Node.js
Click the link to read the article: 내용 보러가기 ================================ 종종 node.js 를 사용하여 몇몇 업체에서 나오는 엔진 혹은 홈페이지 등...
Read More
[Node.js 강좌] Node.js 란? 개념과 소개

[Node.js 강좌] Node.js 란? 개념과 소개

Node.js
Click the link to read to the article: 블로그 내용보러가기 ===== 요즘 웹언어에서는 정적인 홈페이지 뿐만 아니라 쇼핑몰, 티켓 예메사이트, 블로그...
Read More
Node.js란?

Node.js란?

Node.js
Click the link to read the article: 블로그바로가기... ============================== 이 글을 쓰게 된 계기는 다음과 같다. Q: Node.js는 서버인가요? A: 네,...
Read More
Java-생활코딩

Java-생활코딩

Java
Java-생활코딩. Click the link to read the articles: opentutorials.org =====  
Read More
XE에서 파비콘(favicon) 만들기

XE에서 파비콘(favicon) 만들기

XE
XE에서 파비콘(favicon) 만들기 Click the link to read the article: https://www.xpressengine.com/ === 제로보드 XE에서 파비콘(favicon) 만들기 2008.05.26 21:08 tindrum 1. 파비콘(Favicon)이란...
Read More
XE 데이터 이전하기

XE 데이터 이전하기

XE
XE 데이터 이전하기 Click the link to read the article: http://www.xeschool.com/ ==== XE 데이터 이전하기 XE 코어의 포장이사와 셀프이사의 개념...
Read More
XE 1.7 동영상 강좌입니다.

XE 1.7 동영상 강좌입니다.

XE
XE 1.7 동영상 강좌입니다. Click to the following link to read the article: https://www.cameron.co.kr:47741/xe_tip/4657
Read More
Links/button disabled until another button is clicked:

Links/button disabled until another button is clicked:

Javascript
Links/button disabled until another button is clicked:  Click to the following link to read the article: http://stackoverflow.com/questions/14654013/links-button-disabled-until-another-button-is-clicked
Read More
PHP mail with Multiple Attachments

PHP mail with Multiple Attachments

PHP
PHP mail with Multiple Attachments Click to the following link to read the article: https://www.sanwebe.com/2015/12/php-mail-with-multiple-attachments
Read More
[CSS study] CSS Learning Site

[CSS study] CSS Learning Site

CSS
[CSS study] CSS Learning Site Click the link to go to the blog site: http://jaewook.net/archives/375 === ▶ CSS개념을 잡기에 좋은 사이트...
Read More
Making a contact form with file upload support

Making a contact form with file upload support

HTML
Making a contact form with file upload support Click to the following link to read the article: http://www.html-form-guide.com/contact-form/contact-form-attachment.html
Read More
jQuery Column Chart Example

jQuery Column Chart Example

Ajax Jquery
jQuery Column Chart Example Click to the following link to read the article: http://canvasjs.com/docs/charts/integration/jquery/chart-types/jquery-column-chart/
Read More
Ajax Contact Form with an Attachment (jQuery & PHP)

Ajax Contact Form with an Attachment (jQuery & PHP)

Ajax Jquery
Ajax Contact Form with an Attachment (jQuery & PHP) Click to the following link to read the article: https://www.sanwebe.com/2014/04/ajax-contact-form-attachment-jquery-php
Read More
Atmel Studio 7 설치 후 Atmega128 작동시키기
C/C++

Atmel Studio 7 설치 후 Atmega128 작동시키기

Click the link to read the original article: Here

===================

AT128A-75B 라는 Atmega128 MCU을 사용한 제품을 구매해서 처음 구동시켜보려고 합니다.
아두이노만 사용하다가 처음 사용하는데 감이 잘 오지 않네요.

https://www.devicemart.co.kr/1149213
AT128A-75B Plus MKII 라는 제품을 구매했습니다. ( AT128-75B 에 MKll 를 추가로 주는 것 같습니다. )

https://www.google.co.kr/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&ved=0ahUKEwj5hY3NjI3TAhVCz1QKHeOlA_EQFggaMAA&url=https%3A%2F%2Fwww.devicemart.co.kr%2Finclude%2Fdown.php%3Ffile%3D%2Fdata%2Fgoods%2Fgoodsfile%2F1149213_file_0.pdf%26mode%3Dgoods%26name%3DAT128A-75B%2520Plus_MKII_%25B8%25C5%25B4%25BA%25BE%25F3.pdf&usg=AFQjCNEniDJ7KJi3UTCn0SLWOMNMg17xhg&sig2=xFLZQegpNL_KhcBpMKypsQ&cad=rjt

위의 링크에서 매뉴얼을 확인 할 수 있습니다.

위 제품은 usb Btype, isp, JTag 방식으로 파일 전송이 가능한 제품이라고 하여 구매하게 되었습니다.

마이크로프로세서 책 들을 읽어보니 데이터 전송 방식에는 여러가지가 있는데 isp, jtag? 등등
대부분 isp 를 이용하는 듯 하였고, 단순히 usb 로 전송하는 것 보다는 isp 전송 방식을 알고 싶어서 구매한 제품입니다.

위의 2*5 짜리는 JTAG 아래의 2*3 짜리는 ISP 통신용입니다. )

http://www.atmel.com/tools/atmelstudio.aspx#download

다음으로는 위 경로로 들어가서 atmel studio 7을 설치합니다.

위와 같이 설치가 완료 되었습니다.

위와 같이 ATmega 128 을 선택해줍니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <avr/io.h>
#include <util/delay.h>
int main(void)
{
    //포트D를 출력으로 설정한다.
    DDRD = 0xFF;
    /* Replace with your application code */
    while (1)
    {
        //포트D의 값을 0xFF로 한다. LED가 켜진다.
        PORTD  = 0xFF;
        _delay_ms(300); //300ms 대기
        //포트D의 값을 0x00으로 한다. LED가 꺼진다.
        PORTD = 0x00;
        _delay_ms(300); //300ms 대기
    }
}
cs
 

위의 소스코드를 넣어주고 D 포트 0~7 번에 출력을 설정하고 LED와 저항을 연결해준다.

그리고 빌드해주면 ??

이런 창이 뜨면서 Selected debugger/programmer 를 선택하라고 합니다.

저는 AVRISP MKll 를 선택했구요

그 다음 코드를 실행하면 ??

잘 작동합니다.

– 출처 –
http://webnautes.tistory.com/674
http://jjungineer.tistory.com/3

C++ 기초
C/C++

C++ 기초

Click the link to read the original article: TCPSchool.com

====

C++ 개요


C++

C++은 기존의 C언어에 여러 가지 기능을 추가하여 만든 프로그래밍 언어입니다.

C++은 C언어에서 절차 지향적 언어의 특징을 가져왔을 뿐만 아니라, 클래스를 사용하는 객체 지향적 언어인 동시에 템플릿으로 대변되는 일반화 프로그래밍 방식의 언어이기도 합니다.

 

C++ 수업 시작 =>

 

여러분이 직접 코드를 변경하고, 그 결과를 확인할 수 있는 온라인 에디터가 준비되어 있습니다.

예제

#include <iostream>

#define TEXT “Welcome to C++ Programming!!”

int main()

{

    std::cout << TEXT;

    return 0;

}

11 Best PHP Frameworks for Modern Web Developers in 2018
PHP

11 Best PHP Frameworks for Modern Web Developers in 2018

Click the link to read the original article: Here

=============

11 Best PHP Frameworks for Modern Web Developers in 2018

Best PHP Frameworks for Modern Developers

With PHP being the most popular server-side programming language to date, We have put together the best PHP frameworks for 2018 that have emerged which offer developers the ability to build more complex, secure, and well-rounded web applications faster than ever before. Frameworks for PHP come in all sorts of shapes and sizes and have targeted developers with different levels of experience, application needs, hosting capabilities, and development time-frames.

Contents [show]

Below is a quick summary of pros and cons for each framework. We’ve linked each framework for your convenience to read more about each one.

Best PHP frameworks Compared

For a Thorough 2018 update and revisit to this topic we decided to dig deeper and find what is not only the most used framework for 2018, but which is the utmost valuable? When surveying google Trends, it is explicit that Laravel still remains the most searched framework for all new PHP projects. Just have a look here:

Google Trends Graph of the best PHP Frameworks Compared

Taking it a step, further I wanted to see what authentic everyday coders as well as novices are learning / using on a day to day basis. We took the time to give a survey to our progressive subscribers and notably came back with over 7,500 results.

Our survey queried subscribers on in depth questions such as specific uses of authentication, session coding, caching methods, and routing, but the results listed below will just be overall use starting with the top being the top used php framework. What we must note is the survey doesn’t completely correlate with how our recommended list is in order of most recommended, but rather real data of how much each person uses each framework. Afterall, all coder’s typically get in the groove of a certain programming language then prefer that over others. some that end up using zend also incorporate their skills in network management. Those that combine zend or Laravel with a free syslog server (as seen here at ITT systems), have the best of both worlds.
 

PHP Framework Used for Project UseLaravelCode IgniterSymfonyZendYii 2CakePHPFuel PHPFatFreeAura43.7%12.5%13.6%14.9%

Framework Quantity
Laravel 3,177
Code Igniter 1,085
Symfony 990
Zend 907
Yii 2 373
CakePHP 402
Fuel PHP 172
FatFree 91
Aura 66

What are the Top Rated PHP Frameworks of 2018?

프레임워크(FRAMEWORK)란
PHP

프레임워크(FRAMEWORK)란

Click the link to read the original article: Here

===========================

프레임워크(FRAMEWORK)란

2011. 1. 7. 16:56

 이웃추가

프레임워크란 이렇다고 누군가는 정의했다.

 

대부분의 프레임워크 정의에서 내포하고 있는 의미는 “애플리케이션 개발에 바탕이 되는 템플릿과 같은 역활을 하는 클래스들과 인터페이스의 집합“이다. 즉, 프로그램의 전체적인 구조와 흐름을 확정지으며, 프로그래머가 정의해야 할 메소드의 이름까지고 결정짓는 역할을 한다.

프레임워크란 것의 정의가 참 애매하고 사람마도 조금씩은 다른 것같다.

그래서 나같은 초짜는 더욱 햇갈리고, 오묘해진다.

경력과 연륜이 내게 더욱 구체적인 정의를 내려줄지는 아직 의문이다.

 

프레임워크에 대해서 구글링 중 에너지관리공단에 올라온 글을 발췌했습니다.

쉽게 이해하는데 도움이 될까 퍼왔습니다.

문제가 되면 삭제하겠습니다.

 

프레임워크(FRAMEWORK)란

프레임워크는 공장과 같습니다.
옷 공장, 신발 공장, 만두 공장 등 공장마다 서로 다른 제품을 생산 합니다.
제품을 만들기 위해 어떤 재료를 사용 하냐에 따라 같은 제품일지라도 품질, 디자
인 등 여러 면이 달라집니다.
하지만 공장이라는 개념을 봤을 경우 공장은 재료를 준비하고 가공하고 생산 하는
일은 같은 원리입니다.

프레임워크도 같은 개념입니다. 애플리케이션을 구축할 때 모든 애플리케이션의 공
통적인 부분을 제공해줍니다.

 

예를 들면 웹 애플리케이션을 구축 한다고 예를 들겠습니다.

웹 애플리케이션을 구축하려면 우선 웹에 맞는 환경설정과 DB에 연결하는
부분, 사용자에게 보여주는 부분 등 모든 웹 애플리케이션의 공통적인 부분입니다.
이런 부분을 제공해주는 것이 프레임워크입니다.

그렇다보니 애플리케이션 구축 시간이 빨라지며 비용이 절감됩니다.

 

(비용 절감은 많은 것이 있겠지만 대표적인 것이 인력비용입니다.). 그래서 현재 애플리케이션 구축에 있어서 프레임워크를 이용하여 구축하는 사례가 많아지고 있습니다.
현재 많이 알려진 프레임워크는 MS사에서 개발한 “.NET” 프레임워크입니다.
“.NET” 프레임워크에서는 웹 환경에서도 개발 할 수 있도록 만들어진 프레임워크
입니다. 그래서 “.NET” 많은 웹 언어(JSP, PHP, ASP 등)를 사용 할 수 있게 되었
습니다. 하지만 많은 언어를 수용하다 보니 상당히 무겁습니다.

 

그리고 MS사의 특징이 오픈소스가 아닌 오프소스이며, 무료가 아닌 유료입니다.

그래서 “.NET” 프레임워크를 사용하게 되면 고정된 운영체제(윈도우 NT기반) 사용과 많은 메모리가
필요하며, 비용이 많이 들어간다는 단점이 있어서 현재 많이 개발되고 있는 않는
프레임워크입니다.

그래서 오픈소스이고 비용절감이 되는 프레임워크가 대두 되었고 그중 하나가 자바 기반을 제공해주는 스트럿츠 프레임워크가 대표적입니다.스트럿츠 프레임워크는 자카르타사에서 개발된 프레임워크입니다.
스트럿츠(STRUTS) 용어를 보면 “지주, 버팀목, 받침대” 라는 뜻을 갖고 있습니다.
그래서 스트럿츠라는 용어를 사용하게 된 것입니다.
스트럿츠 프레임워크는 자바 기반으로한 웹 언어인 JSP만을 위한 프레임워크입니다.

자바 기반이기 때문에 자바의 장점을 그대로 갖고 있습니다.

독립된 플렛폼 사용하여 운영체제에 구애 받지 않고, 오픈 소스라 개발에 필요한 부분을 수정하여
사용 할 수 있습니다.

 

그리고 무료배포를 한다는 것이 큰 장점 이며, 한 언어만 사용하다 보니 상당히 가볍습니다.

자바에서는 표준 프로토콜(TCP/IP, XML 등)을 사용하기 때문에 안정적입니다.

이런 장점 때문에 스트럿츠 프레임워크 기반으로 개발되는 추세입니다.

스트럿츠 프레임워크는 MVC(Model-View-Controller) 패턴 기반을 이용하여 개발되었습니다.

MVC 패턴은 이름 그대로 로직을 처리 해주는 Model 부분과 사용자에
게 보여주는 View 부분 그리고 Mode1 부분과 View 부분을 연결하고 제어하는 Controller 부분이 있습니다.
MVC 패턴을 이용하게 된 이유는 유지보수가 쉽고 빠른 시간에 애플리케이션을 구축 할 수 있는 장점이 있습니다.

그래서 MVC2 개발 방법이 나왔지만 재사용성이 떨어지는 단점이 있어서

그것을 보안하게 나오는 개발 방법이 스트럿츠 프레임워크 기반 개발 방법인 것입니다.

애플리케이션의 구축에 있어서 반은 개발기간에 사용되며, 반은 유지보수를 위해 사용되고 있습니다.

그 만큼 현재 개발되는 애플리케이션의 유지보수의 중요성이 대두 되고 있습니다.

유지보수가 잘 된다면 사용자 입장에서는 보다 안정적이고 효율적으로 애플리케이션을 사용 할 수 있는 것입니다.

그래서 유지보수가 쉽고 안정적인 애플리케이션을 구축하기 위해 MVC 패턴을 이용한 스트럿츠 프레임워크 기
반으로 개발되고 있습니다.

스트럿츠 프레임워크를 이용하여 개발 했을 경우의 장점을 게시판을 예를 들어 간단히 설명하겠습니다.
게시판 리스트를 보여주기 위해서 기존의 방법(Model 1)에서는 jsp 파일에서 보여
주기 위한 로직을 사용 했습니다.

 

즉, DB로부터 읽어온 데이터를 보여주기 위해 for문이나 while문을 이용하여 보여 주었습니다.

하지만 스트럿츠의 View 부분인 jsp 파일에서는 DB에서 읽어온

데이터를 가져오는 Model 부분의 처리 함수만 불러 오면 되는 것입니다.

 

이때 만약 게시판 리스트 개수를 수정 하겠다 하면 Model1 방식에서는 jsp 파일에서 수정해야 하는 불편이 있습니다.

(사실, 이거 하나 수정하는데도 해당 jsp파일을 읽어야 하는 불편이 있습니다.)

하지만 게시판 리스트를 불러오는 Model 부분의 처리 함수에서만 수정하면 됩니다.

이것만 봐도 유지보수가 쉽게 알 수 있습니다.

만약 게시판의 디자인을 수정 시 Model 1방식에는 잘못하다간 게시판의 로직부분과 연결되어 있어 수정 또는 다른 오류 상황이 발생할 수 있는데 스트럿트에서는 보여주는 부분과 로직 부분이 완전히 분리 되어 있어서 이런 상황이 발생 되지 않는 안정성을 갖고 있습니다.

잠시 유지보수 중요성에 대하여 간단히 설명하겠습니다.
만약 아파트에서 산다고 가정하겠습니다. 아파트에서 살다가 벽에 금이가고 물이 센다면 이럴 경우 어떻게 하십니까? 사비를 들여 해결 할 수 있는 문제가 아닙니다. 그 아파트를 시공한 회사에 의뢰를 하게 됩니다. 공사가 끝나고 그 공사비를 받는 것은 아닙니다.

그건 그 시공사에서 그 아파트의 유지보수 부분인 것입니다. 이렇듯 애플리케이션도 같습니다. 애플리케이션이 구축 했다고 끝나는 것이 아니라 사후에 발생되는 문제점을 해결하기 위한 유지보수까지 되어야 애플리케이션 구축이 끝난 것입니다. 문제점이 발견되었을 경우 얼마나 신속하고 정확하게 해결하는 것이 유지보수 방법 중 하나입니다.

그래서 개발자는 유지보수의 중요성을 느끼게 되었고 나온 방법이 MVC 패턴을 이용한 MVC2 기반 개발 방법이며, MVC 2 기반 개발 방법의 단점을 보안하여 나온 방법이 스트럿츠 프레임워크를 이용한 개발 방법입니다.

–문슈리뷰 : java로 개발할 당시 , 개발을 배울 당시 프레임워크의 중요성을 여러번 배웠고,

그로 인해 mvc2 패턴의 개발 방식으로 프로젝트를 진행하였다.

델파이를 시작하고 다시 처음으로 회귀하여 ,

한 소스 코드내에서 모듈과 콘트롤 , 뷰를 한번에 처리하고 있다.

이러면 유지보수나 여러면에서 불편한 점이 있지만, 현재 기간내 빨리 만들어서 배포하여야

한다는 핑계로 쭈욱 현 상황이 진행되고 있다.

보다 더 스킬을 업해서 다음 프로젝트 때는 이런 면에서 확실히 정리된 프로젝트에 투입해서

배우고 싶다.

ORM 프레임워크(Object-relational mapping)
C/C++

ORM 프레임워크(Object-relational mapping)

Click the link to read the original article: Here

==============================================

ORM 프레임워크(Object-relational mapping)

Jayzzz 2017.10.11 15:34

 ORM은 데이터베이스와 객체 지향 프로그래밍 언어간의 호환되지 않는 데이터를 변환하는 프로그래밍 기법이다. 객체 관계 매핑이라고도 한다. 객체 지향 언어에서 사용할 수 있는 ‘가상’ 객체 데이터베이스를 구축하는 방법이다.

ORM(Object-relational mapping)을 단순하게 표현하면 객체와 관계와의 설정이라 할 수 있다. ORM에서 말하는 객체(Object)의 의미는 우리가 흔히 알고 있는 OOP(Object Oriented Programming)의 객체를 의미한다는 것을 쉽게 유출할 수 있다. 그렇다면 그 관계라는 것이 의미하는 것은 무엇일까? 지극히 기초적인 이야기지만 개발자가 흔히 사용하고 있는 관계형 데이터베이스를 의미한다.

ORM개념이 나온 이유는 코딩의 반복적인 부분을 줄일 수 있고 SQL의 의존적인 코딩에서 벗어나 생산적인 코딩이 가능하며 유지보수가 편의하기 때문이라 할 수 있다.

 

 

ORM 등장배경

 

1. Model1 개발방식

 

~ 초기 데이터베이스 개발모델

~ JSP, Servlet에서의 persistence layer처리

~ 장점 : 배우기 쉽다. 빠른 시간 내에 개발 할 수 있다.

단점 : 복잡도 증가, 유지보수가 어렵다.

~ 비객체지향적 프로그래밍

 

 

2. Model2 개발방식

 

~ MVC모델에서의 데이터베이스 개발 모델

~ DAO, EJB(CMP)를 이용한 Persistence layer 개발

~ 장점 : MVC 모델 적용이 가능하다. 객체 단위의 개발이 가능하다.

단점 : MVC/EJB에 대한 이해도가 필요하다. 유지보수가 어렵다.

 

 

3. ORM 개발방식

 

~ Persistence Layer를 담당하는 Framework 개발모델

~ iBatis, Hibernate와 같은 persistence를 담당하는 Framework

~ 장점 : 객체지향적 프로그래밍이 가능하다. 쿼리를 이용하게 business layer에 집중 할 수 있다.

단점 : Framework 이해도가 필요하다.

 

 

 

ORM프레임워크 장점

 

~ 객체 지향적인 코드로 인해 더 직관적이고 비즈니스 로직에 더 집중할 수 있게 도와준다.

* 선언문, 할당, 종료 같은 부수적인 코드가 없거나 급격히 줄어든다.

* 각종 객체에 대한 코드를 별도로 작성하기 때문에 코드의 가독성을 올려준다.

* SQL의 절차적이고 순차적인 접근이 아닌 객체 지향적인 접근으로 인해 상산성이 증가한다.

 

~ 재사용 및 유지보수의 편리성이 증가한다.

* ORM은 독립적으로 작성되어있고, 해당 객체들을 재활용 할 수 있다. 때문에 모델에서 가공된 데이터를 컨트롤러에 의해 뷰와 합쳐지는 형태로 디자인 패턴을 견고하게 다지는데 유리하다.

* 매핑정보가 명확하여 ERD를 보는 것에 대한 의존도를 낮출 수 있다.

 

~ DBMS에 대한 종속성이 줄어든다.

* 대부분 ORM 솔루션은 DB에 종속적이지 않다.

* 종속적이지 않다는 것은 구현 방법 뿐만아니라 많은 솔루션에서 자료형 타입까지 유효하다.

* 프로그래머는 Object에 집중함으로 극단적으로 DBMS를 교체하는 거대한 작업에도 비교적 적은 리스크와 시간이 소요된다. 또한 자바에서 가공할 경우 equals, hashCode의 오버라이드 같은 자바의 기능을 이용할 수 있고, 간결하고 빠른 가공이 가능하다.

 

ORM프레임워크 단점

 

~ 완벽한 ORM으로만 서비스를 구현하기가 어렵다.

* 사용하기는 편하지만 설계는 매우 신중하게 해야한다.

* 프로젝트의 복잡성이 커질경우 난이도 또한 올라갈 수 있다.

* 잘못 구현된 경우에 속도 저하 및 심각할 경우 일관성이 무너지는 문제점이 생길 수 있다.

* 일부 자주 사용되는 대형 쿼리는 속도를 위해 SP를 쓰는 등 별도의 튜닝이 필요한 경우가 있다.

* DBMS의 고유기능을 이용하기 어렵다.

(하지만 이건 단점으로만 볼 수는 없다. 특정 DBMS의 고유기능을 이용하면 이식성이 저하된다.)

 

~ 프로시저가 많은 시스템에서는 ORM의 객체 지향적인 장점을 활용하기 어렵다.

* 이미 프로시저가 많은 시스템에선 다시 객체로 바꿔야하며, 그 과정에서 생산성 저하나 리스크가 많이 발생 할 수 있다.

 

 

정리

 

ORM이 없을때는 개발자가 개발을 하며 DB에 접근하기 위해서 SQL Query를 직접 만들었다. 여기서 문제점은

1. SQL문법을 숙지해야한다는 점(물론 숙지해야하는 것은 당연하지만 SQL문법 이유로 개발이 지체되는 것은 문제라고 볼 수 있다.)

2. 개발 코드와 DB가 서로 종속되게 한다.

이였다.

이러한 문제점을 해결하기 위해 ORM이 등장하였고 ORM의 등장으로

1. SQL문법에서 자유로워 졌고

2. 개발 코드와  DB를 독립하므로 유지보수가 편리해져서 객체지향의 의도에 부합하게 되었다.

 

즉 객체지향 프로그래밍에서 데이터베이스를 관리 할때 데이터베이스 언어(SQL)를 숙지하고 쿼리로 인한 코드 가속석 저하, 프로그램과 DB관리를 독깁하기 위함과 객체를 저장하는 문제 등으로 ORM프레임워크가 등장하게 되었다.

ORM 이란 무엇인가?
C/C++

ORM 이란 무엇인가?

Click the link to read the original article: Here

=========================

ORM(Object-Relational Mappings)라는 건 과연 무엇일까?

근래 많이 보고 듣는 단어이고 ORM Framework이나 Tool이니 하면서 Hibernate나 iBatis, Toplink등등의 이름들도 많이 듣게 된다. 과연 이 ORM이라는 것이 무엇이길래 왜 이렇게 많은 사람들의 입에 오르내리는 것일까?

ORM이라는 것을 단순하게 표현해보자면 객체와 관계와의 설정? 정도일까? 그럼 여기서 말하는 객체라는 것은 우리가 흔히 말하는 OOP(Object-Oriented Programming)의 그 객체를 이야기 하는 것 이라면, 과연 관계라는 것이 의미하는 것은 무엇일까? 뭐 지극히 기초적인 이야기지만 우리(개발자)가 흔히 사용하고 있는 관계형 데이터베이스를 의미한다.

그렇다면 도대체 무엇이 문제여서 객체와 관계형 데이터베이스 간의 매핑을 지원해주는 Framework이나 Tool들이 나오는 것일까? 이미 우리는 OOP를 하면서 객체와 관계형 데이터베이스를 모두 잘 사용하고 있지 않은가? 그런데도 굳이 이런 새로운 개념들이 나오게 되는 이유는 흔히 말해서 Back to basics 라고 볼 수 있겠다. 즉, 보다 OOP다운 프로그래밍을 하자는 데 에서부터 출발한 것이다.

그럼 과연 무엇이 문제였던 것일까? 생각해보면 당연하게 문제가 있을 수 밖에 없다고 생각되어진다. 스스로 한번 생각해보자. 우리가 어떤 어플리케이션을 만든다고 할 때 관련된 정보들은 객체에 담고 있게 된다. 많이들 예를 드는 주소록을 만든다고 생각을 해보자. 일단은 주소록의 주체가 될 사람이라는 객체가 있다고 가정해보면 주민등록번호, 이름, 키, 몸무게 등등이 저장될 것이다. 그리고 주소라던지 전화번호등이 저장 될 다른 객체(여기서는 주소만을 가정해보고 주소라는 객체라고 가정한다.)도 있게 될 것이다. 그럼 이것을 영구적으로 저장하기 위해서 파일이나 데이터베이스에 입력을 한다고 하면, 객체와 객체들의 관계를 데이터베이스의 테이블에 저장을 하게 된다는 말과 동일하게 된다. 즉 table들에 객체가 가지고 있던 정보를 입력하고 이 table들을 join과 같은 sql query문을 통해서 관계를 설정해주게 된다. 여기서 문제는 이 table들과 객체간의 이질성이 발생을 한다는 것이다.

보통 ORM Framework들은 이러한 이질성을 해결하기 위해서 객체와 table간의 관계를 설정하여 자동으로 처리를 해준다는 것이다. 개인적으로 많은 ORM Framework를 접해본 것이 아니라서 어떤 방법들이 사용되는지는 잘 모르겠지만, 예를 들어서 눈으로 확인해보자면 다음과 같은 Person이라는 객체가 있다고 가정한다.

 

public class Person {

private String name;

private String height;

private String weight;

private String ssn;

// implement getter & setter methods

}


iBatis의 경우에는 다음과 같이 mapping file내에서 해당 query의 결과를 받을 객체를 지정해 줄 수 있다.

<select id=”getPerson” resultClass=”net.agilejava.person.domain.Person”>

SELECT name, height, weight, ssn FROM USER WHERE name = #name#;

</select>


즉, 이 getPerson라고 정의된 query의 결과는 net.agilejava.person.domain의 Person객체에 자동으로 mapping 되는 것이다. Hibernate의 경우에는 mapping 파일에서 다음과 같이 표현을 해준다.

<hibernate-mapping>

<class name=”net.agilejava.person.domain.Person” table=person”>

<id name=”name” column=”name” />

<property name=”height” column=”height” />

<property name=”weight” column=”weight” />

<property name=”ssn” column=”ssn” />

</class>

</hibernate-mapping>

 

위 두개의 Framework의 예시를 보면 알 수 있듯이 setter 메소드가 있다면 객체에 결과를 set하는 작업들이 따로 필요한 것이 아니라 자동으로 setting 되는 것이다. 물론 여기에 추가적으로 1:m 이나 m:1 등의 관계들이 형성되면 추가적인 작업이 필요하긴 하지만 어쨌든 일단 눈에 보이는 간단한 부분은 처리가 되는 것을 볼 수 있다. 물론 반대의 경우에도 객체를 던져주면 ORM Framework에서 알아서 get을 해와서 해당하는 column에 넣어주게 된다.

 

어떻게 보면 더 복잡해 보일 수 도 있는 ORM이지만 막상 사용해보면 그 편리함에 몸을 떨게 된다. 단순하게 get/set만 해주는게 목적이 아니라 객체지향적인 시스템을 위해서 관계형데이터베이스의 설계부터 변화를 주고, 설계된 데이터베이스와 객체와의 관계에 대한 설정 등을 포함하여 보다 객체지향적인 시스템의 완성을 위한 도구라고 말할 수 있겠다. 물론 ORM이라는 것이 흔히 말하는 silver bullet은 절.대. 아니다. 이 녀석이 쓰여서 이득을 볼 수 있는 부분이 존재할 것이며, 쓰지 않아서 이득을 볼 부분이 존재 할 것이다. 많은 사람들이 ORM에 대하여 우려하고 있는 부분은 객체지향적으로 설계되지 않은 데이터베이스에서의 사용에 따른 폐혜라고 생각한다. 이미 데이터베이스 중심적인 사고를 통하여 만들어 놓은 데이터베이스에 ORM을 도입을 해서도 분명 이점이 있긴하겠지만, 그에 비해서 개발자들의 학습곡선 이라던지, 기존에 존재하는 코드나 시스템들과의 연계 또는 유지보수적인 측면, 그리고 성능 등에서 생각해보면 부정적으로 볼 수 밖에 없다. 즉, 전체적인 시스템의 분석,설계 단계에서부터 객체와 데이터베이스를 따로 생각하는 것이 아니라 하나의 덩어리로 인지하고 양쪽 모두를 고려한 설계를 해나갈 수 있을 때, ORM은 보다 좋은 모습을 보여주고 각광을 받을 수 있을 것이다

출처 : evilimp‘s Blog



출처: http://civan.tistory.com/156 [행복만땅 개발자]

AngularJS 란 무엇인가?
angularJs

AngularJS 란 무엇인가?

AngularJS 란 무엇인가?

Click to the link to go to the site:

===============

AngularJS 개념

AngularJS 는 SPA(Single Page Application) 프레임워크라고 합니다.

예를 들어, 하나의 웹 페이지가 실행할 때 View 단에 해당되는 부분이 페이지의 주소가 바뀌지 않으면서 또 다른 새로운 view 를  동적으로 로드하여  사용하는 것을 SPA 라고 합니다.

이러한 SPA 를 편하게 사용하도록 도움을 주는 것이 AngularJS 와 같은 자바스크립트 프레임워크입니다.

그래서 AngularJS 는 SPA 를 만들때 도움을 주는 프레임워크이고 자바스크립트 기반의 MV* 오픈소스 프레임워크라고도 합니다.

결론적으로 SPA & 자바스크립트 기반의 MV* 프레임워크입니다.

MVC

그렇다면, MV* 패턴은 무엇인가?

자바스크립트 공부를 시작하면서 생소한 용어들 중에 디자인 패턴이란 용어가 있습니다.

디자인 패턴은 건축으로치면 공법에 해당하는 것으로 소프트웨어의 개발 방법을 공식화 한 것으로써, 소수의 뛰어난 엔지니어가 해결한 문제들에 대한 규칙들을 다수의 엔지니어들이 문제를 처리 할 수 있도록 한 규칙들이면서, 구현자들 간의 커뮤니케이션의 효율성을 높이는 기법을 디자인 패턴이라고 합니다.

MVC란 Model View Controller의 약자로 에플리케이션을 세가지의 역할로 구분한 개발 방법론입니다.

아래의 그림처럼 사용자가 Controller를 조작하면 Controller는 Model을 통해서 데이터를 가져오고 그 정보를 바탕으로 시각적인 표현을 담당하는 View를 제어해서 사용자에게 전달하게 됩니다.

위의 그림을 웹에 적용해 보자면…

1. 사용자가 웹사이트에 접속한다. (Uses)

2. Controller는 사용자가 요청한 웹페이지를 서비스 하기 위해서 모델을 호출한다. (Manipulates)

3. 모델은 데이터베이스나 파일과 같은 데이터 소스를 제어한 후에 그 결과를 리턴한다.

4 .Controller는 Model이 리턴한 결과를 View에 반영한다. (Updates)

5. 데이터가 반영된 VIew는 사용자에게 보여진다. (Sees)

 

Controller

사용자가 접근 한 URL에 따라서 사용자의 요청사항을 파악한 후에 그 요청에 맞는 데이터를 Model에 의뢰하고, 데이터를 View에 반영해서 사용자에게 알려준다. 

Model

일반적으로 CI의 모델은 데이터베이스 테이블에 대응된다. 이를테면 Topic이라는 테이블은 topic_model이라는 Model을 만든다. 그런데 이 관계가 강제적이지 않기 때문에 규칙을 일관성 있게 정의하는 것이 필요하다.

View

View는 클라이언트 측 기술인 html/css/javascript들을 모아둔 컨테이너이다. 

MV* (통칭으로 MVstar 라고 말합니다)

– MVC

Model

View

Controller

– MVVM (Model-View-ViewModel)

– MVP (Model View Presenter)

MVC 패턴의 프레임워크를 통칭적으로 MV스타(MV*) 프레임워크라고 합니다.

AngularJS 참고사이트

출처: http://webclub.tistory.com/206 [Web Club]

Angular Seed

 – 처음 시작을 위한 기본구조 제공

 – http://github.com/angualr/angular-seed 

 – http://ionicframework.com

AngularJS 구성요소

1. 지시자(Directive) 

– 뷰(View) 영역 

– 특정한 html 태그에 AngularJS 의 기능을 적용하고자 할 때 사용하는 것이 Directive 란 지시자를 사용하는데 AngularJS 의 Directive 는 ng 로 시작하는 지시자들이 많이 있습니다. 예) ng-*

2. 필터(Filters) 

– 어떤 데이터를 화면에 출력하는데 있어서 원하는 데이터만을 필터링하여 가져다 사용할 수 있도록 해주는 기능입니다.

3. 데이터 바인딩(Data Binding) 

– 표형태의 데이터들을 원하는 위치에 사용하기 편하게 바인딩하도록 해줍니다.

4. 컨트롤러(Controller) 

– 메인 컴포넌트 

– 기능별로 묶어서 사용하도록 해줍니다.

5. 서비스(Service) 

– 비즈니스 로직

AngularJS Expressions(표현식)

표현식 (Expressions)

– {{ }} 로 사용됨 (표현식 안에는 자바스크립트 문법을 사용할 수 있습니다)

– JavaScript 의 모든 문법을 지원하지 않음.

– 배열 등 선언 가능합니다.

사용 예

– {{ 표현식 }}

– {{ name }} 

– {{ 3 % 5 }} 의 결과값이 출력됩니다.

– {{ “안녕” + “하세요“ }} 문자열과 문자열을 접합한 결과가 나타납니다.

지시자(Directive)

새로운 형태의 HTML 태그/속성/속성값을 만들어서 정의해주는 것을 지시자라고 합니다.

다음의 ng-app=”” 과 같은 태그와 속성/속성값을 정의할 수 있습니다.

ex) <body ng-app=””>

위의 코드와 같이 html 이나 body 태그에 ng-app=”” 을 지시자를 명시해 줌으로써 AngularJS 를 사용할 준비 단계를 설정합니다.

ng-app 은 data-ng-app 으로 사용할 수 있는데 ng 앞에는 모두 data 가 생략되어 있습니다.

다시말해서, ng-app 은 모듈을 정의해 주는 것입니다.

출처: http://webclub.tistory.com/206 [Web Club]

React와 불변객체
react.js

React와 불변객체

블로그 사이트 바로가기

이번에는 불변객체의 개념과 React에 그 개념을 적용했을 때 어떤 이점을 얻을 수 있는지 소개하고자 합니다.

불변객체란?
객체 지향 프로그래밍에 있어서 불변객체(Immutable object)는 생성 후 그 상태를 변경할 수 없는 객체를 말합니다. 불변객체의 반대말은 가변객체로 자바스크립트의 배열과 같이 객체 내에서 관리하는 값이나 상태를 변경할 수 있는 것을 말합니다.

var greeting = new String(‘Hello World!!’);

greeting.replace(‘World’, ‘Gil-dong’);
greeting.valueOf(); // Hello World!!
위 예에서 greeting 변수에 문자열 객체를 생성해 대입했습니다. 그리고 문자열 객체의 replace 메서드를 이용해 ‘World’라는 문자열을 ‘Gil-dong’으로 변경했습니다. 하지만 여전히 greeting의 값은 ‘Hello World’ 입니다.

greeting에 생성한 문자열 객체는 불변 객체이므로 객체 자신이 소유하거나 관리하는 값 또는 상태를 바꿀 수 없습니다. 따라서 replace 메서드는 새로운 상태를 가지는 또 다른 객체를 생성합니다.

변수에 값을 바꾸기 위해서는 아래 처럼 새로운 객체를 변수에 대입해야 합니다.

var greeting = new String(‘Hello World!!’);

greeting = greeting.replace(‘World’, ‘Gil-dong’);
greeting.valueOf(); // Hello Gil-dong!!
값 객체
이러한 불변 객체의 특성은 우리가 밀접히 사용하는 Number, String, Boolean과 같은 값 객체에서 만날 수 있습니다. 값 객체란 비교 연산 시 자신의 상태보다 값(value)을 우선하는 단순한 객체를 말합니다.

자바스크립트에서 비교 연산
여기에서는 이해를 돕기 위해 생성자를 이용해 문자열이나 정수를 생성하고 있지만, 자바스크립트에서 생성자를 이용해 원시 타입 객체를 생성하면 비교 연산 시 참조를 이용해 비교합니다. 따라서 항상 리터럴 표기법으로 값을 다루기 바랍니다.

new String(‘Hello’) === new String(‘Hello’); // false
new Number(5) === new Number(5); // false
값 객체는 값을 이용해 새로운 값을 만들어 낼 수 있지만 값 자체를 변경할 수 없습니다. 즉, 불변입니다.

var num = new Number(2);
num = num + new Number(3);

num.valueOf(); // 5
위에서 숫자 2를 생성한 후 숫자 3을 더해 숫자 5를 얻고 있습니다. 숫자 2에 숫자 3을 더하는 것은 값 자체를 바꾸는 것이 아니라 새로운 값을 생성하는 것입니다. 이러한 특징은 상태를 변화시키지 않으며 새로운 값을 생성하는 함수형 스타일(functional style)과 닮았습니다.

React.js와 불변객체
React 컴포넌트의 라이프 사이클 메서드 중에는 shouldComponentUpdate 메서드가 있습니다. 이 메서드는 컴포넌트가 다시 그려지기 전에 호출되며 만약 false를 반환하면 컴포넌트의 VirtualDOM을 비교하지 않습니다.

다량으로 엘리먼트를 출력하는 리스트나 피드와 같은 컴포넌트는 매번 VirtualDOM을 비교하게 되면 성능 문제가 발생할 수 있으므로 필수로 사용해야 하는 메서드입니다(대도록이면 모든 컴포넌트에 작성하는 습관을 들이는게 좋습니다).

가변 객체일 때
잘 알려진 TodoMVC를 예를 들어 설명하겠습니다.

// todoItem.js
shouldComponentUpdate(nextProps, nextState) {
return (
nextProps.todo !== this.props.todo ||
nextState.label !== this.state.label
);
}
todoItem 컴포넌트의 shouldComponentUpdate 메서드는 prop 속성으로 전달된 todo 객체를 비교하여 VirtualDOM을 비교할지 말지 결정하고 있습니다.

// todoHome.js
onUpdate(todoId, label) {
this.todos.update(todoId, label);
}

// todos.js
update(todoId, label) {
var todo = this._todos.find((todo) => todo.id === todoId);

todo.update(label);
this.emit(‘update’);
}
특정 todo의 label 값을 변경하라고 todos 모델 객체에 요청하고 있습니다. todos 모델 객체는 자신이 관리하는 todo 객체들 중 하나를 찾아서 값을 변경하고 변경 사실을 통지합니다. 하지만 todoItem 컴포넌트의 단순한 비교문으로는 todo 객체의 값이 변경됐는지 알 수 없습니다.

todos 모델 객체에서 관리하는 todo 객체와 prop 속성으로 전달된 todo 객체의 참조가 동일하기 때문에 항상 참이되므로 의도한 결과를 얻을 수 없는 것입니다.

// todoItem.js
shouldComponentUpdate(nextProps, nextState) {
return (
nextProps.todo.label() !== this.props.todo.label() ||
nextProps.todo.completed() !== this.props.todo.completed() ||
nextState.label !== this.state.label
);
}
shouldComponentUpdate 메서드의 비교문을 변경했습니다. 조금 복잡해졌습니다. 만약 하나의 객체에서 관리하고 있는 상태가 많을수록 이 비교문은 아주 복잡해질 것입니다.

하지만 여전히 이 코드는 동작하지 않습니다. todos 모델 객체에서 특정 todo 객체의 상태를 변경하면 같은 todo 객체를 참조하는 todoItem 컴포넌트에도 동일하게 반영돼 상태가 변경됐는지 알 수 없습니다. 이처럼 가변 객체의 참조를 가지고 있는 어떤 장소에서 객체를 변경하면 참조를 공유하는 모든 장소에서 그 영향을 받기 때문에 객체를 참조로 다루기란 쉽지 않습니다.

// todoHome.js
render() {
var todos = this.props.todos.forEach((todo) => {
return <TodoItem key={todo.get(‘id’)} todo={todo.clone()} />;
});

return (
<ul>{todos}</ul>
);
}
이번엔 clone 메서드를 이용해서 todo의 객체 상태를 전부 복사하여 새로운 todo 객체를 만들어 todoItem 컴포넌트에 전달하고 있습니다. 이러한 방법을 방어적 복사(defensive copy)라고 합니다.

드디어 코드는 의도한대로 동작하겠지만, 비교문은 여전히 복잡하며 매번 객체를 전체적으로 복사하는건 성능면에서 좋지 않습니다. 또, 객체의 전달 방식이나 사용 방식을 예의주시해야하는 번거로움도 수반됩니다.

불변 객체일 때
이제 todos 모델 객체의 update 메서드를 Immutable.js를 이용해 불변 객체로 관리하도록 변경해보겠습니다.

// todos.js
class Todos extends events.EventEmitter {
constructor() {
this._todos = new Immutable.List();
}

// … 생략 …

update(id, label) {
// 새로운 List 객체를 생성한다.
this._todos = this._todos.update(
this._todos.findIndex(t => t.get(‘id’) === id),
t => t.set(‘label’, label) // 새로운 todo 객체를 생성한다.
)

this.emit(‘update’);
}
}
todos 객체의 생성자 메서드를 통해 Immutable.js의 List 객체를 생성하고 있습니다. 특정 todo 객체의 값을 변경할 때는 List 객체의 update 메서드를 이용해 새로운 상태를 갖는 todo 객체와 List 객체를 다시 생성하여 설정합니다.

// todoItem.js
shouldComponentUpdate(nextProps, nextState) {
return (
nextProps.todo !== this.props ||
nextState.label !== this.state.label
);
}
이제 비교문이 다시 단순해졌습니다. 객체의 상태가 변하지 않는 한 참조는 항상 같을 것이고, 객체의 상태가 변경될때만 새로운 객체가 생성되므로 참조가 달라집니다. 따라서 단순히 참조만 비교하는 것 만으로도 객체의 상태가 변경됐는지 판단할 수 있습니다.

매번 객체를 새로 생성하면 메모리 관리 시스템에 부담을 줄 수 있다고 생각할 수 있지만 이 점이 시스템 전체적인 병목을 일으키진 않습니다. 오히려 객체의 값을 전체적으로 복사하는 방어적 복사가 더 부담이 될 수 있습니다.

정리
불변 객체는 값을 복사할 필요 없습니다. 객체를 복사할 때는 항상 같은 객체를 참조하는 주소만 반환하면 됩니다. 즉, 객체를 하나 생성하고 이를 지속적으로 재사용할 수 있습니다(Intern) 이처럼 불변 객체는 복사를 단순화할 수 있어 성능적으로 유리할 수 있습니다. 동일한 값을 여러번 복사해도 참조를 위한 포인터 크기 만큼만 메모리가 늘어날 뿐입니다.

또한 React.js의 shouldComponentUpdate 메서드를 통해 알 수 있듯이 비교문을 크게 단순화할 수 있습니다. 이 점이 React.js에서 불변 객체를 사용했을때 가장 피부로 체감할 수 있는 부분입니다. 단순한 비교문은 코드를 관리하기 쉽게 만들어줍니다. 반면, 가변 객체를 여러 뷰 컴포넌트에서 의존하면 이를 추적하고 관리하기 쉽지 않을 뿐더러 비교문도 작성하기 어렵습니다.

Flux 아키텍처에서 말하는 단방향 데이터 흐름과 Immutable.js의 불변 객체, 그리고 수동적인 뷰 특징을 가진 리액트 컴포넌트가 한데 어울어지면 보다 단순하고 사고하기 쉬운 프로그램을 작성할 수 있습니다.

React.js를 이해하다(7)
react.js

React.js를 이해하다(7)

블로그 사이트 바로가기

읽기전에…
이 문서는 koba04님이 작성한 React.js Advent Calendar를 번역한 것입니다. 본래 원문서는 캘린더 형식으로 소개하지만 여기에서는 회를 나눠 작성할 생각입니다. 또한, React 버전 0.12.1 때 작성된 문서이기 때문에 현 버전과 다른 점이 있을 수 있습니다. 최대한 다른 부분을 노트로 작성할 생각이지만, 만약 생략된 부분이 있다면 댓글로 알려주시면 감사하겠습니다.

React.js + CSS
React.js 개발자인 vjeux가 「React:CSS in JS」 라는 주제로 발표를 했는데 그 내용이 꽤 흥미있고 React.js와도 관계가 있는 것이기 때문에 소개하고자 합니다. 또다른 React.js 개발자 zpao의 「React Through the Ages」 라는 발표에서도 이 관점에 관해 언급하고 있습니다.

CSS를 확장할 때의 문제점
Global Namespace
Dependencies
Dead Code Elimination
Minification
Sharing Constantsn
Non-deterministic Resolution
Isolation
여기에서 말하는 확장은 페이스북 정도의 규모에서 확장을 말하는 것 같습니다.

Global Namespace
CSS에서 모든 것은 글로벌 공간에 선언되기 때문에 명명 규칙 등으로 분할할 필요가 있습니다.(부트스트랩은 600개의 전역 이름을 정의하고 있습니다.)

Dependencies
컴포넌트와의 의존 관계를 관리하기 힘듭니다. 컴포넌트 내에서 requireCSS 처럼 CSS를 읽어 들이도록 했다고 하더라도 다른 곳에서 이미 그 CSS를 require 했다면 이미 동작하게 됩니다.

Dead Code Elimination
미사용 코드를 검출하기 어렵습니다.

Minification
class 명의 minification에 관한 것입니다. (저자: 할 필요가 있는지 의문입니다) 이것도 템플릿(HTML or JS)과 CSS를 대응하여 개발할 필요가 있습니다.

Sharing Constantsn
CSS와 JS 측에서 변수를 공유하기 어렵습니다.

Non-deterministic Resolution
CSS에서는 상세한 속성이 같은 경우 나중에 작성한 것이 우선됩니다. 그래서 requireCSS 등의 구조를 사용해 컴포넌트와 같이 비동기로 CSS를 읽을 경우 읽는 순서에 따라 다르게 출력돼 의도하지 않는 결과가 발생할 수 있습니다.

<div class=”foo bar”>xxx</div>
.foo {color: red}
.bar {color: blue}

/* or */

.bar {color: blue}
.foo {color: red}
이를 회피하기 위해서 상세한 속성을 수정하는 등의 작업이 필요할 수 있습니다.

Isolation
React.js에서 Button 컴포넌트를 만들었을 때 이 button 태그의 스타일을 지정하려면 Button 컴포넌트가 어떤 태그 구조로 구현돼 있는지를 알아야 할 필요가 있어 컴포넌트를 잘 분리 할 수 없습니다.

<div className=”foo”>
<Button/> <!– <div><button>xxx</button></div> –>
</div>
.foo > div {

}
그렇다면 CSS in JS
위와 같은 문제는 Sass 같은 CSS Preprocessor 등을 사용하거나 설계 레벨에서 해결 가능한 것도 있지만, CSS를 JavaScript의 Object 형태로 컴포넌트의 스타일을 지정하는데 사용하면 문제를 해결할 수 있지 않을까 하는 접근법입니다. 즉, 템플릿(HTML)을 JS의 안에 가지고 온 것(JSX)처럼 CSS도 JS 안으로 가지고 오겠다는 뜻입니다.

var style = {
container: {
backgroundColor: ‘#ddd’,
width: 900
}
}

var Container = React.createClass({
render() {
return <div style={style.container}>{this.props.children}</div>;
}
});
아래와 같은 함수를 이용하면 조금 더 유연하게 스타일을 지정할 수 있습니다.

function m() {
var res = {};
for (var i=0; i < arguments.length; ++i) {
if (arguments[i]) assign(res, arguments[i]);
}
return res;
}

<div style={m(
style.container,
{ marginTop: 10 },
this.props.isWarning && {color: ‘red’}
)}>xxx</div>
또, Prop을 공개해 밖에서 스타일을 지정하도록 할 수 있습니다.

propTypes: {
style: React.PropTypes.object
},
render() {
return <div style={m(style.container, this.props.style)}>xxx</div>
}
스타일의 우선 순위는 순서를 조절하는 것으로 간단히 변경할 수 있습니다.

propTypes: {
style: React.PropTypes.object
},
render() {
return <div style={m(this.props.style, style.container)}>xxx</div>
}
이처럼 컴포넌트에 직접 지정하는 것으로 상세한 속성 등은 알 필요 없어지고 JavaScript에 가져오는 것으로 프로그래밍적으로 처리 가능하며 공통화나 상속 등도 간단히 실현할 수 있어 그 결과 처음에 언급한 여러가지 문제를 해결할 수 있습니다. 예에서는 스타일을 컴포넌트의 안에 작성했지만 다른 파일에 작성하고 require 해서 사용할 수도 있습니다.

JavaScript 쪽으로 마크업을 가지고 온 JSX 처럼 CSS도 JavaScript로 가져오자는 이 접근에 관해 어떻게 생각하시나요? 여기까지 CSS in JS를 소개했습니다.

React.js in future
React.js의 향후라는 주제로 이번 절을 작성할까 합니다. React.js의 로드맵은 facebook/react와는 다른 저장소 인 react-future에서 논의되고 있습니다. 여기에 있는 것은 어디까지나 아이디어 수준이지만 구체적인 코드로 설명돼 있어서 어떤 모습일지 예측하기 쉽습니다.

또, 이전 절에서도 소개했던 「React Through the Ages」 슬라이드에서도 React.js의 현재와 미래에 대해서 이야기하고 있으므로 참고하세요.

지금까지의 React.js
React.js는 원래 페이스북이 PHP + XML로 만든 XHP 프로젝트에서 시작됐습니다. 이를 JavaScript에 가져온 것이 React.js입니다. 애플리케이션 전체적으로 rerender 하는 구조는 서버 측의 rendering 방식과 비슷하다는 점에서도 이런 흐름을 예측할 수 있습니다. 또, React.js는 최초엔 Standard ML로 만들어졌다가 그 뒤 Haxe가 되어 지금의 Pure한 JavaScript가 됐습니다.

1.0과 그 앞
「React Through the Ages」를 보면 API의 안정화와 삭제 그리고 ES6, 7 사양을 따르려고 하는 의도를 느낄 수 있습니다. ES6, 7에서 사용할 수 있는 기능을 최대한 활용하여 React.js 자체에서는 부가적인 처리를 하지 않겠다는 방향성을 엿볼 수 있습니다.

class Button extends React.Component {
getInitialState() {
return {count: 0};
},
render() {
return (
<button onClick={() => this.setState({count: this.state.count + 1}) }>
{this.state.count}
</button>
);
}
}
CSS in JS : 이는 이전 절에서 소개한 CSS의 문제를 해결하기 위한 접근 방식입니다.
Web Workers : VirtualDOM 계산을 WebWorkers에서 하는 것으로 UI 단에 좋은 영향을 줄 수 있다면 도입하고 싶다고 합니다.
Layout & Animation : 어떠한 방식으로 정의하도록 하느냐가 어려운 문제이지만 중요한 기능이기 때문에 지원하고 싶다고 합니다.
M(V)C : 자신(페이스북)은 필요하지 않지만 많은 개발자가 React.js를 사용했을 때의 MVC의 M과 C에 대해 논의하거나 개발하고 있는 것을 보고 이에 대한 지원도 중요한 사항으로 여기는 것 같습니다. React.js가 풀-프레임워크가 되는 일은 없을 것 같습니다만…
Other : 이 외에도 새로운 테스트 지원이나 문서, Immutable Data 등 다양한 아이디어가 있는 것 같습니다.
React.js의 미래
react-future의 저장소를 보면 ES6, 7의 기능을 도입할 경우의 형태를 볼 수 있습니다. 단, 여기에서 소개하는 기능은 아직 구현돼 있지 않고 합의된 것도 아니기 때문에 이렇게 지원된다고 장담할 순 없습니다.

역자노트
일부 기능은 이미 사용할 수 있습니다. 원문이 2014년 12월에 작성됐다는 사실을 감안해주세요.

Class
import {Component} from ‘react’;

export class Button extends Component {
props : {
width: number
}
static defaultProps = {
width: 100
}
state = {
counter: Math.round(this.props.width / 10)
}
handleClick = (event) => {
event.preventDefault();
this.setState({counter: this.state.counter + 1});
}
render(props, state) {
return (
<div>
This button has been clicked: {state.counter} times
<button onClick={this.handleClick} style={{ idth: props.width}}/>
</div>
);
}
}
ES6의 Module이나 Class, ArrowFunction 등이 사용됐고 React.js 독자적인 부분이 적어졌습니다. 또 props의 형 지정 방식도 변경 됐는데 이는 facebook/flow와 연계될 수도 있을 것 같습니다. (댓글에는 TypeScript compatible syntax로 작성돼 있지만) 또, render에 props와 state를 인자로 전달하는 것 같은 형태로 돼 있습니다.

mixin
import { mixin } from ‘react-utils’;

const A = {
componentDidMount() {
super();
console.log(‘A’);
}
};

class B extends mixin(A) {
componentDidMount() {
console.log(‘B’);
super();
}
}

new B().componentDidMount(); // B, A

import { Component } from ‘react’;

class Component extends mixin(Component, C) {
render() {
return <div/>;
}
}
mixin은 util로써 준비하고, super로 부모의 것을 호출하는 식으로 디자인돼 있습니다. state의 merge 방식에 관한 문제가 있는 것 같습니다.

Stateless Functions
export function Button(props : {width: number, onClick: function}) {
return (
<div>
Fancy button
<button onClick={props.onClick} style={{width: props.width}}/>
</div>
);
}
Prop 만을 갖는 Stateless한 컴포넌트는 Prop을 전달받는 함수로써 정의할 수 있도록 돼 있습니다.

Elements
JavaScript 객체 문법이나 JSX 이외에도 여러가지 방법으로 React Element를 작성할 수 있도록 하고자 하는 바램이 있는 것 같습니다.

Object 리터럴
{
type: Button,
props: {
foo: bar,
children: [
{ type: ‘span’, props: { children: a } },
{ type: ‘span’, props: { children: b } }
]
},
// optional
key: ‘mybutton’,
ref: myButtonRef
}
Native Components
React.DOM 이하의 API는 없어지고 단순한 문자열로 정의할 수 있도록 돼 있습니다. 또 Web Components의 커스텀 태그에도 호환성을 지니게 돼 있습니다.

Template Strings
ES6의 Template Strings을 이용해 정의할 수 있도록 돼 있습니다.

X`
<my-button foo=${bar} key=”mybutton” ref=${myButtonRef}>
<span>${a}</span>
<span>${b}</span>
</my-button>
`
이외에도 여러가지 소개하고 있으므로 흥미가 있다면 꼭 한번 읽어보시길 바랍니다.

React.js에 관한 리소스, 그리고 정리
여기까지 React.js를 소개했습니만, 조금이라도 사용하는데 참고가 됐다면 좋겠습니다. React.js는 facebook, instagram이나 Github의 AtomEditor 물론, 「Atlassian」, 「Netflix」, 「Reddit」, 「The New York Times」, 「Yahoo」 등 많은 곳에서 사용하고 있는 것 같습니다(참고).

또, 내년 1월말에는 React.js Conf가 있으므로 여러가지 소식이 공유되고 점점 분위기도 무르익을 것으로 생각됩니다. 내년도 즐거운 한해가 될 것 같습니다.

React.js의 공식 블로그나 #reactjs 해쉬 태그를 구독하면 여러가지 정보를 모을 수 있습니다.

리소스 정리
개인적으로 읽고 재미있었던 것이나 공식적인 사이트를 정리해봤습니다.

공식 사이트
공식 홈페이지(한국어)
Flux
Complementary Tools
Immutable.js
Jest
컴포넌트, 샘플 모음집
React Coponents: 공개된 React.js 컴포넌트가 정리돼 있습니다.
React Rocks: React.js의 샘플이나 데모가 모여있습니다.
입문
Learning React.js: Getting Started and Concepts: React.js를 사용하여 앱을 만드는 과정을 순차적으로 쉽게 설명하고 있습니다.
React JS and why it’s awesome: React.js의 장점이 잘 설명돼 있습니다.
Virtual DOM
OSCON – React Architecture: 페이스북 개발자가 설명하는 React.js의 VirualDOM 구현 단의 이야기 입니다.
Components, React and Flux: React.js와 Flux를 코드와 함께 이해하기 쉽게 설명하고 있습니다.
Flux
Isomorphic Flux: Yahoo가 Isomorphic한 Flux 애플리케이션을 만든 이야기입니다.
flux-meetup: 페이스북의 개발자가 하는 React.js와 Flux에 관한 설명입니다.
Developer tool
소개하는 것을 깜빡 잊고 있었습니다. React.js 개발을 할 때에 편리하게 사용할 수 있는 크롬 확장 도구인 React Developer Tools도 있습니다.

아래 그림과 같이 React.js를 사용하는 페이지에 가면 개발자 도구에 React탭이 표시되고 거기서 HTML의 태그가 아니라 Component로 볼 수 있습니다. 또, Prop과 State및 EventListener와 Component의 값도 확인 할 수 있어 편리하게 디버깅할 수 있습니다.

React Developer Tools
<그림 1 React Developer Tools>
정리
역시 읽을 때와 번역해서 공유할 때 느낌은 많이 다르네요. 알아서 이해했던 것들도 신경 써야 하니 시간이 좀 걸렸습니다. koba04님의 React.js Advent Calendar는 제가 처음 React.js를 학습할때 도움을 받았던 문서였기 때문에 무엇부터 차근차근 봐야 할지 모르시는 분들이 있을 것 같아서 일본어 문서를 번역했습니다. React.js를 이해하는데 많은 도움이 되길 간절히 바라면서 이만 마치도록 하겠습니다.

여기까지 React.js를 소개했습니다. 끝까지 읽어주셔서 감사합니다!

React.js를 이해하다(6)
react.js

React.js를 이해하다(6)

블로그 사이트 바로가기

읽기전에…
이 문서는 koba04님이 작성한 React.js Advent Calendar를 번역한 것입니다. 본래 원문서는 캘린더 형식으로 소개하지만 여기에서는 회를 나눠 작성할 생각입니다. 또한, React 버전 0.12.1 때 작성된 문서이기 때문에 현 버전과 다른 점이 있을 수 있습니다. 최대한 다른 부분을 노트로 작성할 생각이지만, 만약 생략된 부분이 있다면 댓글로 알려주시면 감사하겠습니다.

React.js의 테스트
이번에는 React.js 환경에서 테스트하는 방법을 소개하겠습니다.

React.js와 테스트
React.js는 컴포넌트에 대응하여 테스트를 작성해야 하므로 DOM을 의존하여 힘들 것으로 예상하지만 React.addons.TestUtils라는 Addon이 테스트에 편리한 함수를 제공하고 있으므로 이를 이용하면 더 쉽게 테스트를 작성할 수 있습니다.

DOM이 필요할까?
React.js 컴포넌트는 서버-사이드에서도 사용할 수 있으므로 node.js 환경에서 테스트를 작성하고 싶을 수 있지만 onClick이나 onKeyUp 같은 이벤트에 실제로 반응하는지 테스트하기 위해서 DOM이 필요합니다. 단순히 Prop 값을 전달하고 renderToStaticMarkup을 사용하여 결괏값인 HTML을 테스트하는 경우엔 node.js 환경에서 작성할 수 있습니다.

이벤트 시뮬레이트
「버튼을 클릭하면」이라는 테스트를 작성하고자 할 때 DOM을 셀렉트하고 값을 설정하여 이벤트를 발생시키는 일련의 과정이 필요하지만, React.addons.TestUtils.Simulate를 사용하면 DOM을 지정하고, 전달하고 싶은 이벤트 객체의 형식을 지정할 수 있으므로 격식없이 사용자 액션 테스트를 작성할 수 있습니다.

Simulate.{eventName}(DOMElement element, object eventData)
var node = this.refs.input.getDOMNode();

React.addons.TestUtils.Simulate.click(node);

// 전달하고자 하는 이벤트 객체를 지정한다.
React.addons.TestUtils.Simulate.change(node, {target: {value: ‘Hello, world’}});
React.addons.TestUtils.Simulate.keyDown(node, {key: ‘Enter’});
컴포넌트 작성 지원
renderIntoDocument
renderIntoDocument를 사용하면 DOM에 컴포넌트를 실제로 추가하지 않아도 테스트할 수 있습니다. 아래 예제를 보면 일단 renderintoDocument가 컴포넌트를 DOM에 추가해 나갈 것으로 보입니다.

var Hello = require(‘./components/hello’);
var component = React.addons.TestUtils.renderIntoDocument(<Hello name=”foo” />);
하지만 이것은 실제 DOM 트리에 추가되는 것이 아니라 document.createElement로 생성한 div에 render 할 뿐입니다. 그래서 요소의 실제 높이나 너비 등은 알 수 없습니다. (이름이 다소 혼란스럽기 때문에 변경될 수 있을 것 같습니다)

mockComponent
Jest를 사용하고 있을 때 mock 컴포넌트에서 더미로 <div/>(엘리먼트 요소)를 반환하도록 하는 mockComponent도 있습니다. 이 함수를 사용하기 위해서는component.prototype.render.mockImplementation이 작성되어야 하는데 Jest를 고려한 함수(mockFn.mockImplementation(fn)) 인듯합니다. 자주 쓰일지 모르겠습니다만, 보통 Mock으로 작성한 컴포넌트에서 render를 동작시키고 싶을 때 사용하는 듯합니다.

mockComponent: function(module, mockTagName) {
mockTagName = mockTagName || module.mockTagName || ‘div’;

module.prototype.render.mockImplementation(function() {
return React.createElement(
mockTagName,
null,
this.props.children
);
});

return this;
},
컴포넌트 셀렉트
findAllInRenderedTree(ReactComponent tree, function test)
특정 컴포넌트의 하위 컴포넌트 중에서 지정한 함수의 조건을 충족한 컴포넌트만 배열로 반환합니다. 아래에서 소개할 함수를 사용할 수 없는 경우에 사용할 수 있는 가장 기본적인 구현입니다.

console.log(
React.addons.TestUtils.findAllInRenderedTree(
React.render(<div><span>foo</span><span>bar</span><p>baz</p></div>, document.body),
function(component) { return component.tagName === ‘SPAN’ }
).map(function(component){ return component.getDOMNode().textContent })
);

// [‘foo’, ‘bar’]
scryRenderedDOMComponentsWithClass(ReactComponent tree, string className)
특정 컴포넌트의 하위 컴포넌트 중, 지정한 className에 해당하는 컴포넌트를 배열로 반환합니다.

console.log(
React.addons.TestUtils.scryRenderedDOMComponentsWithClass(
React.render(
<div>
<span className=”foo”>foo1</span>
<span className=”foo”>foo2</span>
<span className=”bar”>barbar</span>
</div>,
document.body
),
‘foo’
).map(function(component){ return component.getDOMNode().textContent })
);

// [‘foo1’, ‘foo2’]
findRenderedDOMComponentWithClass(ReactComponent tree, string className)
특정 컴포넌트의 하위 컴포넌트 중, 지정한 className에 해당하는 컴포넌트를 1개만 반환합니다.

console.log(
React.addons.TestUtils.findRenderedDOMComponentWithClass(
React.render(
<div>
<span className=”foo”>foo1</span>
<span className=”foo2″>foo2</span>
<span className=”bar”>barbar</span>
</div>,
document.body
),
‘foo’
).getDOMNode().textContent
);

// [‘foo1’]
해당하는 컴포넌트가 없거나 여러개가 매치되면 오류를 발생시킵니다.

console.log(
React.addons.TestUtils.findRenderedDOMComponentWithClass(
React.render(
<div>
<span className=”foo”>foo1</span>
<span className=”foo”>foo2</span>
<span className=”bar”>barbar</span>
</div>,
document.body
),
‘foo’
).getDOMNode().textContent
);

// Uncaught Error: Did not find exactly one match for class:foo
scryRenderedDOMComponentsWithTag(ReactComponent tree, string tagName)
특정 컴포넌트의 하위 컴포넌트 중, 지정한 태그 네임에 해당하는 컴포넌트를 배열로 반환합니다.

console.log(
React.addons.TestUtils.scryRenderedDOMComponentsWithTag(
React.render(
<div>
<span>foo1</span>
<span>foo2</span>
<p>barbar</p>
</div>,
document.body
),
‘span’
).map(function(component){ return component.getDOMNode().textContent })
);

// [‘foo1’, ‘foo2’]
findRenderedDOMComponentWithTag(ReactComponent tree, string tagName)
특정 컴포넌트의 하위 컴포넌트 중, 지정한 className에 해당하는 컴포넌트를 1개만 반환합니다. 해당하는 컴포넌트가 없거나 여러개가 매치되면 오류를 발생시킵니다.

console.log(
React.addons.TestUtils.findRenderedDOMComponentWithTag(
React.render(
<div>
<span>foo1</span>
<span>foo2</span>
<p>barbar</p>
</div>,
document.body
),
‘p’
).getDOMNode().textContent
);

// barbar
scryRenderedComponentsWithType(ReactComponent tree, function componentClass)
특정 컴포넌트의 하위 컴포넌트 중, 지정한 컴포넌트의 인스턴스에 해당하는 컴포넌트를 배열로 반환합니다.

console.log(
React.addons.TestUtils.scryRenderedComponentsWithType(
React.render(
<div>
<Hello name=”foo” key=”foo” />
<Hello name=”bar” key=”bar” />
<span>xxx</span>
<p>zzz</p>
</div>,
document.body
),
Hello
).map(function(component){ return component.getDOMNode().textContent })
);

// [‘foo’, ‘bar’]
findRenderedComponentWithType(ReactComponent tree, function componentClass)
특정 컴포넌트의 하위 컴포넌트 중, 지정한 컴포넌트의 인스턴스에 해당하는 컴포넌트를 1개만 반환합니다. 해당하는 컴포넌트가 없거나 여러개가 매치되면 오류를 발생시킵니다.

console.log(
React.addons.TestUtils.findRenderedComponentWithType(
React.render(
<div>
<Hello name=”foo” key=”foo” />
<span>xxx</span>
</div>,
document.body
),
Hello
).getDOMNode().textContent
);

// foo
Assert
React 컴포넌트의 상태를 확인하기 위한 함수들의 모음입니다.

isElementOfType(ReactElement element, function componentClass)
특정 컴포넌트가 지정한 컴포넌트의 인스턴스에 해당하는지를 판단합니다.

React.addons.TestUtils.isElementOfType(<Hello />, Hello);
isDOMComponent(ReactComponent instance)
특정 컴포넌트가 div나 span과 같은 DOM 컴포넌트인지 판단합니다.

React.addons.TestUtils.isDOMComponent(
React.render(<div />, document.body)
);
isCompositeComponent(ReactComponent instance)
특정 컴포넌트가 React.createClass에 의해 정의된 컴포넌트를 포함해 작성된 것인지 판단합니다. div나 span 등은 포함하지 않습니다.

React.addons.TestUtils.isCompositeComponent(
React.render(<Hello />, document.body)
);
isCompositeComponentWithType(ReactComponent instance, function componentClass)
특정 컴포넌트가 지정한 Component 타입을 포함해 작성된 것인지 판단합니다.

React.addons.TestUtils.isCompositeComponentWithType(
React.render(<Hello />, document.body), Hello
);
isTextComponent(ReactComponent instance)
특정 컴포넌트가 텍스트 컴포넌트를 반환하는지 판단합니다.

var textComponents = React.addons.TestUtils.findAllInRenderedTree(
React.render(
<div>{‘hello’}{‘react’}</div>,
document.body
),
function(component) {
return React.addons.TestUtils.isTextComponent(component)
}
);
console.log(textComponents[0].props + ‘ ‘ + textComponents[1].props);
// hello react
여기까지 TestUtils의 종류와 사용 방법을 설명했습니다. 다음 절에서는 페이스북이 만들고 배포한 테스트 프레임워크인 Jest와 조합하는 방법을 소개하고자 합니다.

React.js와 Jest
이전에는 TestUtils를 사용하는 방법을 중심으로 설명했습니다. 이번에는 facebook이 개발하고 있는 Jest라고 하는 프레임워크와 함께 구성해 보고자 합니다.

Painless JavaScript Unit Testing
Jest는 공식 홈페이지에서 「Painless JavaScript Unit Testing」 문구를 대표적으로 소개하고 있으며 도입하기 쉽다는 특징을 가지고 있습니다. 그 특징으로는 「Mock By Default」가 있는데 기본적으로 Jest에서는 CommonJS Style의 require 구문이 Mock을 반환하도록 설정합니다. 조금 과격한 느낌입니다만 테스트 대상이 되는 동작에만 민감한 테스트를 간단하게 작성할 수 있습니다. 반대로 테스트 대상 이 외는 모두 Mock으로 대체 되므로 인터페이스 밖에 테스트 할 수 없지만, 그것은 Unit Test의 범위 밖으로 볼 수 있어서 큰 문제가 되지 않습니다.

Jasmine
Jest는 Jasmine을 기반으로 만들어졌습니다. 따라서 Assert 등과 같은 기본적인 문법은 Jasmine과 같습니다. 단, Jasmine 2.0에서 비동기 테스트를 작성하기 보다 쉬워졌지만 1.3을 기반으로 하고 있어 이를 이용할 수 없습니다(issues/74).

DOM
Jest는 jsdom으로 생성한 DOM 위에서 실행되므로 Node.js 환경처럼 CLI로 테스트를 실행할 수 있습니다. 즉, Jest를 사용하면 Karma 같은 Test Runner를 사용할 필요가 없으므로 간단하게 도입할 수 있습니다.

Install
jest-cli만 설치하면 됩니다.

$ npm install –save-dev jest-cli
tests
기본적으로 tests 디렉터리를 찾습니다. 그리고 그 디렉터리 내의 파일을 테스트로써 실행합니다. 따라서 Getting Started에서도 알 수 있듯이 tests 디렉터리를 내에 테스트 파일를 두고 jest를 실행하면 테스트가 진행됩니다. 만약 jest-cli를 전역이 아닌 devDependencies에 설치한다면 package.json의 scripts 프로퍼티에 npm test로 실행할 수 있도록 아래처럼 작성하면 편리하게 사용할 수 있습니다.

“scripts”: {
“test”: “jest”
}
React.js를 테스트한다.
Jest의 Tutorial – React 문서에 React.js를 사용한 애플리케이션을 테스트하는 경우도 작성돼 있습니다. 테스트하기 위해서는 두 가지 설정을 할 필요가 있습니다.

JSX의 변환
JSX를 사용해 애플리케이션을 작성한 경우에는 테스트를 위해 JSX를 변환할 필요가 있습니다. package.json의 Jest 프로퍼티에 scriptPreprocessor로 사전에 동작해야할 script를 지정합니다.

// package.json
“jest”: {
“scriptPreprocessor”: “preprocessor.js”
},

// preprocessor.js
var ReactTools = require(‘react-tools’);
module.exports = {
process: function(src) {
return ReactTools.transform(src, {harmony: true});
}
};
Mock의 해제
위에서 언급한 것처럼 Jest에서는 모든 require 구문이 Mock을 반환합니다. 단, React도 Mock으로 대체되면 테스트할 수 없으므로 react를 Mock으로 대체하지 않도록 경로를 설정할 필요가 있습니다. 이러한 설정도 package.json에 속성을 추가하는 것으로 간단하게 할 수 있습니다. 테스트 파일에서도 Mock하지 않을 파일을 지정할 수 있지만, 만약 모든 테스트에서 Mock 하고 싶지 않은 파일이 있다면 아래와 같이 작성합니다.

“jest”: {
“scriptPreprocessor”: “preprocessor.js”,
“unmockedModulePathPatterns”: [“node_modules/react”]
},
테스트 작성해보기
아래와 비슷한 느낌으로 React 컴포넌트의 테스트를 작성할 수 있습니다.(참고)

jest.dontMock(‘../InputArtist’);

var React = require(‘react/addons’),
InputArtist = require(‘../InputArtist’),
AppTracksActionCreators = require(‘../../actions/AppTracksActionCreators’)
;

describe(‘inputArtist’, function() {
var inputArtist;
beforeEach(function() {
inputArtist = React.addons.TestUtils.renderIntoDocument(<InputArtist />);
});

describe(‘state’, function() {
it(‘set inputArtist radiohead’, function() {
expect(inputArtist.state.inputArtist).toBe(‘radiohead’);
});
});

describe(‘handleSubmit’, function() {
var preventDefault;
beforeEach(function() {
preventDefault = jest.genMockFunction();
inputArtist.setState({ inputArtist: ‘travis’ });
React.addons.TestUtils.Simulate.submit(inputArtist.getDOMNode(), {
preventDefault: preventDefault
});
});
it (‘calls AppTracksActionCreators.fetchByArtist with state.inputArtist’, function() {
expect(AppTracksActionCreators.fetchByArtist).toBeCalled();
expect(AppTracksActionCreators.fetchByArtist).toBeCalledWith(‘travis’);
});
it (‘calls e.preventDefault’, function() {
expect(preventDefault).toBeCalled();
});
});
});
Jest 동작 테스트
<그림 1 Jest 동작 테스트>
그럼 코드를 자세히 살펴보겠습니다.

jest.dontMock(‘../InputArtist’);
Mock으로 대체할 필요가 없는 module은 dontMock에 명시적으로 지정합니다.

var React = require(‘react/addons’),
InputArtist = require(‘../InputArtist’),
AppTracksActionCreators = require(‘../../actions/AppTracksActionCreators’)
;
React는 package.json의 unmockedModulePathPatterns의 지정했으므로 Mock으로 대체되지 않습니다. 그 외 다른 모듈은 Mock으로 대체됩니다.

describe(‘inputArtist’, function() {
var inputArtist;
beforeEach(function() {
inputArtist = React.addons.TestUtils.renderIntoDocument(<InputArtist />);
});

describe(‘state’, function() {
it(‘set inputArtist radiohead’, function() {
expect(inputArtist.state.inputArtist).toBe(‘radiohead’);
});
});
이 코드는 보통의 Jasmine 테스트 코드와 같습니다. React.addons.TestUtils.renderIntoDocument를 사용하여 Component를 DOM에 붙여서 테스트하고 있습니다.

describe(‘handleSubmit’, function() {
var preventDefault;
beforeEach(function() {
preventDefault = jest.genMockFunction();
inputArtist.setState({ inputArtist: ‘travis’ });
React.addons.TestUtils.Simulate.submit(inputArtist.getDOMNode(), {
preventDefault: preventDefault
});
});
it (‘calls AppTracksActionCreators.fetchByArtist with state.inputArtist’, function() {
expect(AppTracksActionCreators.fetchByArtist).toBeCalled();
expect(AppTracksActionCreators.fetchByArtist).toBeCalledWith(‘travis’);
});
it (‘calls e.preventDefault’, function() {
expect(preventDefault).toBeCalled();
});
위는 submit 버튼이 클릭 됐을 때 fetchByArtist와 e.preventDefault가 호출되는지 테스트하는 코드입니다. React.addons.TestUtils.Simulate.submit를 사용해 submit 이벤트를 발생시켜 이벤트 객체의 jest.genMockFunction 생성한 preventDefault Mock 함수을 통해서 호출됐지 확인합니다. fetchByArtist는 실제로 Ajax 요청을 하지만 Jest가 Mock으로 대체했으므로 특별히 의식하지 않고 간단하게 테스트를 작성할 수 있습니다.

Mock
Mock은 jest.genMockFunction과 같은 API로 직접 만드는 것도 가능하며 mock property에 calls나 instances 등의 호출 정보가 기록되므로 이 기록을 사용해 테스트를 작성할 수 있습니다. 또, Mock Function의 mockReturnValue를 사용해 지정한 값을 반환하도록 할 수 있고 mockimplementation에 callback을 전달하는 것으로 직접 Mock을 구현할 수도 있습니다.

Mock Assert
Mock을 확인하기 위한 assert도 준비돼 있습니다. expect(mockFunc).toBeCalled와 같이 테스트를 작성할 수 있습니다.

module 교체
mocks 디렉터리를 생성하여 그 안에 module 구현을 작성하는 하면 테스트 시 모듈 자체를 항상 대체할 수 있습니다. superagent를 Mock으로 대체하면 에러가 발생하는 이슈가 있는데, 이를 방지하기 위해 mocks/superagent.js에서 workaround로 Mock을 두고 있습니다.

Timer
setTimeout이나 setInterval을 사용하는 구현을 테스트하는 경우 jset.runAllTimers나 jset.runOnlyPendingTimers를 사용하여 동기적으로 테스트를 작성할 수 있습니다. runAllTimers는 setTimeout이나 setInterval 큐에 존재하는 모든 태스크를 실행하고 runOnlyPendingTimers는 호출한 시점에서 대기중인 태스크만 실행합니다. setTimeout으로 반복하고 있는 구현의 경우 runAllTimers를 사용하면 무한 루프에 빠지므로 runOnlyPendingTimers를 사용해 한 번에 하나씩 테스트를 진행하도록 작성합니다.

API
API는 공식 홈페이지의 API Reference에 정리돼 있습니다. 여기에서 전부 소개하진 않지만 여러 상황에 대응한 API를 제공하고 있음을 알 수 있습니다.

불편한 점
이것저것 설정하여 해결할 수 있을지 모르지만, Karma와 비교할 때 상대적으로 테스트 실행이 느립니다. 이슈(issues/116)로도 등록돼 있으므로 빨리 개선되길 바랍니다.

여기까지 Jest를 소개하겠습니다. 다음 절에서는 Flux를 소개하겠습니다.

React.js와 Flux
이번에는 React.js와 관계가 깊은 Flux를 소개하겠습니다.

Flux is Architecture
Flux 아키텍처
<그림 2 Flux 아키텍처>
위는 깃-허브 저장소에 명시된 그림입니다. Flux는 위와 같은 아키텍처의 명칭이기도 합니다. 조금 더 살펴보면 알겠지만, Dispatcher 부분만 구현하고 있습니다.

Unidirectional data flow
위 아키텍처를 보면 알 수 있듯이 Flux는 애플리케이션의 복잡함을 없애기 위해서 데이터의 흐름을 단방향 운영합니다. 이런 방식은 전체적인 처리 흐름을 알기 쉽지만 Angular.js 등과 비교했을 때 상대적으로 표현이나 문법이 장황한 느낌이 있습니다. 그렇지만 데이터의 흐름을 단순하게 만드는 것으로 애플리케이션의 규모가 커져 복잡화돼도 데이터나 이벤트의 흐름이 엉키지 않고 파악하기 쉬운 구조를 유지할 수 있다고 합니다. (실제로 Flux를 사용해 대규모 애플리케이션을 구현해보지 않아서 단언할 순 없습니다)

자, 그럼 react-boilerplate를 예제를 사용해 본격적으로 Flux를 소개하겠습니다.

Flux의 구성 요소
Constants
Flux에서는 각 요소 간 주고 받을 타입을 상수처럼 정의합니다.

var keyMirror = require(‘react/lib/keyMirror’);

module.exports = {
ActionTypes: keyMirror({
RECEIVE_TRACKS_BY_ARTIST: null,
RECEIVE_TRACKS_BY_COUNTRY: null
}),
PayloadSources: keyMirror({
VIEW_ACTION: null
})
};
참고로 keyMirror는 key를 사용해 value로 설정해주는 Util 입니다.

Dispatcher
Dispatcher는 Action을 받아 등록된 callback을 실행합니다. 여기에서는 facebook/flux가 유일하게 제공하고 있는 Dispatcher를 확장하는 느낌으로 오브젝트를 생성해 싱들톤으로 반환합니다. 여기에서는 ActionCreators부터 Dispatcher에 Acton을 던지기 위한 handleViewAction을 정의하고 있습니다.

var Dispatcher = require(‘flux’).Dispatcher,
assign = require(‘object-assign’),
AppConstants = require(‘../constants/AppConstants’)
;

var PayloadSources = AppConstants.PayloadSources;

module.exports = assign(new Dispatcher(), {
handleViewAction: function(action) {
this.dispatch({
source: PayloadSources.VIEW_ACTION,
action: action
});
}
});
Store
Store는 애플리케이션의 데이터와 비즈니스 로직을 담당합니다. Store에서 담당하는 데이터는 메시지 목록과 같은 집합도 다룹니다.

var AppDispatcher = require(‘../dispatcher/AppDispatcher’),
AppConstants = require(‘../constants/AppConstants’),
EventEmitter = require(‘events’).EventEmitter,
assign = require(‘object-assign’)
;

var ActionTypes = AppConstants.ActionTypes;
var CHANGE_EVENT = ‘change’;
var tracks = [];

var TrackStore = assign({}, EventEmitter.prototype, {

emitChange: function() {
this.emit(CHANGE_EVENT);
},
addChangeListener: function(callback) {
this.on(CHANGE_EVENT, callback);
},
removeChangeListener: function(callback) {
this.removeListener(CHANGE_EVENT, callback);
},
getAll: function() {
return tracks;
},
});

TrackStore.dispatchToken = AppDispatcher.register(function(payload) {
var action = payload.action;

switch (action.type) {
case ActionTypes.RECEIVE_TRACKS_BY_ARTIST:
tracks = action.tracks;
TrackStore.emitChange();
break;
case ActionTypes.RECEIVE_TRACKS_BY_COUNTRY:
tracks = action.tracks;
TrackStore.emitChange();
break;
}
});

module.exports = TrackStore;
여기에서 눈여겨 봐야 할 포인트는 다음과 같습니다.

getter 메서드만 정의하여 외부에서 데이터에 접근할 수 없는 형태로 유지합니다.
데이터의 갱신은 ActionCreator에서 Despatcher에 전달하여 등록한 callback 함수를 호출하여 실시합니다.
Dispatcher에 callback을 등록하여 처리 할 수 있도록 합니다.
Store는 EventEmiiter의 기능을 가지고 있어 데이터가 갱신되면 이벤트를 발행합니다.
View는 Store의 이벤트를 구독합니다.
ActionCreators (Action)
Action을 생성해 Dispatcher에 전달합니다. 이 문서의 예제에서는 Ajax 요청도 ActionCreators 내에서 담당하고 있지만 facebook/flux의 예제에서는 Utils 이라고 하는 네임스페이스를 만들어 그 안에서 담당하도록 디자인돼 있습니다. Ajax이 끝난 시점뿐만 아니라 시작한 시점에도 Action을 발생시켜 로딩하는 View를 출력할 수도 있을 것 같습니다.

var request = require(‘superagent’),
AppDispatcher = require(‘../dispatcher/AppDispatcher’),
AppConstants = require(‘../constants/AppConstants’)
;

var ActionTypes = AppConstants.ActionTypes;
var urlRoot = ‘http://ws.audioscrobbler.com/2.0/?api_key=xxxx&format=json&’;

// TODO Loading
module.exports = {
fetchByArtist: function(artist) {
request.get(
urlRoot + ‘method=artist.gettoptracks&artist=’ + encodeURIComponent(artist),
function(res) {
AppDispatcher.handleViewAction({
type: ActionTypes.RECEIVE_TRACKS_BY_ARTIST,
tracks: res.body.toptracks.track
});
}.bind(this)
);
},
fetchByCountry: function(country) {
request.get(
urlRoot + ‘method=geo.gettoptracks&country=’ + encodeURIComponent(country),
function(res) {
AppDispatcher.handleViewAction({
type: ActionTypes.RECEIVE_TRACKS_BY_ARTIST,
tracks: res.body.toptracks.track
});
}.bind(this)
);
}
};
Action은 아래와 같은 형태의 리터럴 객체입니다.

{
type: ActionTypes.RECEIVE_TRACKS_BY_ARTIST,
tracks: res.body.toptracks.track
}
View (ReactComponent)
데이터를 출력하는 View와 Action을 발생하는 View를 나누어서 소개하겠습니다.

Store의 데이터를 출력하는 컴포넌트
View에서는 componentDidMount로 Store의 change 이벤트를 구독하고 componentWillUnmount에서 구독을 해제하고 있습니다. change 이벤트가 발행되면 Store에서 다시 데이터를 가져와 setState에 설정합니다. 여기에서 Store 데이터는 동기적으로 취득할 수 있다고 전제하고 있습니다.

module.exports = React.createClass({
getInitialState() {
return {
tracks: TrackStore.getAll(),
};
},
componentDidMount: function() {
TrackStore.addChangeListener(this.<onChange);
},
componentWillUnmount: function() {
TrackStore.removeChangeListener(this.<onChange);
},
<onChange: function() {
this.setState({ tracks: TrackStore.getAll() });
},
render() {
var tracks = this.state.tracks.map( (track, index) => {
return (
<li className=”list-group-item” key={index}>
<span className=”label label-info”>{index+1}</span>
<a href={track.url} target=”<blank”><span className=”track”>{track.name}</span></a>
<span className=”artist”>{track.artist.name}</span>
<small className=”listeners glyphicon glyphicon-headphones”>{track.listeners}</small>
</li>
);
});
return (
<div className=”tracks”>
<ul className=”list-group”>
{tracks}
</ul>
</div>
);
}
});
Action을 발생시키는 컴포넌트
이번에는 이벤트를 받아서 ActionCreator에 전달하는 컴포넌트입니다.

AppTracksActionCreators.fetchByArtist(artist);
}
},
render() {
return (
<form className=”form-horizontal” role=”form” onSubmit={this.handleSubmit} >
<div className=”form-group”>
<label htmlFor=”js-input-location” className=”col-sm-1 control-label”>Artist</label>
<div className=”col-sm-11″>
<input type=”text” className=”form-control” placeholder=”Input Atrist Name” valueLink={this.linkState(‘inputArtist’)} required />
</div>
</div>
<div className=”form-group”>
<div className=”col-sm-offset-1 col-sm-11″>
<button type=”submit” className=”btn btn-primary”><span className=”glyphicon glyphicon-search”>search</span></button>
</div>
</div>
</form>
);
}
});
역자노트
Flux를 조금 더 알고 싶다면 「페이스북의 결정: MVC는 확장에 용이하지 않다. 그렇다면 Flux다.」와 「다같이! FluxUtils 한바퀴」를 참고해주세요.

이 모두를 종합해보면 Dispatcher -> Store -> View -> ActionCreator -> Dispatcher 순으로 데이터가 단방향으로 흘러간다는 사실을 알 수 있습니다.

그 외 Flux 구현
Flux의 아키텍처는 비교적 단순합니다. 실제로 애플리케이션을 개발하고 있는 개발자는 각각 확장하여 여러 가지 형태의 Flux를 구현하고 있습니다. 몇 가지 소개해드리겠습니다. Flux를 구현할 때 참고하세요.

Yahoo의 Flux 구현
RefluxJS
McFly
Delorean
Fluxxor
Flux + server-side rendering
Flux의 경우, Store의 데이터가 싱글톤이 되지만 Server-Side Rendering의 경우는 싱글-톤으로 생성하면 안 되기 때문에 리퀘스트마다 Store를 생성할 필요가 있으므로 주의가 필요합니다. 이 문제를 어떻게 해결햇는지는 Yahoo의 개발자가 작성한 isomorphic-flux 슬라이드를 참고하시길 바랍니다.

데이터 검증
개인적으로 데이터 검증을 담당하는 곳은 Store라고 생각합니다. View가 Action을 발생시키고 Store가 받았을 때 부정확한 데이터의 경우 오류를 발생시켜 View에 전달하고 View는 필요하다면 에러를 출력하는 흐름이 좋은 것 같습니다.

—— ———— ——————— ——
|View|——–|Dispatcher|——–|Store에서 Validation|——–|View|— 에러 표시
—— action ———— action ——————— error ——
에러를 전달하는 방법은 여러가지가 있습니다만 Node.js에서 첫 번째 인자로 err를 전달하는 패턴을 사용하면 좋을 것 같습니다.

// Store
var TrackStore = assign({}, EventEmitter.prototype, {

emitChange: function(err) {
this.emit(CHANGE_EVENT, err);
},
addChangeListener: function(callback) {
this.on(CHANGE_EVENT, callback);
},
removeChangeListener: function(callback) {
this.removeListener(CHANGE_EVENT, callback);
},
getAll: function() {
return tracks;
},
});

TrackStore.dispatchToken = AppDispatcher.register(function(payload) {
var action = payload.action;

switch (action.type) {
case ActionTypes.RECEIVE_TRACKS_BY_ARTIST:
var err = null;
if (action.tracks.length === 0) {
err = ‘no tracks’;
} else {
tracks = action.tracks;
}
TrackStore.emitChange(err);
break;
case ActionTypes.RECEIVE_TRACKS_BY_COUNTRY:
tracks = action.tracks;
TrackStore.emitChange();
break;
}
});

// View
module.exports = React.createClass({
getInitialState() {
return {
tracks: TrackStore.getAll(),
err: null
};
},
componentDidMount: function() {
TrackStore.addChangeListener(this._onChange);
},
componentWillUnmount: function() {
TrackStore.removeChangeListener(this._onChange);
},
_onChange: function(err) {
if (err) {
this.setState({err: err});
} else {
this.setState({ tracks: TrackStore.getAll() });
}
},
또는 err가 아니라 객체를 전달하여 type으로써 error을 지정하거나 에러는 별도의 이벤트로써 발행하는 방법(CHANGE_EVENT가 아닌 ERROR_EVENT 등)도 있을 것 같습니다. Flux는 개념을 제공한 부분이 많으므로 이 개념을 잘 이용해 자신에게 맞는 최적의 환경을 구성하는 게 좋을 것 같습니다. 하지만 전혀 다른 형태의 Flux가 난립하여 혼란스러울 수도 있으니 조심히 접근합시다.

정리
이번 편에서는 React.js에서 테스트를 작성하는 방법과 테스트 프레임워크인 Jest 그리고 Flux 아키텍처를 간단히 소개했습니다. 다음 편에서는 React.js와 CSS의 관계를 CSS in JS 개념과 함께 소개하면서 최종적으로 정리하며 이 시리즈를 마무리하도록 하겠습니다.

React.js를 이해하다(5)
react.js

React.js를 이해하다(5)

블로그 사이트 바로가기

읽기전에…
이 문서는 koba04님이 작성한 React.js Advent Calendar를 번역한 것입니다. 본래 원문서는 캘린더 형식으로 소개하지만 여기에서는 회를 나눠 작성할 생각입니다. 또한, React 버전 0.12.1 때 작성된 문서이기 때문에 현 버전과 다른 점이 있을 수 있습니다. 최대한 다른 부분을 노트로 작성할 생각이지만, 만약 생략된 부분이 있다면 댓글로 알려주시면 감사하겠습니다.

Server-side rendering
이번에는 Server-Side Rendering을 소개하겠습니다. 이 기능 때문에 React.js를 사용하는 사람이 있을 정도로 React.js의 큰 특징 중 하나입니다. Server-Side Rendering은 말 그대로 서버 측에서 HTML을 생성하여 응답하는 방법을 말합니다. SPA(SinglePageApplication) 같은 자바스크립트에서 DOM을 조작하는 애플리케이션의 경우, 서버에서 만들어주는 HTML에는 빈 태그들만 있고 자바스크립트로 템플릿을 이용해 렌더링하는데 이러한 방법에는 두 가지의 큰 문제점이 있습니다.

초기 로드 시간 : HTML이 반환된 후 자바스크립트를 컴파일하고 템플릿을 이용해 렌더링하므로 서버 측에서 HTML을 만들어 응답하는 것에 비해 처리 시간이 조금 더 걸립니다. 그래서 로딩-바를 보여주는 등의 UI/UX 연구도 함께 필요합니다.
SEO : 최근에 구글의 크롤러가 자바스크립트를 컴파일할 수 있으므로 괜찮을지 모르겠지만 다른 크롤러에 대응하기 위해서는 PhantomJS를 사용해 서버 측에서 렌더링한 HTML을 응답하는 등의 별도의 기법이 필요합니다.
React.js와 Server-Side Rendering
React.js는 실제 DOM을 의존하지 않고 컴포넌트의 VirtualDOM을 HTML로 반환하는 메서드를 갖고 있습니다. 이 메서드를 이용해 Node.js 서버에서 React.js의 컴포넌트를 HTML로 만들어 응답할 수 있습니다. 요즘은 Browserify 를 이용해 브라우저 측에서도 CommonJS 스타일을 많이 사용하고 있으므로 도입하는 데 큰 문제가 없을 것으로 보입니다.

한번 간단한 샘플(저장소)을 이용해 한번 시험해 봤습니다.

원칙(renderToString()를 사용할 경우)
Server-Side Rendering 시, 서버 측에서 React.rednerToString()을 사용해 생성한 HTML의 DOM 구조와 브라우저 측에서 React.redner()하여 생성된 컴포넌트의 DOM 구조가 같아야하는데, HTML에 부여되는 data-react-checksum이라는 값을 사용해 두 상태가 같은지 비교합니다. checksum이 다를 경우엔 아래와 같은 경고 메시지가 출력됩니다.

React attempted to use reuse markup in a container but the checksum was invalid. This generally means that you are using server rendering and the markup generated on the server was not what the client was expecting. React injected new markup to compensate which works but you have lost many of the benefits of server rendering. Instead, figure out why the markup being generated is different on the client or server.
경고가 출력되면 서버에서 응답한 HTML에 의해 만들어진 DOM은 폐기되고 자바스크립트에 의해 다시 생성됩니다. 참고로 checksum은 HTML을 기준으로 Adler-32 알고리즘을 이용해 생성됩니다.

컴포넌트
컴포넌트 자체는 크게 의식할 필요가 없습니다만 componenetWillMount()는 서버 측에서도 호출되고, componentDidMount()는 브라우저에서만 호출되는 Lifecycle 메서드의 특징은 알아둘 필요가 있습니다.

var React = require(‘react’);

var App = React.createClass({
getInitialState() {
return {
message: ‘loading…’
};
},

componentDidMount() {
this.setState({message: ‘welcome!’});
},

render() {
var list = this.props.data.map(obj => <li key={obj.id}>{obj.id}:{obj.name}</li>);
return (
<div>
<p>server-side rendering sample</p>
<p>{this.state.message}</p>
<ul>{list}</ul>
</div>
);
}
});

module.exports = App;
위에서 “loading…” 이라는 메시지를 로드가 끝날 때 “welcome!” 으로 바꾸고 있는데 이 작업은 브라우저에서만 동작합니다.

서버
서버 측에서 주목해야 할 부분은 node-jsx와 renderToString() 입니다. 아래 예제에서는 /bundle.js를 요청할 때 동적으로 browserify 하고 있지만, 실제 서비스 시엔 사전에 browserify한 bundle.js를 준비해 두는 편이 좋습니다.

var express = require(‘express’),
app = express(),
fs = require(‘fs’),
browserify = require(‘browserify’),
reactify = require(‘reactify’),
Handlebars = require(‘handlebars’),
React = require(‘react’)
;

require(‘node-jsx’).install({harmony: true});

var App = require(‘./components/app’);
var data = [
{ id: 1, name: ‘backbone’ },
{ id: 2, name: ‘react’ },
{ id: 3, name: ‘angular’ },
];

var template = Handlebars.compile(fs.readFileSync(‘./index.hbs’).toString());

app.get(‘/’, function(req, res) {
res.send(template({
initialData: JSON.stringify(data),
markup: React.renderToString(React.createElement(App, {data: data}))
}));
});

app.get(‘/bundle.js’, function(req, res) {
res.setHeader(‘content-type’, ‘application/javascript’);
browserify(‘./browser’)
.transform({ harmony: true }, reactify)
.bundle()
.pipe(res)
;
});

var port = process.env.PORT || 5000;

console.log(‘listening…’ + port);
app.listen(port);
node-jsx
먼저 JSX로 작성한 컴포넌트 파일도 require 할 수 있도록 require(‘node-jsx’).install({harmony: true})를 선언하고 있습니다(harmony option도 유효).

renderToString()
React.renderToString()에는 React.createElement()를 이용해 작성한 컴포넌트를 전달합니다. 초기 설정 시 사용하는 데이터가 있다면 이것도 컴포넌트에 Prop으로 전달합니다. 또 전달한 데이터는 클라이언트 측에도 공유해야 하므로 템플릿으로 전달하기 위해 별도의 JSON.stringify 하여 initialData 로써 설정합니다.

템플릿
여기에서 포인트는 {{{}}}(이스케이프 하지 않는다) 에 renderToString()으로 HTML 문자열을 바인드하고, script 태그의 속성값으로 initialData를 바인드한 것입니다. 초기 데이터는 <script id=”initial-data”>{{{data}}}</script>로도 바인드해 사용할 수 있지만, data를 사용자가 조작 가능할 경우 XSS이 가능하므로 주의가 필요합니다 (참고(일본어))

<html>
<head>
<title>React.js server-side rendering sample</title>
</head>
<body>
<div id=”app”>{{{markup}}}</div>
<script id=”initial-data” type=”text/plain” data-json=”{{initialData}}”></script>
<script src=”/bundle.js”></script>
</body>
브라우저
브라우저 측의 엔트리 포인트에서는 initialData의 값을 취득하고 그 값을 사용해 컴포넌트를 작성합니다.

var React = require(‘react’),
App = require(‘./components/app’)
;

var data = JSON.parse(document.getElementById(‘initial-data’).getAttribute(‘data-json’));
React.render(<App data={data} />, document.getElementById(‘app’));
생성되는 소스
생성된 소스는 아래와 같은 느낌으로 root의 요소엔 data-react-checksum이, 각각 요소엔 data-reactid가 지정됩니다.

<body>
<div id=”app”><div data-reactid=”.25wfuv5brb4″ data-react-checksum=”-1037109598″><p data-reactid=”.25wfuv5brb4.0″>server-side rendering sample</p><p data-reactid=”.25wfuv5brb4.1″>loading…</p><ul data-reactid=”.25wfuv5brb4.2″><li data-reactid=”.25wfuv5brb4.2.$1″><span data-reactid=”.25wfuv5brb4.2.$1.0″>1</span><span data-reactid=”.25wfuv5brb4.2.$1.1″>:</span><span data-reactid=”.25wfuv5brb4.2.$1.2″>backbone</span></li><li data-reactid=”.25wfuv5brb4.2.$2″><span data-reactid=”.25wfuv5brb4.2.$2.0″>2</span><span data-reactid=”.25wfuv5brb4.2.$2.1″>:</span><span data-reactid=”.25wfuv5brb4.2.$2.2″>react</span></li><li data-reactid=”.25wfuv5brb4.2.$3″><span data-reactid=”.25wfuv5brb4.2.$3.0″>3</span><span data-reactid=”.25wfuv5brb4.2.$3.1″>:</span><span data-reactid=”.25wfuv5brb4.2.$3.2″>angular</span></li></ul></div></div>
<script id=”initial-data” type=”text/plain” data-json=”[{‘id’:1,’name’:’backbone’},{‘id’:2,’name’:’react’},{‘id’:3,’name’:’angular’}]”></script>
<script src=”/bundle.js”></script>
</body>
이 상태에서 브라우저 측에서 React.render()를 사용해 컴포넌트를 붙이면 checksum을 확인하여 문제가 없으면 DOM은 그대로 두고 이벤트 리스너만 등록합니다. 이러한 원리로 Server-Side Rendering 할 때는 HTML이 서버에서 반환되고 자바스크립트가 컴파일되어 이벤트 리스너가 등록되기 전까지 이벤트에 반응하지 않으므로 주의가 필요합니다.

renderToString()과 renderToStaticMarkup()
이 두 메서드는 필요에 따라 구별해 사용합니다. renderToStaticMarkup()은 data-reactid를 부여하지 않고 순수 HTML을 반환합니다. 즉, 정적 페이지로 출력해도 문제 없으면 사용합니다. 이때 renderToString()과 마찬가지로 renderToStaticMarkup()으로 HTML을 반환하고 브라우저 측에서도 컴포넌트를 실행할 수 있지만, 그 경우 renderToStaticMakrup()이 만든 HTML은 재사용되지 않고 브라우저 측에서 다시 HTML을 만들게 됩니다.

renderToStaticMarkup()에서 출력되는 HTML은 다음과 같습니다.

<body>
<div id=”app”><div><p>server-side rendering sample</p><p>loading…</p><ul><li>1:backbone</li><li>2:react</li><li>3:angular</li></ul></div></div>
<script id=”initial-data” type=”text/plain” data-json=”[{‘id’:1,’name’:’backbone’},{‘id’:2,’name’:’react’},{‘id’:3,’name’:’angular’}]”></script>
<script src=”/bundle.js”></script>
</body>
Flux를 사용할 때 주의할 점
Flux을 사용할 때, 컴포넌트가 싱글-톤의 Store를 가지고 있는 애플리케이션을 그대로 서버 측에서 사용하면 사용자마다 같은 Store가 공유돼 버리므로 주의가 필요합니다. 이 문제를 해결하기 위해 요청마다 Store를 만들 필요가 있습니다.

라우팅
라우팅하고 싶은 경우엔 어떻게 할지 고민될 것 같습니다. 이는 다음에 라우팅을 소개할 때 함께 이야기하겠습니다.

express-react-views
이 라이브러리는 본 문서에서도 소개하고 있는 renderToStaticMarkup()을 사용하고 있으므로 주의가 필요합니다.

Node.js 이외의 서버에서 사용
react-rails : rails와 조합하고 싶을 때 사용할 수 있습니다. ExecJS를 컴포넌트로 처리하고 있는 것 같습니다.
React.NET
react-python
react-php-v8js
여기까지 React.js의 Server-Side Rendering의 구조를 간단하게 소개했습니다. 다음 절에서는 React.js의 라우팅을 소개하겠습니다.

Server-Side Rendering에 대응한 Routing
Server-Side Rendering을 이어서 이번에는 Routing을 이야기하겠습니다. React.js는 컴포넌트를 만드는 라이브러리이므로 Router는 당연히 구현돼 있지 않습니다. 그래서 Backbone.Router나 Driector 등 좋아하는 Router 라이브러리를 조합해 사용합니다. 하지만 Page 단위로 컴포넌트를 만들어 갱신하는 경우엔 작성하기 거추장스럽고 장황하게 될 가능성이 있습니다. 그래서 여기에서는 react-router라는 것을 소개할까 합니다.

React Router
React Router는 이전까지 Server-Side Rendering을 지원하지 않았기 때문에 react-router-component를 사용했지만, 현재는 지원하므로 Server-Side Rendering이 필요한 경우에도 사용할 수 있습니다. React Router Component가 조금 더 단순하게 디자인돼 있으므로 조금 더 접근하기 편한 라이브러리를 찾는다면 분은 이 라이브러리를 참고해주세요. React Router는 기존 Component와 마찬가지로 Routing을 컴포넌트로 정의하는 형태가 됩니다. React Router는 중첩한 라우팅, 링크에 active class, Scroll Top 등 다양한 라우팅 기능을 지원합니다. README에 작성된 내용을 기준으로 사용 방법을 간단히 소개합니다.

정의
라우트를 정의할떄는 Route 컴포넌트를 사용하여 선언하고 라우팅 정의를 작성한 후 Router.run으로 시작합니다.

var routes = (
<Route handler={App} path=”/”>
<DefaultRoute handler={Home} />
<Route name=”about” handler={About} />
<Route name=”users” handler={Users}>
<Route name=”recent-users” path=”recent” handler={RecentUsers} />
<Route name=”user” path=”/user/:userId” handler={User} />
<NotFoundRoute handler={UserRouteNotFound}/>
</Route>
<NotFoundRoute handler={NotFound}/>
<Redirect from=”company” to=”about” />
</Route>
);

Router.run(routes, function (Handler) {
React.render(<Handler/>, document.body);
});
Link
앵커(Anchor)는 Link 컴포넌트를 이용합니다.

<Link to=”users”>Users</Link>
Handler
위 예의 경우 App의 Handler의 안에 각각의 Route가 정의 되어 있으므로 App 컴포넌트 안에 RouteHandler 컴포넌트를 정의해야합니다. 이 부분이 Routing을 응답하는 Handler로 대체됩니다.

var App = React.createClass({
render() {
return (
<div>
<h1>title</h1>
<RouteHandler/>
</div>
);
};
});
History API
HTML5의 History API를 사용하고 싶다면 아래와 같이 두번째 인수에 Router.HistoryLocation을 지정하고 Router.run을 실행합니다.

Router.run(routes, Router.HistoryLocation, function (Handler) {
React.render(<Handler/>, document.body);
});
Server-Side Rendering
Server-Side rendering 시에는 서버 측에서 아래와 같이 두번째 인수에 path를 전달하고 Router.run 합니다.

//express
app.use(function (req, res) {
// pass in `req.path` and the router will immediately match
Router.run(routes, req.path, function (Handler) {
var markup = React.renderToString(<Handler/>);
res.render(‘index’, {markup: markup});
});
});
예제 코드
그럼, 예제 코드를 한번 살펴보겠습니다. 이 예제 코드는 다음 글에서도 사용합니다. Vimeo와 YouTube의 비디오 리스트를 라우팅으로 전환할 수 있도록 작성했습니다. 초기의 데이터를 서버와 브라우저에서 공유하도록 설계했습니다. 예제에서는 React Router뿐만 아니라 react-bootstrap과 react-video를 사용하고 있습니다.

https://github.com/koba04/react-server-side-rendering-sample
http://react-ssr-sample.herokuapp.com
curl http://react-ssr-sample.herokuapp.com/youtube 나 curl http://react-ssr-sample.herokuapp.com/vimeo 으로 요청하면 이에 대응하는 video 정보를 data-react-id와 함께 반환하는 사실을 알 수 있습니다.

서버
코드 일부만 설명하겠습니다. Handler의 Prop에 params으로 초기 데이터를 전달합니다.

app.use(function(req, res) {
Router.run(routes, req.path, function(Handler) {
res.send(template({
initialData: JSON.stringify(data),
markup: React.renderToString(React.createElement(Handler, {params: {videos: data}}))
}));
});
});
이 예에서는 항상 같은 데이터를 반환하게 돼 있지만, req.path에 대응한 데이터를 반환하는 것도 가능합니다.

Browser entry point
Server-Side Rendering 때에도 동일하게 작성했습니다. JSON을 받아 Handler의 Props에 params로 전달합니다.

var initialData = JSON.parse(document.getElementById(‘initial-data’).getAttribute(‘data-json’));

Router.run(routes, Router.HistoryLocation, (Handler) => {
React.render(<Handler params={{videos: initialData}} />, document.getElementById(‘app’));
});
Routing
아래 코드는 이제 특별한 설명 없이도 이해할 수 있을것입니다.

module.exports = function() {
return (
<Route name=”app” path=”/” handler={App}>
<Route name=”youtube” handler={YouTube} />
<Route name=”vimeo” handler={Vimeo} />
<DefaultRoute handler={Top} />
</Route>
);
};
App
아래와 같은 느낌으로 RouteHandler에 spread attributes({…this.props})을 이용해 초기 데이터를 Prop으로 전달합니다.

var App = React.createClass({
render() {
return (
<div>
<h1><Link to=”app”>React server-side rendering sample</Link></h1>
<ListGroup>
<Link to=”youtube” key=”youtube”><ListGroupItem>youtube</ListGroupItem></Link>
<Link to=”vimeo” key=”vimeo”><ListGroupItem>vimeo</ListGroupItem></Link>
</ListGroup>
<RouteHandler {…this.props} />
</div>
);
}
});
Handler
그러면 Handler에서 전달한 초기 데이터를 Prop으로 받을 수 있으므로 이를 이용해 화면을 랜더링합니다.

var YouTube = React.createClass({
mixins: [VideoMixin],
render() {
return (
<Grid>
<h2>youtube</h2>
<Row className=”show-grid”>{this.renderVideos(‘youtube’)}</Row>
</Grid>
);
}
});

// VideoMixin
module.exports = {
getDefaultProps() {
return {
params: {
videos: {
youtube: [],
vimeo: []
}
}
};
},
renderVideos(type) {
return this.props.params.videos[type].map( video => {
return (
<Col xs={6} md={4} key={video.id}>
<Jumbotron>
<Video from={type} id={video.id} />
<p>{video.title}</p>
</Jumbotron>
</Col>
);
});
}
};
초기 데이터를 전부 전달하지 않는 경우
위 예를 조금 바꿔서 /api/youtube와 /api/vimeo로 각각의 데이터를 반환하는 API를 만들고 /youtube에 접근 시 /api/youtube가 반환하는 데이터를 초기 데이터로 사용할 때, 각각의 컴포넌트의 componentDidMount()에서 초기 데이터가 있는지 없는지 확인하여 없을 때만 Ajax 요청을 하도록 작성하면 됩니다.(componentDidMount()는 Server-Side에서 실행되지 않습니다) 이것으로 React Router를 사용한 Routing 작성법에 대해 알아봤습니다.

공개된 React 컴포넌트를 사용해보자
이번에는 조금 화제를 전환해 웹에 공개된 React 컴포넌트를 사용하는 것에 관해 이야기하겠습니다. 컴포넌트는 기본적으로는 Prop이 I/F가 됩니다. 따라서 문서를 통해서 컴포넌트의 특성을 알 수 없는 경우엔 Prop을 보면 어떤 I/F로 형성돼 있는지 알 수 있습니다. 직접 컴포넌트를 공개하는 경우엔 PropTypes나 getDefaultProps()를 사용해 I/F를 명확하게 작성해야 합니다.

부트스트랩
먼저 많이 사용하는 라이브러리인 부트스트랩입니다. React 컴포넌트로 구현한 라이브러리는 react-bootstrap입니다. 이 라이브러리를 사용하고자 할 땐 별도로 부트스트랩 CSS를 로드할 필요가 있습니다.

<link rel=”stylesheet” href=”https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css”>
부트스트랩의 각 컴포넌트가 React의 컴포넌트로 구현돼 있으며 다른 React의 컴포넌트와 마찬가지로 사용할 수 있습니다. (참고)

var {Jumbotron, Col} = require(‘react-bootstrap’);

module.exports = React.createClass({
render() {
<Col xs={6} md={4} key={video.id}>
<Jumbotron>
<Video from={type} id={video.id} />
<p>{video.title}</p>
</Jumbotron>
</Col>
}
});
react-bootstrap의 component 페이지에서 데모와 Prop의 사양 등을 확인할 수 있습니다

컴포넌트 찾기
React Components
React Components는 npm의 키워드로 react-component를 등록한 React의 컴포넌트를 모아놓은 사이트입니다. 여기에서 원하는 컴포넌트를 찾아볼 수 있습니다.

React Rocks
React Rocks는 여러 가지의 React의 컴포넌트를 사용한 샘플을 소개하고 있는 사이트입니다. 실제로 동작하는 데모(참고)를 볼 수 있습니다.

깃-허브의 위키
리액트의 깃허브 저장소에 작성된 공식 위키에도 여러가지 UI 컴포넌트를 소개하고 있으니 참고할 수 있습니다.

실전, 컴포넌트를 찾아서 사용해보자.
이번 절에서는 react-video라고 하는 유투브와 비메오(vimeo) 플레이어를 출력하는 컴포넌트를 실제로 사용해보고자 합니다. 이를 사용해 구현한 샘플을 공개해놨습니다.

사용 방법
type(from)과 id를 속성을 지정하는 방식으로 간단하게 사용할 수 있습니다.

var Video = require(‘react-video’);

type = ‘youtube’ // or ‘vimeo’
<Video from={type} id={video.id} />
CSS
컴포넌트를 사용하기 위해서는 아래 CSS를 로드해야 합니다. require하는 것만으로 CSS도 함께 작업해줬으면 하지만 아쉬운 점입니다.

https://github.com/pedronauck/react-video/blob/master/dist/react-video.css
I/F 확인
react-video의 README.md를 보면 알 수 있지만, I/F를 어떻게 디자인했는지 알아보겠습니다. propTypes과 getDefaultProps을 살펴보면 다음과 같은 사항을 알 수 있습니다.

from에는 youtube나 vimeo를 지정하며 필수 인자다.
id는 문자열이며 필수 인자다.
className도 지정할 수 있으며 기본값은 video다.
propTypes를 잘 명시하면 이해하는데 용이합니다.(참고)

propTypes:{
from: React.PropTypes.oneOf([‘youtube’, ‘vimeo’]).isRequired,
id: React.PropTypes.string.isRequired
},
getDefaultProps() {
return {
className: ‘video’
};
},
이번 편에서는 React.js의 Server-Side rendering과 Routing 그리고 공개된 React.js의 컴포넌트를 사용하는 방법을 소개했습니다. Server-Side rendering은 최근 Ember(참고)와 Angular2(참고)에서도 지원할 정도로 인기있는 기능입니다. 다음 편에서는 React.js를 테스트하는 방법과 Flux 아키텍처를 소개하겠습니다.

React.js를 이해하다(4)
react.js

React.js를 이해하다(4)

블로그 사이트 바로가기

읽기전에…
이 문서는 koba04님이 작성한 React.js Advent Calendar를 번역한 것입니다. 본래 원문서는 캘린더 형식으로 소개하지만 여기에서는 회를 나눠 작성할 생각입니다. 또한, React 버전 0.12.1 때 작성된 문서이기 때문에 현 버전과 다른 점이 있을 수 있습니다. 최대한 다른 부분을 노트로 작성할 생각이지만, 만약 생략된 부분이 있다면 댓글로 알려주시면 감사하겠습니다.

이번에는 React.js의 VIRTUAL DOM을 간단히 소개하겠습니다. VIRTUAL DOM의 자세한 설명은 VirtualDOM Advent Calendar 2014(일본어)를 참고하세요. 사실 이 캘린더 만으로도 Virtual DOM을 충분히 이해할 수 있지만 흐름 상 한번 다뤄야 할 것 같아 작성합니다.

React.js가 VIRTUAL DOM을 채택하고 있어 좋은 점
VIRTUAL DOM의 좋은 점
자바스크립트를 사용해 DOM을 조작하여 UI를 변경하는 애플리케이션의 경우, 사용자 경험을 해치지 않기 위해서라도 갱신되는 DOM을 최소한으로 유지합니다. 예를 들어 Backbone.js를 사용한다면 기본적으로 뷰 단위로 렌더링 하므로 뷰를 아주 잘게 나누는 것이 중요합니다. 그러면 뷰의 개수가 늘어나고 관계가 복잡해져 관리하기 힘듭니다. Angular.js의 경우는 Dirty Checking 하여 변경이 있을 때 다시 랜더링 되는 형식입니다. 이런 방법은 감시 대상이 늘어날수록 성능이 떨어지는 문제가 있습니다.(이 성능 문제를 개선하고자 버전 2부터는 Object.observe를 사용하도록 변경됩니다.)

React.js의 경우는 setState(forceUpdate)가 호출되면 그 컴포넌트와 하위 컴포넌트가 다시 랜더링되는 대상이 됩니다. 이 말을 듣게 되면 매번 광범위하게 DOM이 갱신된다고 느껴지지만 React.js에서는 VIRTUAL DOM이라고 하는 형태로 메모리상에 DOM의 상태를 유지하고 있고 전/후 상태를 비교하여 달라진 부분만 실제 DOM에 반영합니다. 참고로 CSS도 마찬가지로 객체 형식으로 지정해 변경된 Style만 갱신합니다.

var Hoge = React.createClass({
getInitialState() {
return {
style: {
color: ‘#ccc’,
width: 200,
height: 100
}
};
},
onChange() {
var style = _.clone(this.state.style);
style.color = ‘#ddd’;
this.setState({ style: style});
},
render() {
return (
<div style={this.state.style} onClick={this.onChange}>xxx</div>
);
}
}
이러한 방식으로 성능 문제를 해결한 것은 물론, 성능이 중요하지 않은 애플리케이션에서도 상위 레벨의 요소에 애플리케이션의 상태를 갖게 하고 그것을 setState()로 점점 갱신하는 것과 같은 조금은 거친 느낌으로 아키텍처도 할 수 있습니다. 서버 사이드의 렌더링과 비슷하네요. 즉, DOM을 다룰 때 신경 써야 하는 귀찮고 성능에 영향을 주는 부분을 React.js에 맡기는 것으로 애플리케이션의 구현을 단순하게 할 수 있는 특징이 있습니다.

애플리케이션 개발자가 VIRTUAL DOM을 직접 신경 쓰는 경우는 key 속성 지정과 성능 향상의 목적으로 shouldComponentUpdate()를 구현할 때입니다.

shouldComponentUpdate
shouldComponenetUpdate()에 관해서는 Component Lifecycle을 다룰 때 설명했습니다. 이 메서드를 구현(재정의)하지 않는 경우엔 UI를 항상 갱신하도록 구현돼 있습니다. 이 메서드가 false를 반환하면 그 컴포넌트와 하위 컴포넌트의 UI를 갱신하지 않습니다.(참고)

var shouldUpdate =
this._pendingForceUpdate ||
!inst.shouldComponentUpdate ||
inst.shouldComponentUpdate(nextProps, nextState, nextContext);
최소한의 DOM만 갱신되는 메커니즘으로 인해 항상 UI를 갱신하도록 구현해도 문제가 안 될 것 같지만, 매번 VIRTUAL DOM 트리를 만들어 실제 DOM을 비교하는 작업을 하게 되므로 실제 DOM은 갱신되지 않더라도 비용 들어 갑니다. 따라서 컴포넌트의 State와 Prop의 전/후 상태를 비교하여 변경이 있는 경우에만 컴포넌트와 하위 컴포넌트의 VIRTUAL DOM의 트리를 만들어 실제 DOM과 비교하여 UI를 갱신하도록 하는 것이 조금 더 비용을 낮추는 방법입니다.

React.js 이 외의 VIRTUAL DOM
React.js 외에도 VIRTUAL DOM을 채용하고 있는 라이브러리로는 mercury와 Mithril 등 여러 가지가 있고, Ember.js도 버전 2.0에서 VIRTUAL DOM의 구현을 검토(참고)하고 있습니다. 또한, 구현에 관해 알고 싶은 사람들은 vdom이나 deku의 소스부터 살펴나가는 것을 추천합니다.

여기까지 VIRTUAL DOM을 소개했습니다. 다음 절에서는 spread attributes를 사용하여 컴포넌트를 작성하는 방법을 소개하겠습니다.

Spread Attributes
이번에는 기존의 컴포넌트를 Spread Attributes를 사용하여 간단하게 컴포넌트를 확장하는 방법을 가볍게 소개하려고 합니다. Spread Attributes는 React.js 버전 0.12에 추가된 기능입니다.

텍스트와 함께 출력되는 이미지 컴포넌트
예로써, 텍스트와 이미지를 한데 묶은 ImageText 컴포넌트를 사용합니다. 이 컴포넌트의 I/F는 이미지 경로와 텍스트를 전달할 수 있도록 디자인했습니다.

var ImageText = React.createClass({
render() {
return (
<span>
{this.props.text}
<img src={this.props.src} width={this.props.width} height={this.props.height} />
</span>
);
}
});

<ImageText text=”이름” src=”/img/foo.png” width=”100″ height=”200″ />
위와 같은 느낌으로 단순하게 구현할 수 있습니다. 하지만 이미지 태그를 표기할 때는 alt 어트리뷰트가 필요합니다. 여기에 또 추가하자니 귀찮습니다. 이런 문제는 Spread Attributes를 사용하면 다음과 같이 작성할 수 있습니다.

var ImageText = React.createClass({
render() {
var {text, …other} = this.props;
return (
<span>{text}<img {…other} /></span>
);
}
});
Spread Attributes를 이용해 text와 ohter를 나누어 전달하면 이미지 어트리뷰트 갯수나 형식에 상관없이 사용할 수 있습니다. 자바스크립트로도 _.omit()을 이처럼 사용할 수 있습니다. 하지만 이렇게 작성할 경우 컴포넌트의 I/F를 알기 어려워지므로 PropTypes를 될 수 있으면 지정해두는 편이 좋다고 생각합니다.

클릭 이벤트 발생 시 Ajax 요청
이번에는 클릭 이벤트 발생 시 Ajax를 요청하도록 해보겠습니다.

var request = require(‘superagent’);
var ImageText = React.createClass({
onClick() {
request.get(‘/click_img’, { img: this.props.src });
},
render() {
var {text, …other} = this.props;
return (
<span>{text}<img {…other} onClick={this.onClick} /></span>
);
}
});
위와 같이 onClick()을 추가하면 Prop의 값과 자동으로 merge 합니다. 만약 {…other} 앞에 onClick()을 선언하면 Prop의 onClick을 우선시하여 덮어쓰므로 주의가 필요합니다.

var Hello = React.createClass({
onClick() {
alert(‘inner’);
},
render: function() {
var {name, …other} = this.props;
// 클릭시 inner 출력
return <div>Hello <span {…other} onClick={this.onClick}>{name}</span></div>;
// 클릭시 outer 출력
return <div>Hello <span onClick={this.onClick} {…other}>{name}</span></div>;
}
});
function onClick() {
alert(‘outer’);
}
React.render(<Hello name=”World” onClick={onClick}/>, document.getElementById(‘container’));
Spread Attributes는 JSX 없이도 _.extend(), Object.assign() 등을 사용하여 구현할 수 있습니다. 하지만 JSX의 spread attributes 사용하는 편이 조금 더 편리한 것 같습니다. 다음 절에서는 mixin을 소개하겠습니다.

React.js의 믹스-인
이번에는 컴포넌트의 믹스-인 기능을 소개하겠습니다. 보통 믹스-인은 이름 그대로 기능을 수집하는 수단을 말하고 React.js에서 믹스-인은 컴포넌트의 공통 로직을 Object로 분리하여 공통적으로 사용할 수 있도록 하는 기능 뜻합니다. React.js 자체도 LinkedStateMixin이나 PureRenderMxin 등의 믹스-인을 제공하고 있습니다. 덧붙여 Marionette.js에서는 Behavior로, Vue.js에서는 믹스-인이라는 이름으로 같은 기능이 존재합니다.

역자노트
아쉽지만 ES6 문법에서는 Mixin을 사용할 수 없습니다.(참고), react-mixin으로 사용할 수 있지만, 개인적으로 깔끔하진 않은 거 같습니다.

사용 방법
Object를 배열로 지정하는 방식으로 사용합니다. 배열을 보면 알 수 있듯이 복수 지정이 가능합니다.

var Logger = {
logging(str) {
console.log(str);
},
componentDidMount() {
this.logging(‘component did mount’);
}
};

var Hello = React.createClass({
mixins: [Logger],
render() {
this.logging(‘render’);
return <div>Hello</div>
}
});
믹스-인이 로드되는 순서
복수의 믹스-인을 지정할 수 있다고 말씀드렸습니다. 그럼 어떤 순서로 로드될까요? 예상대로 배열의 순서대로 믹스-인이 호출된 후 마지막에 컴포넌트의 메서드가 호출되는 것을 확인할 수 있습니다.

var MixinA = {
componentWillMount() {
console.log(‘mixinA’);
}
};

var MixinB = {
componentWillMount() {
console.log(‘mixinB’);
}
};

var Hello = React.createClass({
mixins: [MixinA, MixinB],
componentWillMount() {
console.log(‘hello’);
},
render() {
return <div>hello</div>
}
});

React.render(<Hello />, document.body);
// mixinA
// mixinB
// hello
Conflict State or Prop
getInitialState와 getDefaultProps 등을 믹스-인으로 지정하면 어떻게 될까요?

getInitialState
아래 예제를 보면 알 수 있듯이 State 값을 합칩니다.

var Mixin = {
getInitialState() {
return {
mixinValue: ‘mixin state’
};
}
};

var Hello = React.createClass({
mixins: [Mixin],
getInitialState() {
return {
componentValue: ‘component state’
};
},
render() {
console.log(this.state);
return <div>hello</div>
}
});

React.render(<Hello />, document.body);
// Object {mixinValue: ‘mixin state’, componentValue: ‘component state’}
getDefaultProps
Props도 State와 마찬가지로 값을 합칩니다.

var Mixin = {
getDefaultProps: function() {
return {
mixinValue: ‘mixin prop’
};
}
};

var Hello = React.createClass({
mixins: [Mixin],
getDefaultProps: function() {
return {
componentValue: ‘component prop’
};
},
render: function() {
console.log(this.props);
return <div>hello</div>
}
});

React.render(<Hello />, document.body);
// Object {mixinValue: ‘mixin prop’, componentValue: ‘component prop’}
getInitialState에서 같은 key를 지정
만약 믹스-인과 같은 key를 지정할 경우엔 에러가 발생합니다.

var Mixin = {
getInitialState() {
return {
value: ‘mixin state’
};
}
};

var Hello = React.createClass({
mixins: [Mixin],
getInitialState() {
return {
value: ‘component state’
};
},
render() {
console.log(this.state);
return <div>hello</div>
}
});

React.render(<Hello />, document.body);
// Uncaught Error: Invariant Violation: mergeObjectsWithNoDuplicateKeys(): Tried to merge two objects with the same key: `value`. This conflict may be due to a mixin; in particular, this may be caused by two getInitialState() or getDefaultProps() methods returning objects with clashing keys.
메서드 재정의
믹스-인과 동일한 이름의 메서드를 컴포넌트에서 선언해 재정의 할때도 에러가 발생합니다.

var Mixin = {
foo: function() {
console.log(‘mixin foo’);
}
};

var Hello = React.createClass({
mixins: [Mixin],
foo: function() {
console.log(‘component foo’);
},
render: function() {
return <div>hello</div>
}
});

React.render(<Hello />, document.body);
// Uncaught Error: Invariant Violation: ReactCompositeComponentInterface: You are attempting to define `foo` on your component more than once. This conflict may be due to a mixin.
믹스-인을 이용하면 코드를 줄일 수 있습니다. 로직을 어렵게 하지 않을 수준에서 잘 사용하길 바랍니다. 여기까지 믹스-인을 소개했습니다. 다음 절에서는 애드온을 소개하겠습니다.

React.js의 애드온
이번에는 에드온을 소개하겠습니다. 엔드온은 코어에 들어갈 수준은 아닌 편리한 믹스-인이나 테스트 유틸, 성능 측정 도구 등을 모아 놓은 부가 기능입니다.

사용 방법
애드온은 require하거나 js 파일을 로드하는 것으로 사용할 수 있습니다.

var React = require(‘react/addons’);
<script src=//cdnjs.cloudflare.com/ajax/libs/react/0.12.1/react-with-addons.js”></script>
TestUtils
React.js를 테스트할 때 편리하게 사용할 수 있는 애드온이며 개발 환경에서만 사용할 수 있습니다. click 이벤트와 같은 이벤트를 시뮬레이터 하는 TestUtils.Simurate나 isElementOfType과 isDOMComponent 등 컴포넌트의 상태를 확인할 수 있는 함수까지 여러 가지 있습니다.(React.js 테스트는 추후 다시 소개하겠습니다.)

cloneWithProps
이 애드온을 사용하는 경우는 많지 않습니다. 어떤 컴포넌트에서 다른 Prop에 의한 새로운 컴포넌트를 만들고 싶을 때 사용합니다.

var cloneWithProps = React.addons.cloneWithProps;

var Item = React.createClass({
render: function() {
var text = this.props.text + (this.props.index != null ? ‘:’ + this.props.index : ”);
return <div>{text}</div>
}
});

var Loop = React.createClass({
render: function() {
var items = _.map(_.range(this.props.count), function(i) {
return cloneWithProps(this.props.children, { key: i, index: i });
}.bind(this));
return <div>{items}</div>
}
});

React.render(<Loop count=”10″><Item text=”hoge” /></Loop>, document.body);
위는 횟수만큼 children 컴포넌트를 만드는 과정을 cloneWithProps 애드온을 사용해 작성한 것입니다.

update
Object를 Immutable하게 조작하기 위한 애드온입니다. 뒤에서 설명할 PureRenderMixin() 또는 Prop과 State를 비교해 최적화하는 용도의 shouldComponentUpdate와 함께 조합해서 사용하면 편리합니다.

var update = React.addons.update;

var obj = {
list: [1,2,3],
};

var obj2 = update(obj, {
list: {
$push: [4]
}
});

console.log(obj2.list); // [‘a’,’b’,’c’,’d’]
console.log(obj === obj2); // false
참고로 페이스북은 별도의 Immutable.js를 만들고 있습니다. 이를 다음과 같이 사용할 수도 있습니다.

var obj = Immutable.Map({
list: Immutable.List.of(1, 2, 3)
});

var obj2 = obj.set(‘list’, obj.get(‘list’).push(4));

console.log(obj2.get(‘list’).toArray()); // [‘a’,’b’,’c’,’d’]
console.log(obj === obj2); // false
PureRenderMixin
성능을 최적화하기 위한 믹스-인입니다. 아래 코드를 살펴보겠습니다.(참고)

var ReactComponentWithPureRenderMixin = {
shouldComponentUpdate: function(nextProps, nextState) {
return !shallowEqual(this.props, nextProps) ||
!shallowEqual(this.state, nextState);
}
};
위 믹스-인이 사용하는 shallowEqual은 다음과 같이 작성돼 있습니다. 중첩된 값까지는 고려하지 않고 단순하게 비교합니다.(참고)

function shallowEqual(objA, objB) {
if (objA === objB) {
return true;
}
var key;
// Test for A’s keys different from B.
for (key in objA) {
if (objA.hasOwnProperty(key) &&
(!objB.hasOwnProperty(key) || objA[key] !== objB[key])) {
return false;
}
}
// Test for B’s keys missing from A.
for (key in objB) {
if (objB.hasOwnProperty(key) && !objA.hasOwnProperty(key)) {
return false;
}
}
return true;
}
Perf
성능 측정을 위한 애드온입니다. 개발 환경에서만 사용할 수 있습니다. Perf.start()와 Perf.stop()으로 성능을 측정하고 싶은 로직을 둘러싸고 수치화할 수 있습니다.

React.addons.Perf.start();
this.setState({ items: items }, function() {
React.addons.Perf.stop();
React.addons.Perf.printInclusive();
});
어떤 식으로 수치화되는지 확인하기 위해 Item 컴포넌트를 100개 추가하는 로직을 성능 측정하는 예제를 작성했습니다. 측정 결과는 개발자 콘솔에서 확인할 수 있습니다.

측정 결과의 수치가 매우 작은 경우엔 출력이 무시되니 참고바랍니다.

printInclusive
측정 중인 컴포넌트 처리에 걸린 시간을 알기 쉽게 출력합니다.

printInclusive의 성능 측정 결과
<그림 1 printInclusive>
printExclusive
컴포넌트 처리에 걸린 시간을 더 상세히 출력합니다.

printExclusive의 성능 측정 결과의 성능 측정 결과
<그림 2 printExclusive>
printWasted
실제 렌더링 처리 이외에 걸린 시간을 출력합니다. shouldComponenetUpdate()를 적용하는 타이밍을 찾기 위한 단서로 사용합니다.

printWasted의 성능 측정 결과의 성능 측정 결과
<그림 3 printWasted>
printDOM(measurements)
돔을 추가하거나 삭제한 내역을 출력합니다.

printDOM의 성능 측정 결과의 성능 측정 결과
<그림 4 printDOM>
getLastMeasurements
성능 측정 결과를 Object 형식으로 가져올 수 있습니다. 서버에 결과를 보내거나 위에서 소개한 각 메서드에 값을 넘겨줄 수도 있습니다. 측정 후 보기 좋게 정리하기 위해서도 사용할 수 있습니다.

React.js에서 애니메이션 처리하기
이번에는 React.js에서 애니메이션을 다루는 방법을 소개하겠습니다. React.js에서는 애니메이션을 Addon으로 지원하고 있으며 CSS 애니메이션과 CSSTransitionGroup addon을 사용하는 방식과 컴포넌트의 Lifecycle 메서드와 같은 메서드에서 훅(hook)하여 작성하는 두 가지 패턴으로 애니메이션을 처리할 수 있습니다.

CSSTransitionGroup
CSSTransitionGroup을 이용하면 컴포넌트를 추가/삭제 시 CSS 애니메이션을 줄 수 있습니다. 방법은 Angular.js와 Vue.js와 비슷합시다. 추가/삭제 시 클래스를 추가하여 CSS 애니메이션을 처리하는 방식입니다. {transitionName}-{enter, leave} 패턴으로 클래스 명이 추가된 뒤, 다음 이벤트 루프에서 {transitionName}-{enter, leave}-active의 className이 추가되는데 이때 이 클래스 명을 사용하여 CSS애니메이션을 처리합니다.(참고)

var CSSTransitionGroup = React.addons.CSSTransitionGroup;

var Hello = React.createClass({
getInitialState: function() {
return {
value: ‘(´・ω・`)’
};
},
onClick: function() {
var value = this.state.value === ‘(´・ω・`)’ ? ‘(`・ω・´)ゞ’ : ‘(´・ω・`)’;
this.setState({ value: value });
},
render: function() {
var value = <span className=”sample” key={this.state.value}>{this.state.value}</span>;
return (
<div>
<div>Animation!!<button onClick={this.onClick}>click!!</button></div>
<CSSTransitionGroup transitionName=”sample”>
{value}
</CSSTransitionGroup>
</div>
);
}
});

React.render(<Hello />, document.body);
.sample-enter {
-webkit-transition: 1s ease-in;
}
.sample-enter.sample-enter-active {
font-size: 80px;
}
.sample-leave {
-webkit-transition: .5s ease-out;
}
.sample-leave.sample-leave-active {
font-size: 10px;
}
주의할 점
애니메이션 되는 요소에는 반드시 key를 지정해야 합니다. 애니메이션 되는 요소가 1개라도 반드시 지정해야 합니다. 이는 컴포넌트가 추가됐는지 아니면 갱신됐는지를 알려주기 위함입니다. 이것을 이용하면 앞에서 소개한 예처럼 컴포넌트가 1개라도 key를 변경하는 것으로 애니메이션을 적용할 수 있습니다.(key를 변경했다는 뜻은 컴포넌트를 추가[또는 갱신]/삭제했다는 뜻이므로)

애니메이션은 추가(enter) 시와 삭제(leave) 시 두 경우 모두에 지정할 필요가 있습니다. 만약 한 경우에만 애니메이션을 지정하고 싶다면 transitionEnter={false}, transitionLeave={false}를 지정합니다.

<CSSTransitionGroup transitionName=”sample” transitionLeave={false}>
{value}
</CSSTransitionGroup>
CSSTransitionGroup의 컴포넌트는 애니메이션 시작 시엔 이미 랜더링 돼 있어야 합니다. 추가되는 요소와 함께 CSSTransitionGroup의 컴포넌트를 추가하면 애니메이션하지 않습니다. 예를 들어 아래의 경우 처음 click 시엔 CSSTransitionGroup이 없으므로 애니메이션하지 않습니다.

var Hello = React.createClass({
getInitialState: function() {
return {
value: ”
};
},
onClick: function() {
var value = this.state.value === ‘(´・ω・`)’ ? ‘(`・ω・´)ゞ’ : ‘(´・ω・`)’;
this.setState({ value: value });
},
render: function() {
var value ;
if (this.state.value) {
value = (
<CSSTransitionGroup transitionName=”sample”>
<span className=”sample” key={this.state.value}>{this.state.value}</span>
</CSSTransitionGroup>
);
}
return (
<div>
<div>Animation!!<button onClick={this.onClick}>click!!</button></div>
{value}
</div>
);
}
});
ReactTransitionGroup
CSS 애니메이션이 아니라 직접 유연하게 애니메이션 작성하고 싶은 경우엔 ReactTransitionGroup을 사용합니다. componentWillEnter(callback), componentDidEnter(), componentWillLeave(callback), componentDidLeave() 이 4개의 Lifecycle 메서드를 이용해 작성합니다. 또 ReactTransitionGroup은 기본으로 span 요소를 DOM에 추가하는데 <ReactTransitionGroup compoenent=”ul”> 문법으로 추가하는 요소를 지정할 수 있습니다.(참고)

var TransitionGroup = React.addons.TransitionGroup;
var duration = 1000;
var AnimationComponent = React.createClass({
componentWillEnter: function(callback) {
console.log(‘component will enter’);
$(this.getDOMNode()).hide();
callback();
},
componentDidEnter: function() {
$(this.getDOMNode()).show(duration);
console.log(‘component did enter’);
},
componentWillLeave: function(callback) {
console.log(‘component will leave’);
$(this.getDOMNode()).hide(duration, callback);
},
componentDidLeave: function() {
console.log(‘component did leave’);
},
render: function() {
return <div>{this.props.text}</div>
}
});

var Hello = React.createClass({
getInitialState: function() {
return {
value: ‘(´・ω・`)’
};
},
onClick: function() {
var value = this.state.value === ‘(´・ω・`)’ ? ‘(`・ω・´)ゞ’ : ‘(´・ω・`)’;
this.setState({ value: value });
},
render: function() {
var value = <AnimationComponent key={this.state.value} text={this.state.value} />;
return (
<div>
<div>Animation!!<button onClick={this.onClick}>click!!</button></div>
<TransitionGroup>
{value}
</TransitionGroup>
</div>
);
}
});

React.render(<Hello />, document.body);
주의할 점
componentWillEnter()와 componentWillLeave() 처리가 끝나게 되면 반드시 callback을 호출해야 합니다.

여기까지 애니메이션에 관해서 간단히 소개했습니다. 이러한 방식으로 애니메이션을 처리하는데 익숙치 않기 때문에 보통 쓰기 어려운 감이 들 수 있습니다. React.js 측에서도 향후 개선점으로 애니메이션도 다루고 있으므로 앞으로는 더욱 쉬워질 것이로 생각합니다.

정리
이번 편에서는 React.js에서 VIRTUAL DOM을 채택해서 가능한 메커니즘과 간단하게 Props를 전달할 수 있는 Spread Attribute 그리고 믹스-인과 애드온, 마지막으로 애니메이션을 처리하는 방법을 소개했습니다. 여기까지 기본적인 React.js 사용법은 모두 소개했습니다. React.js를 이해하는 비용은 그리 비싸지 않습니다. 이 정도의 특징만 숙지해도 큰 무리 없이 컴포넌트를 개발할 수 있습니다. React.js 자체를 사용하는 것보다 컴포넌트를 설계하는 것이 더 어렵고 개발자의 역량에 따라 컴포넌트 효율성이나 디자인이 크게 좌우될 수 있습니다. 많이 만들고 고민해서 좋은 컴포넌트를 만들 수 있길 바랍니다.

다음편에서는 Server-side rendering과 컴포넌트를 테스트하는 방법 등을 소개하겠습니다.

 

React.js를 이해하다(3)
react.js

React.js를 이해하다(3)

블로그 사이트 바로가기

읽기전에…
이 문서는 koba04님이 작성한 React.js Advent Calendar를 번역한 것입니다. 본래 원문서는 캘린더 형식으로 소개하지만 여기에서는 회를 나눠 작성할 생각입니다. 또한, React 버전 0.12.1 때 작성된 문서이기 때문에 현 버전과 다른 점이 있을 수 있습니다. 최대한 다른 부분을 노트로 작성할 생각이지만, 만약 생략된 부분이 있다면 댓글로 알려주시면 감사하겠습니다.

이번에는 컴포넌트의 라이프사이클(Lifecycle)을 소개하겠습니다.

Component Lifecycle
React.js는 컴포넌트의 상태 변화에 맞춰 호출되는 여러 가지 메서드를 제공 합니다. 그 메서드를 사용해 초기화나 후처리 등을 할 수 있습니다. 자주 사용하는 메서드는 componenetDidMount()나 componentWillUnmount() 입니다. componentDidMount()에서 이벤트를 등록하고 componentWillUnmount()에서 이벤트를 해제하는 패턴을 많이 사용합니다.

componentWillMount()
컴포넌트가 DOM 트리에 추가되기 전 한 번만 호출됩니다. 초기화 처리를 하는 데 사용할 수 있습니다. 이 안에서 setState하면 render 시에 사용됩니다. Server-side rendering 시에도 호출되므로 어느 쪽에서도 동작할 수 있는 코드를 작성해야 합니다.

역자노트
Server-side rendering 시에도 호출 되므로 대도록 이 Lifecycle 메서드에서 DOM을 컨트롤 하는 브라우저에서만 동작하는 로직을 작성하면 안됩니다. Node.js 환경에서는 DOM이 없으므로 에러가 발생하게 됩니다.

componentDidMount()
컴포넌트가 DOM 트리에 추가된 상태에 호출됩니다. DOM과 관련된 초기화를 하고 싶을 때 편리하게 사용할 수 있습니다. componentWillMount()와 다른 게 Server-side rendering 시에 호출되지 않습니다. 따라서 DOM을 다루는 처리 외에, Ajax 요청이나 setInterval 등의 Server-side rendering 시에는 불필요한 초기화 처리는 이 메서드를 통해 진행합니다.

componentWillReceiveProps(nextProps)
Prop이 갱신될 때 호출됩니다. 컴포넌트가 새로운 DOM 트리에 추가될 때는 호출되지 않습니다. 부모 컴포넌트의 State가 Prop으로 전달되고, 그 값이 변화한 할 때 화면의 표시 이외 Notification 같은 추가 작업을 이 메서드를 통해 할 수 있습니다. 마지막으로 Prop의 값에 따라 State의 값을 갱신 할 때에도 사용합니다.

shouldComponentUpdate()
이 메서드는 다른 메서드 Lifecycle 메서드와 달리 true나 false를 반환할 필요가 있습니다. 컴포넌트가 rerender 하기 전에 호출되며, 만약 false를 반환하면 VirtualDOM 비교를 하지 않고 rerender도 하지 않습니다. 즉, 독자적으로 Prop이나 State 비교 처리를 구현하는 것으로 불필요한 계산을 하지 않을 수 있습니다. 보통 성능 향상을 목적으로 사용합니다. 이 메서드가 반환하는 기본값은 true 이므로 재정의 하지 않으면 항상 rerender 합니다. 강제적으로 rerender 하고자 할땐 forceUpdate()를 사용합니다. forceUpdate()가 호출되는 경우엔 shouldComponentUpdate()는 호출되지 않습니다.

Porp과 State가 Immutable한 데이터라면 다음과 같이 단순한 객체 비교로 구현이 가능합니다.

shouldComponentUpdate: function(nextProps, nextState) {
return nextProps.user !== this.props.user || nextState.user !== this.state.user;
}
componentWillUpdate(nextProps, nextState)
컴포넌트가 갱신되기 전에 호출됩니다. 최초엔 호출되지 않습니다. 이 안에서는 setState를 호출할 수 없으므로 Prop의 값을 이용해 setState 하고 싶은 경우엔 componentWillReceiveProps()를 사용합니다.

componentDidUpdate(prevProps, prevState)
컴포넌트가 갱신된 뒤에 호출됩니다. 최초엔 호출되지 않습니다. DOM의 변화에 hook 하여 또 다른 작업을 하고 싶을 때 사용할 수 있습니다.

componentWillUnmount()
컴포넌트가 DOM에서 삭제될 때 호출됩니다. 이벤트 해제 같은 clean-up 처리 시 할 때 사용합니다. ComponentDidMount()에서 등록한 Timer의 처리나 DOM의 이벤트 등은 여기에서 해제해야 합니다.

추가
isMounted()
개발 시 Ajax를 요청하고 그 결과를 setState 하는 패턴이 자주 발생합니다. 그때 Ajax의 응답이 왔을 때 컴포넌트가 이미 Unmount 된 경우가 있는데, 바로 setState나 forceUpdate를 호출하면 에러가 발생하게 됩니다. 따라서 isMounted()를 사용해 방어 코드를 작성할 필요가 있습니다.

componentDidMount() {
request.get(‘/path/to/api’, res => {
if (this.isMounted()) {
this.setState({data: res.body.data});
}
});
}
여기까지 컴포넌트의 Lifecycle를 소개했습니다. 다음절에서는 이벤트를 소개하겠습니다.

React.js의 이벤트
이번 절에서는 DOM 이벤트 처리를 소개하겠습니다.

SyntheticEvent
React.js에서는 DOM을 VIRTUAL DOM으로 랩핑한 것처럼 DOM의 이벤트 객체도 SyntheticEvent이라는 객체로 랩핑하여 크로스 브라우저에 대응하고 있습니다. SyntheticEvent의 인터페이스는 아래와 같습니다.

boolean bubbles
boolean cancelable
DOMEventTarget currentTarget
boolean defaultPrevented
Number eventPhase
boolean isTrusted
DOMEvent nativeEvent
void preventDefault()
void stopPropagation()
DOMEventTarget target
Date timeStamp
String type
이처럼 preventDefault()나 stopPropagation() 그리고 target 등을 지금까지 다뤘던 방식으로 사용할 수 있습니다. 추가로 이벤트 리스너에서 false를 반환하는 방법으로 이벤트의 전파를 정지할 수 있었지만, 이 방법은 이해하기 어렵다는 이유로 React.js 버전 0.12에서는 사용할 수 없도록 변경됐습니다.

이벤트 핸들러
기본적인 이벤트는 모두 지원하고 있습니다. 예를 들어 click 이벤트를 처리하고 싶은 경우엔 아래와 같이 작성합니다.

var Counter = React.createClass({
getInitialState() {
return {
count: 0
};
},
onClick(e) {
// e is SyntheticEvent
this.setState({ count: this.state.count + 1 });
},
render() {
return (
<div>
<span>click count is {this.state.count}</span>
<button onClick={this.onClick}>click!</button>
</div>
);
}
});
onClick={this.onClick}으로 클릭 이벤트를 받고 있습니다. 이때 React.js는 컴포넌트의 문맥을 리스너에 bind 해주므로 따로 this.onClick.bind(this)와 같은 별도의 바인딩 작업이 필요하지 않습니다. 따라서 리스너 내에서 바로 this.setState()와 같은 메서드를 사용할 수 있습니다. 참고로 자동으로 this를 바인딩하는 동작은 앞으로 ES6의 ArrowFunction를 사용하도록 권고하고 지원하지 않을 수 있습니다.

역자노트
객체 리터럴로 컴포넌트를 생성할때는 실행 문맥 바인드가 필요 없지만 ES6 Classes 문법으로 작성할 땐 필요합니다.(참고)

Event delegation
Event Delegation은 jQuery에도 널리 알려진 대중적인 개념입니다. React.js는 자동으로 최상위 요소에만 이벤트를 등록하고 그곳에서 이벤트를 취합하여 내부에서 관리하는 맵핑 정보를 바탕으로 대응하는 컴포넌트에 이벤트를 발행합니다. 이때 이벤트는 캡처링, 버블링 되는데, 각 리스너마다 SyntheticEvent의 객체가 만들어지기 때문에 메모리의 얼로케이트를 여러 번 할 필요가 있습니다. 이 문제를 해결하기 위해 React.js는 객체를 풀(pool)로 관리하고 재사용하여 가비지 컬렉터의 횟수를 줄일 수 있도록 구현돼 있습니다. 추가로 DOM에 설정된 data-reactid을 사용해서 맵핑하고 있는 것 같습니다. 그리고 id로 부모와 자식 관계를 알 수 있도록 디자인돼 있습니다.(참고)

<ul class=”nav nav-pills nav-justified” data-reactid=”.1px6jd5i1a8.1.0.0.0.1.0″>
<li class=”” data-reactid=”.1px6jd5i1a8.1.0.0.0.1.0.0″>
<a href=”/artist” data-reactid=”.1px6jd5i1a8.1.0.0.0.1.0.0.0″>Artist</a>
</li>
<li class=”” data-reactid=”.1px6jd5i1a8.1.0.0.0.1.0.1″>
<a href=”/country” data-reactid=”.1px6jd5i1a8.1.0.0.0.1.0.1.0″>Country</a>
</li>
</ul>
Not provided event
React.js가 지원하는 기본적인 이벤트 외에 window의 resize 이벤트나 jQuery Plugin의 독자 포멧 이벤트를 사용하고 싶은 경우 componentDidMount()에서 addEventListener를 통해 이벤트를 등록하고 componentWillUnmount()를 이용해 removeEventListener 하여 이벤트를 해제해 사용합니다.(참고) 참고로 이 경우 역시 this를 자동으로 bind 합니다.

var Box = React.createClass({
getInitialState() {
return {
windowWidth: window.innerWidth
};
},
handleResize(e) {
this.setState({windowWidth: window.innerWidth});
},
componentDidMount() {
window.addEventListener(‘resize’, this.handleResize);
},
componentWillUnmount() {
window.removeEventListener(‘resize’, this.handleResize);
},
render() {
return <div>Current window width: {this.state.windowWidth}</div>;
}
});

React.render(<Box />, mountNode);
글로벌 이벤트를 선언하는 방법에 여러 논의가 있었습니다. 이슈285을 참고하세요.

touch event
터치 이벤트는 기본적으로 비활성화 돼 있습니다. 활성화하고 싶은 경우엔 React.initializeTouchEvents(true)를 호출합니다.

여기까지 Event를 정리했습니다. 다음으로 Form을 다루는 방법을 소개하겠습니다.

React.js에서 폼 다루기
이번 절에서는 React.js에서 폼을 다루는 방법을 소개하겠습니다. React.js에서는 아래와 같이 Input 폼을 작성하면 변경할 수 없는 텍스트 필드가 생성됩니다.(데모)

<input type=”text” value=”initial value” />
<input type=”text” value={this.state.textValue} />
Controlled Component
Controlled Component는 State에 따라 값을 관리하는 Componenet 입니다. 이를 이용해 텍스트 필드를 재작성합니다.

var Text = React.createClass({
getInitialState() {
return {
textValue: “initial value”
};
},
changeText(e) {
this.setState({textValue: e.target.value});
},
render() {
return (
<div>
<p>{this.state.textValue}</p>
<input type=”text” value={this.state.textValue} onChange={this.changeText} />
</div>
);
}
});
value를 State로 관리하고, onChange()에서 setState()하여 명시적으로 값을 갱신하고 전달합니다.

UnControlled Component
UnControlled Componenent는 반대로 값을 관리하지 않는 컴포넌트로 초기값을 설정한 값은 defaultValue로 지정합니다. 이 경우는 앞 절에서처럼 onChange()에서 항상 값을 state에 반영해도 되고, 반영하고 싶을 때만 DOM에서 value를 취득하여 갱신하는 것도 가능합니다.

var LiveText = React.createClass({
getInitialState() {
return {
textValue: “initial value”
};
},
changeText(e) {
this.setState({textValue: this.refs.inputText.getDOMNode().value });
},
render() {
return (
<div>
<p>{this.state.textValue}</p>
<input type=”text” ref=”inputText” defalutValue=”initial value” />
<button onClick={this.changeText}>change</button>
</div>
);
}
});
textarea
textarea의 경우도 텍스트 필드와 마찬가지로 value를 지정합니다. HTML 처럼 <textarea>xxx</textarea> 으로 작성하면 xxx는 defaultValue로 취급됩니다.(데모)

var OreTextArea = React.createClass({
getInitialState() {
return {
textAreaValue: ‘initial value’
};
},
onChangeText(e) {
this.setState({textAreaValue: e.target.value});
},
onClick() {
this.setState({textAreaValue: this.refs.textArea.getDOMNode().value});
},
render() {
return (
<div>
<div>{this.state.textAreaValue}</div>
<div>
<textarea value={this.state.textAreaValue} onChange={this.onChangeText} />
</div>
<div>
<textarea ref=”textArea”>this is default value</textarea>
<button onClick={this.onClick}>change</button>
</div>
</div>
);
}
});
셀렉트 박스
셀렉트 박스도 역시 value를 지정합니다. multiple={true}와 같이 Prop을 지정하면 요소를 복수로 선택할 수 있습니다.(데모)

var OreSelectBox = React.createClass({
getDefaultProps() {
return {
answers: [1, 10, 100, 1000]
};
},
getInitialState() {
return {
selectValue: 1,
selectValues: [1,100]
};
},
onChangeSelectValue(e) {
this.setState({selectValue: e.target.value});
},
// 더 좋은 방법이 있을지…
onChangeSelectValues(e) {
var values = _.chain(e.target.options)
.filter(function(option) { return option.selected })
.map(function(option) { return +option.value })
.value()
;
this.setState({selectValues: values});
},
render() {
var options = this.props.answers.map(function(answer) {
return <option value={answer} key={answer}>{answer}</option>;
});
return (
<div>
<div>selectValue: {this.state.selectValue}</div>
<div>
<select value={this.state.selectValue} onChange={this.onChangeSelectValue}>
{options}
</select>
</div>
<div>selectValues: {this.state.selectValues.join(‘,’)}</div>
<div>
<select multiple={true} defaultValue={this.state.selectValues} onChange={this.onChangeSelectValues}>
{options}
</select>
</div>
</div>
);
}
});
LinkedStateMixin
LinkedStateMixin이라는 addon을 사용하면 앞에서 처럼 onChange()를 일일이 구현하지 않아도 state에 반영할 수 있습니다. 체크박스에 사용할 때는 checkLink를 사용합니다.

var React = require(‘react/addons’);
var LinkedStateMixin = React.createClass({
mixins: [React.addons.LinkedStateMixin],
getInitialState() {
return {
textValue: ‘initial value’
}
},
render() {
return (
<div>
<div>value: {this.state.textValue}</div>
<input type=”text” valueLink={this.linkState(‘textValue’)} />
</div>
);
}
});
이 mixin이 하고 있는 것은 간단합니다. 내부 로직을 한번 살펴보는 것도 재미있을 것 같습니다.

LinkedStateMixin의 동작 방식
우선 Mixin해서 사용하는 linkState의 내부 로직을 보면 value와 무엇인가 작성한 Setter를 전달해서 ReactLink 객체의 인스턴스를 생성해 반환하고 있습니다.(참고)

linkState: function(key) {
return new ReactLink(
this.state[key],
ReactStateSetters.createStateKeySetter(this, key)
);
}
ReactStateSetters.createStateKeySetter의 내부를 보면 전달된 State의 키에 대응해서 setState를 하는 함수를 반환하고 있습니다.(참고)

createStateKeySetter: function(component, key) {
// Memoize the setters.
var cache = component.__keySetters || (component.__keySetters = {});
return cache[key] || (cache[key] = createStateKeySetter(component, key));
}
};

function createStateKeySetter(component, key) {
// Partial state is allocated outside of the function closure so it can be
// reused with every call, avoiding memory allocation when this function
// is called.
var partialState = {};
return function stateKeySetter(value) {
partialState[key] = value;
component.setState(partialState);
};
}
ReactLink의 Constructor(생성자)에서는 값(value)과 requestChange(createStateKeySetter에서 반환한 함수)를 프로퍼티로 설정합니다.(참고)

function ReactLink(value, requestChange) {
this.value = value;
this.requestChange = requestChange;
}
여기에서, valueLink의 Prop을 살펴보면 requestChange에 전달하는 인자는 e.target.value라는 사실을 알 수 있습니다.(참고)

function _handleLinkedValueChange(e) {
/*jshint validthis:true */
this.props.valueLink.requestChange(e.target.value);
}

/**
* @param {SyntheticEvent} e change event to handle
*/
function _handleLinkedCheckChange(e) {
/*jshint validthis:true */
this.props.checkedLink.requestChange(e.target.checked);
}
input의 컴포넌트를 보면, onChange 이벤트에 valueLink가 있으면 _handleLinkedValueChange를 호출하여 그 결과, setState 한다는 것을 알 수 있습니다.(참고1, 참고2)

getOnChange: function(input) {
if (input.props.valueLink) {
_assertValueLink(input);
return _handleLinkedValueChange;
} else if (input.props.checkedLink) {
_assertCheckedLink(input);
return _handleLinkedCheckChange;
}
return input.props.onChange;
}
_handleChange: function(event) {
var returnValue;
var onChange = LinkedValueUtils.getOnChange(this);
if (onChange) {
returnValue = onChange.call(this, event);
}
여기까지 폼을 다루는 방법을 소개했습니다. 마지막에 간단한 Mixin을 살펴봄으로써 Mixin이 동작하는 방식도 알 수 있을 것이라 생각합니다. 다음 절에서는 React.js의 VIRTUAL DOM 구현에서 중요한 역할을 맡고 있는 key 속성을 소개하겠습니다.

React.js에서 중요한 key
이번 절에서는 React.js의 Virtual DOM 구현의 내에서도 유저가 인지할 수 있는 Key를 소개하겠습니다. React.js에서는 Prop에 key라는 값을 지정할 수 있고 컴포넌트의 리스트를 렌더링할 때 이를 지정하지 않으면 Development 환경에서 아래와 같은 경고가 출력됩니다.

Each child in an array should have a unique “key” prop. Check the render method of KeyTrap. See http://fb.me/react-warning-keys for more information.
이 key는 VIRTUAL DOM과 비교하여 실제 DOM에 반영할 때 최소한으로 변경하기 위해 사용됩니다. key를 사용하는 예는 다음과 같습니다.(참고)

var KeySample = React.createClass({
getInitialState() {
return {
list: [1,2,3,4,5]
};
},
add() {
this.setState({ list: [0].concat(this.state.list) });
},
render() {
var list = this.state.list.map(function(i) { return <li key={i}>{i}</li> });
return (
<div>
<ul>{list}</ul>
<button onClick={this.add}>add</button>
</div>
);
}
});
위와 같은 원소로 유니크한 ID가 지정돼 있는 배열을 리스트로 출력하는 컴포넌트가 있다고 했을때, 새로 추가 시 배열의 앞에 0을 추가하면 DOM에도 실제로 변경이 필요한 부분만 반영됩니다. 만약 key를 사용하지 않으면 이런 비교가 불가능하여 전체 리스트를 갱신하게 됩니다. 이 예제에는 문제가 있는데 한번 추가한 후 다시 추가하면 0이라는 key를 가진 배열이 계속 추가되므로 실제로 변경된 사항이 없다 판단하여 DOM은 바뀌지 않습니다. 이러 형태의 문제가 발생했을때는 아래와 같은 경고가 출력됩니다.

Warning: flattenChildren(…): Encountered two children with the same key, .$0. Child keys must be unique; when two children share a key, only the first child will be used.
key를 제거하고 예제를 실행하면 같은 값을 가지는 엘리먼트가 계속 추가됩니다. 이와 비슷한 아이디어는 Angular.js의 track by와 Vue.js의 trackby 등 다른 라이브러리나 프레임워크에서도 만날 수 있습니다.

key must by unique
위 경고로 알 수 있듯이 key는 해당 리스트에서 반드시 유니크한 값으로 지정할 필요가 있습니다. 예를 들어 사용자 목록을 출력한다면 사용자의 ID가 key로 사용될 수 있습니다. 배열의 index를 key로 지정하는 것은 사실 큰 의미가 없습니다.

ReactCSSTransitionGroup
React.js에는 CSS 애니메이션을 위한 addon이 있습니다. 이는 애니메이션 대상이 되는 요소가 1개인 경우에도 key를 지정해야합니다. 이는 ReactCSSTransitionGroup에서 요소의 추가, 삭제를 추적해야 하기 때문에 key를 필요로 하는 것 같습니다.(실제 구현을 살펴보진 않았습니다.) ReactCSSTransitionGroup에 관해서는 추후 다시 소개하겠습니다.

추가 내용
마지막으로 React.js and Dynamic Children – Why the Keys are Important을 참고해 key에 관해 생략된 부분을 소개하겠습니다.

<CountriesComponent>
<TabList /> {/* 나라 리스트 */}
<TabList /> {/* 위 나라에 해당하는 도시 리스트 */}
</CountriesComponent>
위와같은 컴포넌트를 구성하고 있고 TabList는 각각 활성화된 탭의 index를 State로 가지고 있다고 합시다. 그리고 국가 목록을 변경했을 때 도시 목록의 활성화된 index도 0으로 되돌리고 싶지만 의도한대로 동작하지 않습니다. getInitialState()에 활성화 index가 0으로 초기화 되도록 작성돼 있습니다. 따라서 나라가 변경됐을 때 도시 목록의 TabList는 나라에 대응한 도시의 리스트로 갱신되면서 초기화 될 것으로 보이지만 실제로 TabList를 재사용하므로 목록만 갱신됩니다. 즉, getInitialState()가 호출되지 않아 활성화 index가 갱신되지 않아 발생하는 문제입니다.

이 문제는 TabList에 key를 지정하고 국가가 달라졌을 때 도시 컴포넌트가 다시 생성되도록 하는 방식으로 해결할 수 있습니다.즉, key를 명시함으로써 새로운 컴포넌트를 만들도록 할 수 있습니다.

<CountriesComponent>
<TabList key=”countriesList” />
<TabList key={this.state.currentCountry} />
</CountriesComponent>
위 블로그에도 언급돼 있지만 이런 경우엔 TabList 컴포넌트에서 활성화 index를 State로 관리하는게 아니라 ContriesComponent가 관리하고 Prop으로 활성화 index를 TabList 컴포넌트에 전달하는게 더 맞는 방법인 것 같습니다.

정리
여기까지 React.js 컴포넌트의 Lifecycle과 이벤트 그리고 폼과 Key를 소개했습니다. 다음 편에서는 VIRTUAL DOM의 장점과 믹스-인 등을 소개하겠습니다.

React.js를 이해하다(2)
react.js

React.js를 이해하다(2)

블로그 사이트 바로가기

읽기전에…
이 문서는 koba04님이 작성한 React.js Advent Calendar를 번역한 것입니다. 본래 원문서는 캘린더 형식으로 소개하지만 여기에서는 회를 나눠 작성할 생각입니다. 또한, React 버전 0.12.1 때 작성된 문서이기 때문에 현 버전과 다른 점이 있을 수 있습니다. 최대한 다른 부분을 노트로 작성할 생각이지만, 만약 생략된 부분이 있다면 댓글로 알려주시면 감사하겠습니다.

전편에서 잠깐 등장한 Props을 소개하겠습니다.

React.js의 Prop
기본 사용법
Prop은 컴포넌트의 속성(어트리뷰트)으로 정의하고 컴포넌트 내에서는 this.props.xxx로 참조해 사용합니다. 이것이 전부입니다. Prop으로는 객체, 함수 등 어떤 타입이든 지정할 수 있습니다.

var Avatar = React.createClass({
render() {
var avatarImg = `/img/avatar_${this.props.user.id}.png`;

return(
<div>
<span>{this.props.user.name}</span>
<img src={avatarImg} />
</div>
);
};
});

var user = {
id: 10,
name: ‘Hoge’
};

// <Avatar user={user} />
I/F(인터페이스)로써의 Prop
Prop은 외부에서 전달하는 값이지 그 컴포넌트가 자체적으로 관리하는 값이 아니므로 내부에서 변경하면 안 됩니다. 컴포넌트가 관리할 필요가 있는 값은 다음 절에서 소개할 State로 정의해야 합니다. 즉, Prop은 Immutable(불변) 하며 외부와 I/F로써 작용합니다.

PropTypes
컴포넌트의 Prop은 외부로부터 값을 지정받기 때문에 검증(벨리데이션)이 필요합니다. 이때 React.js에서는 PropsTypes으로 Prop에 대한 타입 제약을 지정할 수 있습니다. 화려하진 않지만 좋은 기능입니다.

var Avatar = React.createClass({
propTypes: {
name: React.PropTypes.string.isRequired,
id: React.PropTypes.number.isRequired,
width: React.PropTypes.number.isRequired,
height: React.PropTypes.number.isRequired,
alt: React.PropTypes.string
},
render() {
var src = `/img/avatar/${this.props.id}.png`;
return (
<div>
<img src={src} width={this.props.width} height={this.props.height} alt={this.props.alt} />
<span>{this.props.name}</span>
</div>
);
}
});

<Avatar name=”foo” id=1 width=100 height=100 />
위와 같은 느낌으로 작성합니다. PropTypes을 지정하는 것으로 컴포넌트의 I/F를 조금 더 명확하게 표현할 수 있습니다. PropTypes의 지정은 아래와 같은 느낌으로 유연하게 지정할 수 있습니다.

React.PropTypes.array // 배열
React.PropTypes.bool.isRequired // Boolean, 필수
React.PropTypes.func // 함수
React.PropTypes.number // 정수
React.PropTypes.object // 객체
React.PropTypes.string // 문자열
React.PropTypes.node // Render가 가능한 객체
React.PropTypes.element // React Element
React.PropTypes.instanceOf(XXX) // XXX의 instance
React.PropTypes.oneOf([‘foo’, ‘bar’]) // foo 또는 bar
React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.array]) // 문자열 또는 배열
React.PropTypes.arrayOf(React.PropTypes.string) // 문자열을 원소로 가지는 배열
React.PropTypes.objectOf(React.PropTypes.string) // 문자열을 값으로 가지는 객체
React.PropTypes.shape({ // 지정된 형식을 충족하는지
color: React.PropTypes.string,
fontSize: React.PropTypes.number
});
React.PropTypes.any.isRequired // 어떤 타입이든 가능하지만 필수

// 커스텀 제약도 정의 가능
customPropType: function(props, propName, componentName) {
if (!/^[0-9]/.test(props[propName])) {
return new Error(‘Validation failed!’);
}
}
아래와 같이 제일 처음 소개한 예제 코드에 PropTypes를 정의할 수 있습니다.

var Avatar = React.createClass({
propTypes: {
user: React.PropTypes.shape({
id: React.PropTypes.number.isRequired,
name: React.PropTypes.string.isRequired
})
},
render() {
var avatarImg = `/img/avatar_${this.props.user.id}.png`;
return(
<div>
<span>{this.props.user.name}</span>
<img src={avatarImg} />
</div>
);
}
});
주의점으로는 React.js의 제약은 성능적인 이유로 실 서비스 환경에서는 검증하지 않습니다. 또 개발 환경에서도 에러가 발생하는 것이 아닌 console.warn으로 출력됩니다. 에러가 발생하도록 변경해 달라는 issue도 등록됐었기 때문에 앞으로 어떻게 변경될진 모르겠습니다.

역자노트
ES6에서 PropTypes을 지정하는 방식은 다음과 같습니다.

class Avatar extends React.Component {
render() {
var avatarImg = `/img/avatar_${this.props.user.id}.png`;

return(
<div>
<span>{this.props.user.name}</span>
<img src={avatarImg} />
</div>
);
}
}

Avatar.propTypes = {
user: React.PropTypes.shape({
id: React.PropTypes.number.isRequired,
name: React.PropTypes.string.isRequired
})
};

export default Avatar;
기본값 지정
getDefaultProps()에서 리터럴 객체를 반환하면 기본값으로 지정됩니다. 이는 컴포넌트 인스턴스가 만들어질 때 호출되는 것이 아니라 컴포넌트가 정의될 때만 호출되므로 주의가 필요합니다. 다음 절에서 소개할 getInitialState()은 다릅니다.

var Hello = React.createClass({
getDefaultProps() {
return {
name: ‘React’
};
},
render() {
return <div>Hello {this.props.name}</div>
}
});

// <Hello />
역자노트
ES6에서 PropTypes을 지정하는 방식은 다음과 같습니다.

class Hello extends React.Component {
render() {
return <div>Hello {this.props.name}</div>
}
}

Hello.defaultProps = {
name: ‘React’
};

export default Hello;

// <Hello />
setProps & replaceProps
컴포넌트에 새로운 Prop을 전달하고 다시 rerender 하고 싶은 경우엔 setProps()와 replaceProps()를 사용합니다. 이 메서드를 이용하면 Prop을 갱신하면서 rerender 할 수 있습니다.

var Test = React.createClass({
getDefaultProps: function() {
return {
id: 1
};
},
render: function() {
return (
<div>{this.props.id}:{this.props.name}</div>
);
}
});

var component = React.render(<Test name=”bar” />, document.body);

component.setProps({ name: “foo” }); // <div>1:foo</div>
component.replaceProps({ name: “hoge” }); // <div>:hoge</div>
setProps()은 기존의 Prop과 새로운 Prop을 합치(merge)지만 replaceProps()는 대체합니다. 그리고 각각 두 번째 인수에 콜백 함수를 지정할 수 있습니다.

역자노트
replaceProps()는 ES6에서 사용할 수 없으며, 곧 제거될 예정입니다.

여기까지 React.js의 Prop을 살펴봤습니다. 다음 절에서는 State를 소개하겠습니다.

React.js의 State
Porp은 Immutable하지만 State는 Mutable(이변)한 값을 정의할 수 있습니다.

기본 사용법
getInitialState()을 이용해 state의 초기값을 반환하고 데이터 변경이 있는 경우 this.setState()로 갱신합니다. 상태가 갱신되면 컴포넌트가 rerender 되어 UI가 갱신됩니다. 이때, 자식 컴포넌트도 함께 rerender 됩니다.

var Counter = React.createClass({
getInitialState() {
return {
count: 0
};
},
onClick() {
this.setState({ count: this.state.count + 1});
},
render() {
return (
<div>
<span>{this.state.count}</span>
<button onClick={this.onClick}>click</button>
</div>
);
}
});
setState()의 두 번째에 인수에는 setProps() 처럼 콜백 함수를 지정할 수 있습니다. 또 replaceProps()와 비슷한 replaceState()도 있습니다.

역자노트
replaceState()는 ES6에서 사용할 수 없으며, 곧 제거될 예정입니다.

State를 사용한 UI
State는 텍스트 필드 같은 컴포넌트 내에서 사용자 인터렉션에 따라 변경되는 값을 관리하는 경우에 가장 자주 사용됩니다. 또 컴포넌트 내에서 Ajax로 데이터를 요청하고 성공 시 콜백 함수에서 응답 데이터를 setState() 하는 방식으로도 사용합니다.

주의할 점
state의 값을 프로퍼티로 접근해 직접 변경하면 안 되고 반드시 setState()를 사용해 갱신해야 합니다. 이는 setState()가 호출되어야 rerender 되기 때문입니다. this.state 값 자체도 Immutable 하다라고 생각하는 것이 좋습니다. 만약, this.state.list라는 배열이 있고 list에 요소를 추가하고 싶은 경우도 push()하고 setState()하는 것이 아니라 this.setState({list: this.state.list.concat([value]})로 새로운 값(배열)을 지정하는 것이 좋습니다. 이 방법이 shouldComponentUpdate()로 성능 최적화 할 때와 undo의 구현 시에 좀 더 유용합니다.

State는 최소화
Prop만 가지고 있는 Immutable한 컴포넌트가 조작하거나 이해하기 쉬우므로, 기본적으로는 Prop을 고려하고, State를 가진 컴포넌트는 최소화 하는 게 좋습니다. 최상위 컴포넌트만 State를 갖게 하고, 하위 컴포넌트는 전부 Prop만을 가지는 Immutable한 컴포넌트로 구성하여 어떤 변경이 있을 때 최상위 컴포넌트에서 setState()하여 rerender 하는 설계도 가능합니다. 이는 VirtualDOM의 기술을 이용한 설계 방법입니다. 이와 관련된 내용은 다음에 소개하겠습니다.

여기까지 State를 소개했습니다. 다음으로 Prop과 State를 사용한 컴포넌트 간의 상호작용을 소개하겠습니다.

Prop과 State를 사용한 컴포넌트 상호작용
이번에는 지금까지 소개한 Prop과 State를 사용해 컴포넌트 간 상호작용 하는 방법에 대해서 작성하겠습니다.

부모의 State를 자식의 Prop으로 전달
컴포넌트 설계 시 인터페이스를 고려해서 Prop을 설계하고 그 컴포넌트가 관리할 값 중 변경되는 값을 추려 State로 정의합니다. 컴포넌트 간의 부모와 자식 관계를 의식해서 설계해야 합니다. 부모는 State를 갖고 있고, 자식의 Prop으로 값을 전달하는 것이 기본 흐름입니다. 자식은 값을 사용하기만 할 뿐 관리는 부모가 합니다.

var User = React.createClass({
propTypes: {
name: React.PropTypes.string.isRequired,
id: React.PropTypes.number.isRequired
},
render() {
return (
<div>{this.props.id}:{this.props.name}</div>
);
}
});

var request = require(‘superagent’);

var Users = React.createClass({
getInitialState() {
return {
users: [{id: 1, name: ‘foo’}, {id: 2, name: ‘bar’}]
}
},
componentDidMount() {
request.get(‘http://example.com/users/’, (res) => {
this.setState({users: res.body.users});
});
},
render() {
var users = this.state.users.map((user) => {
return <User id={user.id} name={user.name} key={user.id}/>
});
return (
<div>
<p>사용자 목록</p>
{users}
</div>
);
}
});
자식의 이벤트를 부모에서 처리
자식 컴포넌트 내에서 발생하는 이벤트를 부모에서 처리하고 싶은 경우엔 자식이 이벤트를 처리하기 위한 함수를 Prop 즉, I/F로 공개하고 부모가 자식의 Prop을 이용해 리스너를 전달하는 형태로 처리합니다. 예를 들어 TodoList에서 각 Todo는 자식 컴포넌트가 되고 자식 컴포넌트에 삭제나 편집 기능이 있을 때 삭제와 편집 처리 로직은 부모 컴포넌트에 정의하고 이벤트는 자식 컴포넌트에서 버블링되는 느낌으로 동작합니다.

var Todo = React.createClass({
propTypes: {
todo: React.PropTypes.shape({
id: React.PropTypes.number.isRequired,
text: React.PropTypes.string.isRequired
}),
// 삭제 처리를 I/F로 정의
onDelete: React.PropTypes.func.isRequired
},
// 부모에게 이벤트 처리를 위임한다.
_onDelete() {
this.props.onDelete(this.props.todo.id);
},
render() {
return (
<div>
<span>{this.props.todo.text}</span>
<button onClick={this._onDelete}>delete</button>
</div>
);
}
});

var TodoList = React.createClass({
getInitialState() {
return {
todos: [
{id:1, text: ‘advent calendar1’},
{id:2, text: ‘advent calendar2’},
{id:3, text: ‘advent calendar3’}
]
};
},
// TodoList는 이 컴포넌트가 관리하고 있으므로 삭제 처리도 여기에 존재한다.
deleteTodo(id) {
this.setState({
todos: this.state.todos.filter((todo) => {
return todo.id !== id;
})
});
},
render() {
var todos = this.state.todos.map((todo) => {
return <li key={todo.id}><Todo onDelete={this.deleteTodo} todo={todo} /></li>;
});
return <ul>{todos}</ul>;
}
});

React.render(<TodoList />, document.body);
State 초기값을 Prop에서 전달
State의 초기값을 Prop에서 전달해야 하는 경우엔 아래와 같이 처리합니다.

var Counter = React.createClass({
propTypes: {
count: React.PropTypes.number
},
getDefaultProps() {
return {
count: 0
};
},
getInitialState() {
return {
count: this.props.count
}
},
onClick() {
this.setState({ count: this.state.count + 1 });
},
render() {
return (
<div>
<p>{this.state.count}</p>
<button onClick={this.onClick}>click</button>
</div>
);
}
});

// <Counter count=10 />
하지만 위와 같은 형태로 작성하면 값이 증가할 때마다 Prop의 count도 함께 증가할 것으로 보이기 때문에 Prop을 초기값으로 사용할 때는 의도를 명확하게 드러내는 이름으로 작성합니다.

var Counter = React.createClass({
propTypes: {
initialCount: React.PropTypes.number
},
getDefaultProps() {
return {
initialCount: 0
};
},
getInitialState() {
return {
count: this.props.initialCount
}
},
onClick() {
this.setState({ count: this.state.count + 1 });
},
render() {
return (
<div>
<p>{this.state.count}</p>
<button onClick={this.onClick}>click</button>
</div>
);
}
:
});

// <Counter initialCount=10 />
ref
컴포넌트 내에서 ref 프로퍼티를 사용하여 자식 컴포넌트를 참조할 수 있습니다. 이 프로퍼티를 사용하면 부모에서 자식의 메서드를 호출할 수 있습니다. 하지만 한번 사용하기 시작하면 컴포넌트 간의 관계를 알기 어려워지므로 기본적으로 div나 button 등과 같은 내장 컴포넌트를 참조할 때만 사용하는 게 좋습니다. 보통 다음 절에서 설명할 getDOMNode()와 함께 사용하는 경우가 많습니다.

var Test = React.createClass({
componentDidMount() {
console.log(this.refs.myDiv.props.children); // xxx
},
render() {
return (
<div ref=”myDiv”>xxx</div>
);
}
});
getDOMNode
React.js에서 DOM은 VirtualDOM에 감춰져 있어서 직접 DOM을 조작하지 않습니다. 하지만 focus 하거나, jQuery Plugin을 쓰고자 할 때는 직접 DOM을 조작해야 하는 경우도 있습니다. 그런 경우에는 ref와 함께 getDOMNode()를 사용하여 DOM을 참조합니다. 다만, DOM을 직접 수정하게 되면 VirtualDOM과의 관계가 틀어지기 때문에 읽기 전용으로 사용해야 합니다.

var Focus = React.createClass({
componentDidMount() {
this.refs.myText.getDOMNode().focus();
},
render() {
return (
<div>
<p>set focus</p>
<input type=”text” ref=”myText” />
</div>
);
}
});
역자노트
getDOMNode()는 deprecated 됩니다(참고). 대신 다음과 같이 사용하세요.

componentDidMount() {
React.findDOMNode(this.refs.myText).focus();
}
Props.children
<myComponent>xxx</myComponent>와 같이 작성할 때 xxx를 얻고자 할때는 this.props.children 프로퍼티를 사용합니다.

var Hello = React.createClass({
render() {
return <div>{this.props.children}</div>;
}
});

console.log(
React.render(
<Hello>xxx</Hello>,
document.body
).props.children
);
// => xxx

console.log(
React.render(
<Hello><span>1</span><span>2</span></Hello>,
document.body
).props.children
);
// => [React.Element, React.Element]

console.log(
React.render(
<Hello></Hello>,
document.body
).props.children
);
// undefined
위와 같이 props.children은 지정 방식에 따라 문자열이거나 원소가 React Element로 이뤄진 배열이거나 undefined 일 수도 있습니다. 그래서 배열이라는 가정에 따라 원소의 개수를 확인하기 위해 children.length 한 경우 만약 문자열이 전달되면 String.length의 값이 반환되므로 chdilren을 사용할 때는 어떤 타입인지 검사할 필요가 있습니다. React.Children에는 count, forEach, map, only 등 편리한 함수를 제공하고 있습니다. 이 메서드를 잘 사용하면 자식을 조작할 때 발생하는 문제를 잘 회피할 수 있습니다.

var Hello = React.createClass({
render() {
return <div>{this.props.children}</div>;
}
});

[
<Hello>xxx</Hello>,
<Hello><span>1</span><span>2</span></Hello>,
<Hello></Hello>
].forEach( jsx => {
var children = React.render(jsx, document.body).props.children;
console.log(######### + children + ##########);
console.log(React.Children.count(children));
React.Children.forEach(children, (child) => { console.log(child) });
});

// #########xxx##########
// 1
// xxx
// #########[object Object],[object Object]##########
// 2
// ReactElement {type: “span”, key: null, ref: null, _owner: null, _context: Object…}
// ReactElement {type: “span”, key: null, ref: null, _owner: null, _context: Object…}
// #########undefined##########
위 예제를 보면 알 수 있듯이 React.Children의 메서드를 사용하여 배열과 문자열의 문제를 해결하고 있습니다. 참고로 React.Children.only는 children의 React.element가 하나 이상일 때 오류를 발생시키는 함수입니다.

정리
여기까지 Prop과 State를 알아보고 그 속성을 사용해 컴포넌트에서 상호작용하는 방법도 알아봤습니다. prop과 state는 컴포넌트에서 데이터와 상태를 관리하는 데 중요한 속성이므로 꼭 기억해두시길 바랍니다. 다음편에서는 React 컴포넌트 작성 시 유용하게 사용할 수 있는 Lifecycle와 이벤트 등을 소개하겠습니다.

React.js를 이해하다(1)
react.js

React.js를 이해하다(1)

블로그 사이트 바로가기

읽기전에…
이 문서는 koba04님이 작성한 React.js Advent Calendar를 번역한 것입니다. 본래 원문서는 캘린더 형식으로 소개하지만 여기에서는 회를 나눠 작성할 생각입니다. 또한, React 버전 0.12.1 때 작성된 문서이기 때문에 현 버전과 다른 점이 있을 수 있습니다. 최대한 다른 부분을 노트로 작성할 생각이지만, 만약 생략된 부분이 있다면 댓글로 알려주시면 감사하겠습니다.

올해(2014년) 들어 갑자기 대세가 된 듯한 React.js 지만, “조금 전까지만 해도 Angular.js가 대세라고 하더니!”라며 혼란스러워하는 사람도 많을 거라 생각해서 Advent Calendar 형식으로 간단히 소개하고자 합니다. React.js에서 중요한 개념인 VIRTUAL DOM(가상돔) 별도의 Adevent Calendar에 작성돼 있으니 꼭 봐주시길 바랍니다.

React.js 란?
왜 이 라이브러리가 뜨거운 감자가 됐는지는 솔직히 잘 모르겠지만, 필자는 개인적으로는 Github의 atom에서 성능 향상의 이유로 React.js를 사용하기로 했다는 기사(Moving Atom To React)를 보고 흥미를 갖게 됐습니다. React.js는 Facebook이 만들고 있는 이른바 MVC 프레임워크에서의 뷰 부분을 컴포넌트로 만들기 위한 라이브러리입니다. Handlebars 같은 템플릿 엔진이 아닙니다. Facebook은 물론 instagram, AirBnb, Yahoo, Atlassian 등 여러 곳에서 사용하고 있습니다.

특징
공식 사이트에서는 특징을 크게 세 가지로 나눠 소개하고 있습니다.

JUST THE UI
VIRTUAL DOM
DATA FLOW
이 세 가지 특징에 관해서 간단히 설명해 드리겠습니다.

JUST THE UI
React.js는 UI 컴포넌트를 만들기 위한 라이브러리입니다. 컴포넌트 지향 프레임워크는 여러 가지가 있지만 React.js는 정말 UI 컴포넌트만 지원합니다. 비록 지원하는 범위는 작지만, 애플리케이션을 만드는 방법을 크게 바꿀 수 있다는 점이 재미있습니다. 또한, 이해 비용이 적어 도입하기 쉬우며 Backbone.js의 뷰 부분을 React.js로 구현하거나 Angular.js의 directives를 React.js를 사용해 구현하는 등 여러 환경과 조합해 사용할 수 있습니다.

VIRTUAL DOM
React.js는 자바스크립트 내에 DOM Tree와 같은 구조체를 VIRTUAL DOM으로 갖고 있습니다. 다시 그릴 때는 그 구조체의 전후 상태를 비교하여 변경이 필요한 최소한의 요소만 실제 DOM에 반영합니다. 따라서 무작위로 다시 그려도 변경에 필요한 최소한의 DOM만 갱신되기 때문에 빠르게 처리할 수 있습니다.

DATA FLOW
React.js는 단방향 데이터 흐름을 지향합니다. 따라서 Angular.js의 양방향 데이터 바인딩을 사용할 때처럼 작성할 코드의 양이 확연히 줄거나 하지는 않습니다. 그렇지만, 애플리케이션의 데이터를 관리하는 모델 컴포넌트가 있고 그 데이터를 UI 컴포넌트에 전달하는 단순한 데이터 흐름으로 이해하고 관리하기 쉬운 애플리케이션을 만들 수 있습니다.

역자노트
과거엔 데이터가 변경되면 전체를 새로 그리는 간편하고 단순한 방법으로 애플리케이션을 구현했습니다. 현대에 들어 애플리케이션을 개발하는 방법이 많이 복잡해졌다고 생각합니다. Angular.js의 양방향 데이터 바인딩은 코드를 줄여주고 사용하기 편하지만, 규모가 커질수록 데이터의 흐름을 추적하기 힘듭니다. React.js는 근원(根源)으로 돌아가는 개발 방법입니다. 그리고 그 과정에서 발생하는 비효율적인 부분, 예를 들어 DOM 전체를 갱신해야하는 문제를 VIRTUAL DOM과 비교(diff)로 해결했습니다.

기타
JSX
추가로 두 가지 더 설명하겠습니다. 첫 번째로 JSX입니다. React.js에서는 JSX라고 하는 XML과 비슷한 문법을 이용할 수 있습니다. 이는 선택적으로 사용할 수 있는 문법이므로 JSX가 마음에 들지 않는다면 자바스크립트로 작성할 수도 있습니다. JSX는 다음에 자세히 소개하겠습니다.

역자노트
JSX는 페이스북에서 스펙을 정의한 ECMAScript 친화적인 XML 스러운 문법입니다. React.js에서는 이 문법을 VIRTUAL DOM(또는 컴포넌트의 계층)을 선언적(또는 명시적)으로 서술하여 표현하기 위해 사용됐습니다. 선택적으로 사용할 수 있다고는 하나 JSX가 React.js를 사용하는 이유 중 하나이기 때문에 사용하지 않는 건 개인적으로 추천하지 않습니다.

Flux
React.js에 조금 관심이 있는 분은 React.js와 Flux를 세트로 구성하는 방법에 관해 들은 적 있을 겁니다. 이것은 MVC와 같은 아키텍처를 구성하는 이야기이며 단지 Flux의 구성 요소로서 React.js를 사용하는 방법일 뿐 React.js에 포함된 것은 아닙니다. 이와 관련한 내용도 다음에 자세히 소개하겠습니다.

다음 절에서는 Hello World를 컴포넌트로 만드는 간단한 예제와 함께 React.js를 사용하는 방법을 소개하겠습니다. 예제 코드를 작성할 때는 아래 공식 jsfiddle 링크를 사용하면 더욱 쉽게 테스트할 수 있으니 참고하시길 바랍니다.

React JSFiddle
React JSFiddle without JSX
Hello React.js
이번 절에서는 Hello World를 컴포넌트로 만들어보겠습니다. 기본적으로 React.createClass로 컴포넌트를 만듭니다. 그리고 그 컴포넌트들을 조합해 페이지를 만들고 React.render를 이용해 DOM과 짝을 맞춰 출력합니다.

JSX 사용
JSX에 관해서는 다음 절에서 조금 더 자세히 소개할 예정입니다. 보통 아래와 같은 느낌으로 자바스크립트 내에 XML과 비슷한 마크업을 직접 사용할 수 있습니다.

var React = require(‘react’);

var Hello = React.createClass({
render: function() {
return (
<div className=”container”>Hello {this.props.name}</div>
);
}
});

React.render(<Hello name=”React” />, document.getElementById(“app”));
위 코드를 브라우저에서 실행하면 당연히 에러가 발생합니다. 따라서 react-tools를 사용하여 사전에 컴파일하거나 JSXTransformer를 불러와야 합니다. 또한, browserify와 reactify를 조합해 사용하는 변환 방법도 있습니다. 참고로 말씀드리면 div(division)은 흔히 우리가 생각하는 HTML 태그가 아니라 React의 컴포넌트입니다.

역자노트
JSX에서 보이는 div, a 등과 같은 HTML 태그는 사실 HTML 태그가 아니라 모두 React.js의 컴포넌트입니다. 기본 HTML 태그를 React.js에서 미리 컴포넌트로 작성해 제공할 뿐입니다. JSX로 작성되는 모든 요소는 React.js 컴포넌트로 보시면 됩니다.

JSX + ES6, 7의 문법(일부)
JSX의 transform에는 harmoney 옵션이 있습니다. 이 옵션을 켜면 ES6, 7의 문법을 일부 사용할 수 있습니다. ES6의 문법인 Arrow function은 map, filter 등과 조합해 사용하면 정말 편리합니다.

var items = this.props.items.map((item) => {
return <div>{item.name}</div>;
});
역자노트
위에서 언급된 react-tools와 JSXTransformer는 곧 Babel로 옮겨집니다(참고). 자바스크립트 발전 속도에 대응하기 힘들었던 거로 보입니다. 반면, Babel은 잘 대응하고 있고 또 많은 개발자가 기본적으로 채택하는 빌드 도구이기 때문에 결정한 것 같습니다. 따라서 이를 사용하기보단 Babel과 함께 프로젝트를 구성하길 바랍니다.

without JSX
JSX 없이 코드를 작성하면 아래와 같습니다. Hello 컴포넌트의 render 메서드 이외에도 React.render에 Hello 컴포넌트를 전달하는 방식도 바뀌었습니다.

var React = require(‘react’);

var Hello = React.createClass({
render: function() {
return React.DOM.div({className: ‘container’, ‘Hello ‘ + this.props.name);
}
})

React.render(
React.createFactory(Hello)({name: ‘React’}), document.getElementById(“app”)
);
이 Advent Calendar에서 소개하는 코드는 JSX에서 harmony 옵션을 켠 상태에서 작성했음을 알려드립니다. 그럼, 다음 절에서 JSX에 관해 조금 더 넓게 설명하도록 하겠습니다.

React.js의 JSX
위 Hello React.js 절에서 JSX를 잠깐 소개했습니다. 이번에는 조금 더 넓게 살펴보도록 하겠습니다.

JSX
var Hello = React.createClass({
render: function() {
return (
<div>Hello {this.props.name}</div>
);
}
});
위 코드에서 한눈에 HTML로 보이는 부분 <div>…</div>이 JSX 문법입니다. XML과 비슷한 형태로 태그를 작성해 나가면 됩니다. 따로 학습하고 기억해야 할 내용은 거의 없습니다. 이 문법에 관한 자세한 설명은 JSX Specification에 작성돼 있습니다. 하나 주의해야 할 점으로는 JSX는 HTML이 아니므로 div에 container라는 클래스를 지정하고 싶은 경우, <div class=”container”>…</div>가 아니라 <div className=”container”>…</div>로 작성해야 한다는 것입니다. 자바스크립트의 예약어 문제를 회피하기 위해서 이런 문법으로 디자인됐습니다. 추가로 label의 for 속성은 htmlFor로 작성해야 합니다. 이와 관련한 내용은 Tags and Attributes에 정리돼 있습니다. HTML은 태그가 제대로 닫히지 않아도 에러가 발생하지 않지만 JSX는 태그를 닫지 않은 경우 에러가 발생하므로 문법 문제를 쉽게 알아차릴 수 있습니다.

사용법
Realtime로 변환
JSX Transformer를 불러오면 JSX 문법을 실시간으로 변환할 수 있습니다. 다만, 이 방법을 제품(서비스) 환경에서 사용하는 것은 성능면에서 좋지 않아 권장하지 않습니다. 보통 개발 및 디버깅의 편의를 위해 사용합니다.

Precompile로 변환
npm install -g react-tools 커맨드 라인으로 react-tools를 설치하면 jsx 명령을 사용할 수 있습니다.

$ jsx src/build/
파일을 감시하는 것도 가능합니다.

$ jsx –watch src/build/
browserify나 webpack으로 변환
browserify와 reactify를 사용하여 변환할 수 있습니다.

“browserify”: {
“transform”: [
[“reactify”, {“harmony”: true} ]
]
}
node-jsx로 변환
Server-Side rerendering과 같이 ndoe.js 환경에서 변환하고 싶은 경우엔 node-jsx를 사용할 수 있습니다. require하고 install 하는 것으로 간단히 변환할 수 있습니다.

역자노트
Browserify와 babelify(babel)를 조합하면 ES6는 물론 React.js의 JSX 문법을 사용할 수 있습니다. ECMAScript 6 compatibility table의 core.js + babel 항목을 보면 사용할 수 있는 ES6 문법을 확인할 수 있습니다. 여기에 Grunt를 이용해 자동화하면 조금 더 안락한 개발 환경을 구성할 수 있습니다.

JSX 사용 의미
JSX를 사용하면 HTML 문법과 비슷한 느낌으로 작성할 수 있어 비엔지니어도 이해하기 쉽다는 장점이 있습니다. 개인적인 성향 차이가 있다고는 하지만 개인적으로 React.DOM.div(null, ‘hello’) 보다 <div>hello</div>와 같은 방식이 더 좋다고 생각합니다. 또, 버전 0.12는 버전 0.11에 비해 React.createClass의 동작 방식(인터페이스)이 바뀌었지만(이것에 관한 내용은 다음 절에서 소개하겠습니다.) JSX를 사용하고 있는 경우엔 코드를 그대로 사용 가능합니다. 즉, JSX에 대한 지원이 조금 더 좋습니다. JSX를 사용했을 때의 이 점은 이 정도로 생각하고 있으므로 자바스크립트로 작성하고 싶은 사람은 굳이 JSX를 사용하지 않아도 괜찮을 것 같습니다. JSX 이외로 커피스크립트 환경을 고려해 만들어진 react-kup도 있습니다.

변환 코드 확인
특정 코드를 변환한 결과를 확인하고 싶은 경우엔 아래 문서를 참고하세요.

JSX Compiler Service
HTML to JSX
ES6, 7
harmony 옵션을 켜면 JSX의 변환할 시 Class나 Arrow Function 등 ES6, 7의 기능 일부를 사용할 수 있습니다. 개인적으로 아래와 같이 ES6, 7 문법으로 작성하는 것을 좋아해 옵션을 켜두고 사용하고 있습니다.

var Items = React.createClass({
itemName(item) {
return `${item.name}:${item.count}`;
},
render() {
var items = this.props.items.map(item => <span>{this.itemName(item)}</span>);

return (
<div>{items}</div>
);
}
});
아래와 같은 기능들을 사용할 수 있습니다.(참고)

es6-arrow-functions
es6-object-concise-method
es6-object-short-notation
es6-classes
es6-rest-params
es6-templates
es6-destructuring
es7-spread-
React.js를 처음 접하면 JSX라는 불가사의한 언어를 사용할 필요가 있어서 꺼리는 사람도 있을 것 같습니다만 컴포넌트를 알기 쉽게 정의하기 위한 문법이므로 조금 더 가볍게 생각했으면 좋겠습니다. 다음 절에서는 컴포넌트에 관해 조금 더 설명하겠습니다.

React.js의 컴포넌트
이번에는 컴포넌트를 소개하겠습니다. React.js에서는 기본적으로 컴포넌트를 만들고 조합하여 애플리케이션을 만듭니다.

render
컴포넌트는 React.createClass()에 render 메서드를 가진 리터럴 객체를 전달해 작성할 수 있습니다.

var Hello = React.createClass({
render() {
return (
<div><span>hello</span></div>
)
}
});
그러면서 render()는 컴포넌트를 하나만 반환해야 합니다. 아래 처럼 복수의 컴포넌트를 반환할 수 없습니다.

// NO
render() {
return (
<div>title</div>
<div>contents</div>
);
}

// OK
render() {
return (
<div>
<div>title</div>
<div>contents</div>
</div>
);
}
또, render()는 어떤 타이밍에 몇번 호출될지 모르기 때문에 반드시 멱등성을 지키는 방법으로 구현해야합니다.

Separation of concerns?
React.js는 컴포넌트로써 마크업과 뷰의 로직을 createClass()의 안에 작성합니다. 하지만 마크업은 HTML이나 mustache로 작성하고 뷰의 로직은 자바스크립트로 나눠서 작성하는 기존의 방식을 취하지 않아 마음에 들지 않는 사람도 있을 것 같습니다. 이 사안에 대해 React.js의 개발자인 Pete Hunt는 “그것은 관심사의 분리(Separation of concerns)가 아니라 기술의 분리(Speparation of technologies)”라며 마크업과 뷰의 로직은 긴밀해야 한다고 언급했습니다. 거기에 템플릿의 문법으로 불필요하게 코드를 작성하는 것보다 자바스크립트로 작성하는 것이 더 좋다고 말하고 있습니다.

역자노트
HTML, CSS, 자바스크립트를 분리하는 건 관심사의 분리가 아니라 단순한 기술의 분리일 뿐, 그래서 React.js는 관심사를 컴포넌트 단위로 해석했다고 이해할 수 있습니다.

컴포넌트 간의 상호작용
Prop을 I/F로써 외부와 주고 받을 수 있습니다. <Hello name=”foo”/> 처럼 작성하면, this.props.name 으로 참조할 수 있습니다.

var Hello = React.createClass({
render() {
return (
<div>Hello {this.props.name}</div>
)
}
});

// <Hello name=”React”/>
// <div>Hello React</div>
Prop에 관해서는 다음 편에서 소개할 예정입니다.

동적으로 갱신
유저의 액션이나 Ajax 요청 등으로 값이 동적으로 변화하는 경우는 State를 사용합니다. 특정 this.state.xxx을 갱신할 때는 this.state를 사용해 갱신하는 것이 아니라 반드시 this.setState를 사용해 갱신합니다.

var Counter = React.createClass({
getInitialState() {
return {
count: 0
};
},
onClick() {
this.setState({count: this.state.count + 1});
},
render() {
return (
<div>
<div>count:{this.state.count}</div>
<button onClick={this.onClick}>click!</button>
</div>
);
}
});
State에 관한 내용은 다음 편에서 소개할 예정입니다.

React.createClass
React.createClass()는 컴포넌트를 작성할 때 사용하는 함수입니다. 이 함수는 버전 0.12에서 동작 방식이 바뀌었습니다. 0.11에서는 컴포넌트의 정의하고 컴포넌트의 엘리먼트를 반환하는 두 가지의 일을 담당했지만 0.12부터 컴포넌트를 정의하는 작업만 담당하도록 분리됐습니다. 즉, 엘리먼트가 아니므로 사용할 때는 React.createElement(Component, {name: ‘xxx’}) 처럼 React Element로 변환할 필요가 있습니다. 이 작업은 React.createFactory(Component)로 해도 같습니다. 다만, JSX를 사용하고 있는 경우는 이전과 똑같이 React.createClass의 반환 값을 <Component />로 직접 전달해도 괜찮습니다.

var Hello = React.createClass({
render() {
return <div>{this.props.name}</div>;
}
});

React.render(React.createElement(Hello, {name: “foo”}), document.body);
// or
React.render(React.createFactory(Hello)({name: “foo”}), document.body);

// JSX는 이전과 같은 방식
React.render(<Hello name=”foo” />, document.body);
이 변경은 createClass()라는 이름 외에 또 다른 일을 담당하고 있었다는 문제를 해결하기도 하지만, createElement를 통해 컴포넌트를 만들도록 함으로써 최적화할 수 있도록 하고 장기적으로 React.createClass로 작성한 문법을 ES6의 class로 대체 할 수 있도록 하려는 뜻도 있습니다.

역자노트
최근에 릴리즈된 버전 0.13에는 ES6의 class 문법을 사용해 컴포넌트를 정의할 수 있게 됐습니다. (참고) ES6 Classes 문법을 이용해 컴포넌트를 작성할 때 몇 가지 주의점이 필요합니다. 이런 사항은 천천히 소개해 드리겠습니다.

정리
여기까지 React.js의 기본적인 특징과 컴포넌트를 명시적으로 서술하기 위한 JSX 문법 등을 알아봤습니다. 컴포넌트는 이 밖에도 Lifecycle을 이용해 hook을 하는 방법도 있습니다. 그 방법에 대해서는 추후 천천히 소개하도록 하고 다음편에서는 Prop와 State 그리고 이 두 속성을 이용해 컴포넌트를 작성하는 방법을 소개하겠습니다.

JavaScriptReact

Ubuntu 14.04에 Node.js 설치 및 간단한 예제
Node.js

Ubuntu 14.04에 Node.js 설치 및 간단한 예제

Site 바로가기: Ubuntu 14.04에 Node.js 설치 및 간단한 예제

라즈베리파이나 아두이노를 Node.js로 제어하는 것을 보고는 흥미가 생겨서 좀 더 공부해보려고 설치를 하게 되었습니다.  Node.js는 자바스크립트 기반으로 서버사이드 어플리케이션을 작성할수 있게 해줍니다.

우분투 14.04에서 다음처럼 해서 Node.js 설치를 진행했습니다.

sudo apt-get install curl

curl -sL https://deb.nodesource.com/setup_4.x | sudo -E bash –

sudo apt-get install -y nodejs

설치된 버전은 다음과 같습니다.

webnautes@webnautes-PC ~ $ node –version

v4.2.3

webnautes@webnautes-PC ~ $ npm –version

2.14.7

server.js라는 이름으로 파일을 하나 작성합니다.. 3000번 포트에서 접속을 기다리는 서버를 하나 생성해서 접속이 이루어지면 Hello World를 화면에 출력할 수 있도록 문서를 전송해줍니다…

nano server.js

  1. var http = require(“http”);
  2. http.createServer(function(request, response) {
  3.   response.writeHead(200, {“Content-Type”“text/plain”});
  4.   response.write(“Hello World”);
  5.   response.end();
  6. }).listen(3000);
 
작성한 파일을 실행킨 후….
 
node server.js
이제 웹브라우저에서 태스트를 해봅니다. localhost:3000 주소로 접속을 시도해봅니다. 
Hello World라고 웹브라우저에서 보여집니다.
 

Python Features
Pathon

Python Features

Click the link to go to the original blog site: 블로그 내용보러가기

 

Python Features

파이썬 프로그래밍 언어는 많은 특징이 있습니다.

1) Easy to Use ( 쉽게 이용 )

파이썬은 사용하기 매우 쉬우며, 높은 레벨의 언어입니다.

그래서 파이썬은 프로그래머 친화적 언어라고 할 수 있습니다.

2) Expressive Language ( 표현적 언어 )

파이썬은 더 표현적입니다.  그래서 코드를 더 쉽게 이해할 수 있습니다.

3) Interpreted Language ( 인터프리티드 언어 )

파이썬은 인터프리티드 언어입니다. 즉, 인터프리터는 한번에 한줄한줄씩 실행한다.

덕분에 디버깅하는 것을 쉽고, 그렇기 때문에 초보자들에게 적합합니다.

4) Cross-platform language ( 교차 플랫폼 언어 ) 

파이썬은 윈도우나, 리눅스, 유닉스, 매킨토시 등 처럼, 다른 플랫폼에서도 동일하게 구동할 수 있습니다.

그렇기 때문에, 파이썬은 이식성 언어라고도 합니다.

5) Free and Open Source ( 무료, 그리고 오픈 소스 )

파이썬은 자유롭게 이용하능합니다. 소스코드 또한 사용할 수 있습니다.

다시말하면, 파이썬은 오픈 소스 입니다.

6) Object-Oriented language ( 객체 지향 언어 )

Python supports object oriented language. Concept of classes and objects comes into existence.

파이썬은 객체 지향적 언어입니다. 클래스 개념과 객체는 존재하게 됩니다.

7) Extensible ( 탄력성이 있는 )

이것은 코드를 컴파일 하는 데 C/C++ 같은 다른 언어가 사용될 수 있다는 것을 의미 합니다.

그러므로 당신의 파이썬 코드에 이것들을 추가로 사용될 수 있습니다

8) Large Standard Library 

파이썬은 크고 넓은 라이브러리를 가지고 있습니다.

9) GUI Programming

파이썬으로 그래픽 유저 인터페이스를 개발 할 수 있습니다.

10) Integrated ( 통합적인 )

C, C++, JAVA 같은 언어와 쉽게 통합될 수 있습니다.

파이썬이란 무엇인가?
Pathon

파이썬이란 무엇인가?

Click the link to go to the original blog site: 블로그 내용보러가기

 

Python 

파이선 혹은 파이썬

파이선은 간단하고, 배우기 쉽고, 강력하며, 높은 레벨의 객체 지향 프로그래밍 언어입니다.

파이선은 또한 스크립팅 인터프리티드 언어입니다. 귀도 반 로썸이라는 파이썬을 만들었습니다.

나무위키에 따르면 귀도 반 로썸이 심심해서 파이썬을 만들었다고 합니다. (…)

What is Python

파이썬이란 무엇인가

파이썬은 객체 지향적, 높은 레벨의 언어이자, 인터프리티드, 역동적 그리고 다용도로 쓰이는 프로그래밍 언어입니다

파이썬은 어플리케이션 개발에 매력적으로 만들어진 강력하고 여러 용도로 쓰이는 스크립팅 언어 중 가장 배우기 쉽습니다.

파이썬의 문법과 인터프리티드한 성격의 동적 변환은, 여러 분야의 빠른 어플리케이션 개발과 스크립팅에 파이썬을 이상적인 언어로 만들어 줍니다.

파이썬은 강제적이고 기능 위주의 프로그래밍 혹은 절차지향적, 객체지향적 프로그래밍을 포함하는 다중 프로그래밍 패턴을 지원합니다.

파이썬은 웹 프로그래밍 같은 특별한 분야에서 작업하는 것을 뜻하지 않습니다.

웹이나 엔터프라이즈(Enterprise), 3D 캐드 등에서 사용될 수 있고, 이것이 파이썬이 다용도라고 알려진 이유입니다.

동적으로 변환되기 때문에, 변수를 선언하기 위해 데이터 타입을 사용하는 것이 필요하지 않습니다.

그래서 변수에 정수값을 선언하기 위해 A=10 이라 작성할 수 있습니다.

파이썬은 신속한 개발과 디버깅을 할 수 있습니다.

그 이유는 파이썬 개발에서 컴파일 단계가 없고, 버그 수정 테스트 주기도 굉장히 빠르기 때문입니다.

영어원문내용출처 : http://www.javatpoint.com/what-is-python

번역,의역 및 작성 : 초코토끼

검수 : 개발토끼

오역 및 오타의 지적은 겸손히 받겠습니다.

[JavaScript] 연산을 해보자  – 1
Javascript

[JavaScript] 연산을 해보자 – 1

Click the link to go to the original blog site: 블로그 내용보러가기

 

컴퓨터가 탄생하게된 이유를 생각하면 아주 쉽게 이해 할 수 있습니다.

인간은 창조와 상상 같은 새로운 무언가를 탄생시키기에 아주 적합한 두뇌를 가지고 있습니다.

그래서 여러가지 도구를 만들어 생활했고 인간이 가진 신체적 약점을 극복하고 오늘날 지구 상에서 가장 번창한 동물 중 하나가 되었습니다.

근데, 우리 인간이 가진 상상력은 너무나 무한하고 넘쳐나는 호기심을 조절하지 못하는 경향이 있습니다.

궁금한 것이 있으면 그 답을 알고 싶어하죠.

 

예를 들어 1,765,121,100,047,778,123,302,787,567,181,982,246,663,112,119,911 이 숫자의 제곱은 무엇일까? 하고 생각한다든지

혹은 임의의 숫자가 소수 인지 아닌지를 파악하는 것들 말이죠.

 

사람의 머리로 계산할 수 있으나 인간의 두뇌는 한 가지의 연산에 대해서 장시간의 연산을 허락하지 않습니다.

어떤 이는 수학 자체를 싫어할 수도 있고 어떤 이는 집중력이 흩어져 저 위와 같은 큰 수를 계산할 수 없게 되죠.

그렇다면 이렇게 반복적인 연산 혹은 작업을 정확하게 대신해줄 누군가가 필요합니다.

 

그것이 바로 컴퓨터죠.

현재 우리는 인터넷을 통해 웃긴 글을 보며 지내는 나날들이 더 많지만 원래 컴퓨터의 용도는 연산 입니다.

연산하지 못하는 컴퓨터는 존재할 가치가 없는 거죠. 지금도 여러분의 컴퓨터는 연산을 하고 있습니다.

그래서 연산은 컴퓨터에게 아주 중요한 기능 중 하나 입니다.

쓰다 보니 또 잡설이 길어졌군요. 본격적으로 프로그래밍에 들어가봅시다.

 

WebStorm을 실행합니다.

기존에 사용하셨던 index.html을 실행하셔도 되고 새로운 HTML 파일을 추가 해서 진행하셔도 무방합니다.

저는 새로운 HTML 파일을 추가 하겠습니다.

새 HTML 추가하기.

이름은 Calulation이라고 명명하겠습니다.

calculation은 우리나라 말로 계산, 연산이라는 뜻입니다.

공부할 때 쓰는 기본 양식입니다.

같이 공부하시는 분들은 이 기본양식을 다른 곳에다가 저장하셔도 좋고

그냥 제 블로그에서 보셔도 무방합니다.

저는 항상 이 기본 양식에서 출발하여 강좌를 진행하겠습니다.

document.write() 를 알아보자.

저번엔 <p> 태그를 통해서 HTML 화면에 결과값을 출력했으나

오늘부턴 자바스크립트에 좀 더 신경쓰기 위해

document.write() 함수를 쓰도록 할 것입니다.

간단하게 설명을 드리면 document.write(“~ 뭐가 들어가~”);

이렇게 쓰면

~뭐가 들어가~ 가 출력됩니다. ㅎㅎㅎㅎ 간단하죠?

그럼 출력해봅시다.

WebStorm에서 ALT + F2 키를 누르시면 각 브라우저 별로 실행이 가능합니다.

오늘은 연산을 공부하자!

아주 손쉽게 결과가 출력되는 것을 보실 수 있을 겁니다.

그럼 앞서 말씀드린 대로 자바스크립트의 사칙연산을 해보도록 하죠

스크립트를 작성합니다.

result라는 변수를 선언하여  1 더하기 1 연산을 해보도록 하죠.

1더하기 1 연산을 하면 result에 결과 값이 담겨지게 됩니다.

그럼 result를 출력해보죠.

document.write(result); 라고 작성하시면

위와 같이 이상한 내용이 나올 것입니다.

 

왜 이러지?

 

ㅎㅎㅎㅎ 아마 브라우저로 출력해도 아무런 내용이 나오지 않을 것입니다.

그 이유를 자세히 살펴보도록 하죠.

먼저, WebStorm에 내장된 DHTML.js를 통해 우리가 사용한 방식에

무슨 문제가 있는 지 살펴 봅시다.

정의로 이동하기!

CTRL(컨트롤)을 누르신 상태에서 document.write()에서 write를 클릭해보세요.

짠! 정의로 이동하여 DHTML.js를 보실 수 있습니다.

코드가 많이 나왔지만 두려워 하실 것 없습니다.

나중에 생각하시면 여기 있는 내용들이 “자바스크립트에서 가장 쉬운 코드이구나 ….” 하고 생각하실 겁니다.

우리가 틀린 내용은 무엇일까?

prototype.write = function(text) 이 부분을 보시면 됩니다.

프로토 타입이니 뭐니 하는 건 무시하시고 write = function(text) 이 부분만 보세요.

write라는 function에는 텍스트만 들어갈 수 있다고 하네요.

텍스트는 말 그대로 문자열만 들어갈 수 있다는 거죠.

1 + 1 = 2 인데 이것도 문자열 아닌가요??

프로그래밍에서는 숫자와 숫자의 연산의 경우 데이터 종류를 숫자로 간주하고

문자열로 간주하지 않습니다.

문자열로 변환하려면 특별한 문구가 필요하죠.

그것은 나중에 알아보도록 합시다.

result의 내용을 문자열로 바꾼다면?

이렇게 되면 document.write(result)에서 밑줄이 가는 에러 표시가 나오지 않게 되는 군요.

즉, write() 괄호 안에는 무조건 문자열만 들어가야 하네요. ㅎㅎㅎㅎ

그러면 숫자를 문자열로 바꾸어 준다면 곧바로 표시 가능하지 않을까요?

네 ^.6 맞습니다.

앞서 약간 언급했지만 숫자에서 문자열로 바꾸어 준다면 write() 함수에서 출력이 될 수 있습니다.

그럼 바꿔봅시다.

오늘도 언제나 JSHint를 도움 받아서 작성하기!!

JSHint를 사용하는 방법은 이전 편들을 보신 분들은 잘 아시겠지만

이번 편은 처음 보신 분들을 위해서 다시

ALT + Enter키

toString() 함수를 사용해 숫자를 문자로 전환하기

이전 시간에도 사용했던 toString() 함수입니다.

프로그래밍 하시면서 많이 쓰는 함수라 굳이 암기 안하셔도

머릿속에 오랫동안 기억에 남을 거에요 ㅎㅎㅎㅎ

그럼 브라우저에서 결과를 실행해봅시다.

1 + 1 은 2 !!

결과 값이 아주 정확하게 나오네요.

그럼 다른 연산도 해봅시다.

일반적인 빼기 연산 말고 음수가 나올 수 있는 상황을 만들어 보아요.

1 – 5 = ?

-4 !!

자바스크립트는 음수 표현도 할 수 있습니다.

사실, 프로그래밍에서 음수, 양수를 표현하는 것은 그리 대단한 것은 아닙니다.

ㅎㅎㅎㅎㅎ 그렇다면 이번엔 소수점 자릿수를 표현해봅시다.

2/ 10 = ? ㅎㅎㅎ 벌써 결과 나오셨나요?

분수 표현이 아닌 소숫점으로 표현되는 자바스크립트

보통 소수점으로 표현하는 것이 연산에 간결성을 유지할 수 있어서

우리가 학교에서 흔히 사용했던 분수는 찾아볼 수 없습니다.

프로그래밍에서는 소수점으로 연산을 할 수 있습니다.

 

네! 여기까지 잘 따라오셨는지 모르겠네요. ㅎㅎㅎㅎ

너무 쉽다고 생각하시는 분들이 아주 많으실 거라 생각합니다.

그럼 프로그래밍으로 구구단을 짜보는 단계로 넘어가 봅시다.

// 썌얘 아니라  //TODO 사용하기

프로그래밍을 하다보면 이 로직을 언젠간은 작성해야 하는 데 지금 당장 작성하지 못하는 경우가 있습니다.

그럴경우에 보통 // 을 써서 주석으로 남겨 놓기도 하죠.

주석은 프로그래밍 로직에는 아무런 영향을 주지 않고 코드 내부에 일종의 메모를 남길 수 있는 기능을 뜻합니다.

근데 위 사진에 보시면 일반적인 주석은 저렇게 회색빛이 나서 눈에 잘 띄지 않죠.

이러한 문제를 해결하기 위해 JetBrains 사에서 제공하는 모든 Tool에서는 TODO라는 기능을 지원합니다.

//TODO라고 써보세요.

위와 같이 색상이 바뀐 주석을 보실 수 있습니다.

나중에 큰 규모의 자바스크립트 프로그램을 작성하실 때 유용하게 사용하실 수 있을 겁니다. ㅎㅎㅎㅎ

저도 강좌를 진행하면서 계속해서 보여드릴 꺼에요. ㅎㅎ

2단을 만들어 보자

변수 gugudan 이라고 선언하고 그 초기 값을 2로 설정해줍니다.

 

gugudan에 왜 밑줄이 가지???

ㅎㅎㅎ 무시 하셔도 됩니다.

웹스톰은 사용자가 작성한 변수 명의 철자까지 검사합니다.

알아보기 쉬운 혹은 올바른 철자를 사용해 변수를 사용함으로써 코드의 가독성을 높이는 것이죠.

지금은 그냥 무시하고 다음 단계를 진행해 봅시다.

반복문을 사용하자.

프로그래밍을 이미 접하신 분들이라면 다들 한번쯤 써보셨을 겁니다.

for 반복문

모르시는 분들을 위해 간단하게 설명 드리면

var i = 1; 은 반복이 시작할 값입니다. ‘1부터 시작하겠다’는 거죠.

i<=9; 는 ‘반복이 9까지 가면 멈추겠다’ 입니다.

i++ 는 반복문이 한번 실행될 때 i의 값을 1씩 증가 시키겠다는 것입니다.

 

즉, 1부터 9까지 1단계씩 반복을 진행하겠다는 뜻이죠. ㅎ

 

근데,

반복문을 작성하다 보니 코드가 몰린 눈코입 처럼 딱 붙어 있네요.

코드를 정리 해줍시다.

CTRL(컨트롤) + ALT(알트) + L 을 눌러 보세요.

정리된 코드의 모습

for 반복문이 일정한 간격을 유지하면서 읽기 좋게 바뀌었군요.

코드 정리하는 단축키는 많이 사용하셔요.

그래야 나중에 코드를 봐도 어렵지 않게 보실 수 있습니다.

코드가 딱 붙어있으면 읽기 힘들어요.

휴~ 작성하다보니 너무 길어졌네요.

보시는 분들도 너무 길어서 질려 하시겠네요. ㅎㅎㅎ

프로그래밍의 즐거움을 드리고자 이렇게 작성하는 포스팅인데

지루함을 드리면 안되겠죠? ㅎㅎㅎ

오늘은 이만 줄이고 내일 2편을 짧게 준비해서 오도록 하겠습니다.

오늘도 좋은 밤 보내시고 좋은 꿈 꾸시길 바랍니다.

내일 뵐께요. 안뇽~ㅎㅎㅎ

[JavaScript] 문자열을 다루어 보자
Javascript

[JavaScript] 문자열을 다루어 보자

Click the link to go to the original blog site: 블로그 내용보러가기

 

그럼 웹 스톰을 실행합니다.

 

Open을 눌러 어제 만들었던 폴더를 열어줍니다.

그냥 새롭게 Create New Project를 눌러 새롭게 만들어 주셔도 무방합니다.

프로젝트 폴더에 새로운 폴더를 추가해줍니다.

여러가지 내용들을 JavaScript Project라는 폴더에 모두 보관하기 위해서죠.

이름은 JavaScript String이라는 폴더로 만들어줍니다

원하는 이름 아무거나 하셔도 무방합니다.

다음으로 넘어가볼까요?

새로운 HTML 페이지 파일도 추가해줍니다.

이름은 String_Index로 지어줍니다.

이것도 원하는 이름으로 만들어주셔도 무방합니다.

근데, 보통 웹 페이지의 첫 페이지는 Index라고 명명하기도 합니다.

<p> </p> 태그를 추가해줍니다.

위 사진 같이 p 태그를 추가 해줍니다.

<p> 태그는 Paragraph라는 뜻으로 한 페이지에 있는 단락을 나타내 줍니다.

그리고 자세히 보시면 HTML ID 값이 showMessage로 설정해져 있을 것입니다.

자바스크립트가 HTML의 특정 태그를 쉽게 찾을 수 있도록 ID 값을 설정해주는 거죠.

그 다음 스크립트 부분을 추가 해줍니다.

<script> </script> 이 부분을 <P> 태그 다음에다가 붙여주죠.

그리고 나서 Script 부분에 이제 자바스크립트 명령어를 넣어줍니다.

넣어줄 명령어는

document.getElementById(” “) 입니다.

이것에 대해서 간단하게 설명드리면 document는 Html 문서를 뜻합니다.

HTML 문서 내에서 get은 가져오겠다 무엇을?

ElementById(“rabbit”) 괄호 안에 있는 rabbit이라는 ID를 가져오겠다는 의미 입니다.

즉, 어떤 Html 문서 안에 있는 특정 Html ID값을 가진 엘리먼트를 가져오겠다는 명령이죠.

JS Hint 를 사용하자!

document.getElementById(“”)를 입력하면 ” ” 사이에서

키보드 : CTRL(컨트롤) + 스페이스(space)를 눌러주세요.

그러면 위 화면같이 showMessage라는 목록이 나오게 됩니다.

그리고 .innerHTML을 넣습니다.

여기서 .innerHTML은 showMessage라는 ID를 가진 HTML 엘리먼트에다가 “안녕하세요. 반갑습니다.” 라고 넣는다는 거죠.

그럼 웹브라우저에서는 어떻게 표시가 될까요?

한번 확인 해봅시다.

키보드 : ALT(알트) + F2 번을 부르게 되면 위와 같이 메뉴가 나타납니다.

원하는 브라우저를 선택해서 실행해봅시다.

저는 Chrome으로 실행 해보겠습니다.

그럼 브라우저에서 “안녕하세요. 반갑습니다.” 라고 표시되게 됩니다.

신기하신가요? ㅎㅎㅎㅎ 프로그래밍을 어느정도 다루어본 분들은 별로 신기하지 않을 수도 있죠.

어쨋든 다음으로 넘어가봅시다.

그렇다면 어떠한 변수를 통해서 저 문자를 표현해볼까요?

var myName = “개발 토끼”;

이렇게 적어봅시다.

그리고 “안녕하세요”라는 문자 다음에 + myName; 이라고 적어보세요.

위와 같이 다 적으셨나요?

그럼 실행해 봅시다.

이번에는 인터넷 익스플로러로 실행해보죠.

그러면 myName이라는 변수에 들어있는 “개발 토끼”라는 내용이

“안녕하세요”와 합쳐져서 위와 같이 표시되게 됩니다.

ㅎㅎㅎㅎ

여기에서 알 수 있는 것이 있죠.

[문자열 1] + [문자열] = [문자열1문자열2] 이런식으로 합쳐지게 됩니다.

그렇다면 [문자열] – [문자열]은 가능할까요? 혹은 [문자열] * [문자열]은요?

ㅎㅎㅎㅎ

아쉽게도 문자열의 합성은 + 만 사용가능합니다.

왜냐하면 예를 들어 문자열을 – 연산할 때를 가정해봅시다.

 

[안녕하세요] – [안녕!] = ?

 

이렇게 될 경우 [안녕 – 안녕]은 빼기를 통해서 소멸될 수 있겠지만 [하세요 – !] 이건 어떻게 빼야할 까요?

명확하게 결과값을 예측할 수 없죠.

 

그래서 자바스크립트는 문자열 중 특정 문자를 뺄 수 있도록 함수를 지원합니다.

그것은 바로 substring() 함수죠

substring()함수는 아주 간단합니다. 문자열의 특정 위치의 문자열만 가져오는 함수죠.

쓰는 방식은 다음 사진에서 보실 수 있습니다.

 

myName에 있는 “개발 토끼”라는 이름 중에 개발만 가져오도록 하죠.

myName.substring(0,2)를 써보세요.

그래서 그 결과값 result를

document.getElementById를 통해 출력해보세요.

그러면 결과값은 다음과 같이 출력됩니다.

“개발”이라는 문자만 표시되도록 해주죠.

원리는 간단합니다.

substring(문자열 첫번째 번호, 특정 문자열까지 번호)로 문자를 잘라버리는 거죠.

앞서 “개발 토끼”라는 것은 총 길이가 5 입니다.

왜 길이가 5일까요?

한번 알아봅시다.

스크립트를 위와 같이 변경해봅시다.

그리고 출력을 해보면 답은 ???

답은 5 입니다.

“개발 토끼”라는 문자의 길이가 총 5이죠.

표로 알아볼까요?

 개 공백
 1번 2번 3번 4번 5번

이렇기 때문에 5라는 길이죠.

 

그럼 다시 돌아가서 substring(0,2)면

 개 공백
 1번 2번 3번 4번 5번
 인덱스 0 인덱스 1 인덱스 2 인덱스 3 인덱스 4

여기서 인덱스는 컴퓨터가 숫자를 셀때 순번을 뜻합니다.

컴퓨터는 항상 숫자를 0부터 시작해서 읽습니다.

그래서 substring(0,2)는 “개발”만 표현하게 되는 것 입니다.

 

그럼 여기서 의문점이 생기죠.

3번의 공백도 포함이 된건가요???

사실 포함되지 않았습니다.

substring(0,2)는 인덱스 0번은 포함하되 인덱스 2번은 포함하지 않습니다.

그래서 인덱스 2번이 공백이 아니라 그냥 “토”라는 문자가 있었더라도

표시가 되지 않겠죠. ㅎㅎㅎㅎ

 

프로그래밍을 처음 하시는 분들은 왜 이따위로 만들어놨을까 생각하실 겁니다.

하지만, 이걸 이해하신다면 컴퓨터와 좀 더 친숙하게 지내실 수 있죠.

프로그래머는 통역사와 같습니다.

컴퓨터가 사람들을 이해할 수 있게끔 해주고

반대로 사람들이 컴퓨터를 이해할 수 있도록 도와주는

매개체와 같은 역할이죠.

 

이러한 프로그래머의 특성은 아주 매력적입니다.

여러분들도 프로그래밍을 하면서 이러한 매력을 느껴보시길 바랍니다.

오늘은 여기까지 작성하도록 하겠습니다.

 

긴글 읽어주셔서 감사합니다.

다음 시간에 또 만나요.

안뇽~

[JavaScript] 데이터 타입에 대하서 알아보자
Javascript

[JavaScript] 데이터 타입에 대하서 알아보자

Click the link to go to the original blog site: 내용 보러가기

 

여기서 1과 0으로 인식하는 이유는 무엇일까요?

초기 컴퓨터는 전기가 들어오면 1, 전기가 들어오지 않으면 0으로 인식해 참과 거짓을 구분하는 것부터 시작했습니다. 그것이 오늘날에도 이어져 온 것이죠.

따라서, 컴퓨터에게 집을 보여줬을 때 이것이 집이라는 것을 어떻게든 알려줘야 합니다. 그래야 집이라고 인식하겠죠?

더 자세히 들어가보죠.

1과 1

이것의 차이점은 무엇일까요?

사람이 이것을 봤을 때는 둘 다 1이라는 숫자 입니다.

하지만, 컴퓨터는 숫라고 인식할 수도 있고 문자라고 인식할 수도 있습니다.

즉, 컴퓨터가 바라보는 관점에서 1과 1은

1과 “1”인 것입니다.

이렇게 컴퓨터가 데이터를 인식할 수 있는 종류를 정의한 것을 데이터 타입이라고 합니다.

자세히 설명하면 첫 번째 1은 숫자 1이고 두 번째 1은 “가나다라마바사” 와 같은 문자 1로 인식하는 것이죠.

사람은 이 모두를 알아서 상황에 맞게 인식할 수 있지만, 컴퓨터는 그렇게 하질 못합니다. 따라서, 숫자인지 문자인지 정확하게 구별해줘야 하죠.

숫자와 문자를 구별해줌으로써 컴퓨터는 숫자 1에 대해서 다른 숫자와 비교하는 대소 구분 및 연산(더하기, 빼기, 나누기, 곱하기)를 할 수 있게 됩니다.

만약에 문자 1로 데이터를 준다면 대소 구분 및 연산을 할 수 없게 되겠죠?

 

자바스크립트에서 데이터 타입(종류)은 무엇이 있을까?

그렇다면 자바스크립트에서 다루는 데이터 타입에 대해서 알아봅시다.

1) 숫자 타입(Numerical Data)

숫자 타입은 우리가 생각하는 1 2 3 4 5 등 실제 숫자들을 인식하는 데이터 입니다.

2) 글자 타입(Text Data)

“안녕하세요”, “반갑습니다.”, “ㄱ” 등 글자 혹은 문자가 있는 데이터를 글자 타입 데이터라고 합니다.

만약에 “1 2 3 4 5″라고 표현했다면 이는 숫자가 아닌 글자로 표현한 데이터 입니다. 비록 숫자를 사용했지만요.

3) boolean 타입(참과 거짓)

앞서 컴퓨터는 1과 0으로 데이터를 인식한다고 했었습니다. 그래서 1이 들어오면 참, 0이 들어오면 거짓이 되는 타입을 정해준 것이 boolean 타입입니다.

자바스크립트에서는 true와 false로 값을 반환하거나 표현합니다.

4) Null 과 Undefined

Null은 데이터 타입 중에 아무것도 존재하지 않을 때 null이라고 표현합니다. 숫자, 문자 등 아무것도 없는 상태를 말이죠.

Undefined도 null과 비슷한 개념입니다. 아무것도 없죠.

근데 왜 이 2가지를 따로 분류 해놓았나요??

이것들을 구별하는 이유는 나중에 설명 드리겠습니다. 여기서 설명하기엔 너무나도 긴 설명이 필요하기 때문입니다.

이것들 외에도 객체(Obect)와 같은 타입도 있으나 이것도 추후에 자세하게 다루어 보겠습니다.

그러면 데이터 타입을 실제 자바스크립트 화면을 통해 알아보도록 합시다.

먼저 웹스톰을 실행합니다.

처음 사용하는 것이라 Create New Project를 눌러 새로운 프로젝트를 생성해 줍니다.

프로젝트 폴더 생성해주기

C 드라이브에 프로젝트를 위한 별도의 폴더를 만들도록 하겠습니다.

물론 만들지 않아도 무방합니다.

저는 소스코드를 관리하기 위해 C드라이브에 다음과 같이 폴더를 만들었습니다.

폴더명 : JavaScript Project

Empty Project를 선택 그리고 Location 변경

우리는 처음 시작이므로 빈 프로젝트로 시작하겠습니다.

프로젝트가 저장될 위치(Location)을 C드라이브에 자바스크립트 프로젝트 폴더로 변경해줍니다.

이렇게 바꿔주시면 됩니다.

웹스톰의 전체 화면

전반적으로 아주 깔끔한 WebStorm의 화면이 이제 나타났습니다.

새로운 파일을 추가 해서 자바스크립트의 데이터 타입에 대해서 알아보도록 하죠.

새 Html 파일 추가하기

왼쪽 프로젝트 폴더에서 마우스 오른쪽 버튼을 클릭 하면 위와 같이 펼침메뉴가 나오게 됩니다.

위와 같이 Html 파일을 추가 해주세요.

이름은 index.html

여기서 .html은 안 붙이셔도 자동으로 붙습니다.

Html 기본 파일 생성

그러면 위와 같이 Html 파일이 생성될 것입니다.

근데 에디터에 있는 글자 크기나 글자체가 마음에 안드는 군요. 조금 바꾸도록 하겠습니다.

바꾸는 방법은 추후 포스팅에서 알려드릴께요.

글자체 : Consolas, 글자크기 : 14

이제 소스코드 보기가 괜찮아졌네요. 계속 진행해봅시다.

자바스크립트 영역 선언

Html에서 자바스크립트를 선언하는 방법은 다양합니다.

저는 여기서 <body> </body> 태그 안에 선언해서 사용해보겠습니다.

WebStorm에는 JSHint 라는 기능이 있습니다.

아주 아주 강력한 기능이죠.

요즘 IDE에 이런거 없으면 프로그래밍 하기에 너무 불편하다고 할 만큼

개발자의 편의성을 제공하는 기능입니다.

저 위화면에서 Sc라는 글자만 입력해도 위 사진 처럼 선택 항목이 나오게 됩니다.

이 때는 간단하게 Tab 키를 눌러 주시면 자동으로 …

짠! 이렇게 자동으로 스크립트 영역을 표현해줍니다.

정말 편리하죠? ㅎㅎㅎㅎ

이건 약과니 앞으로 더 좋은 기능들을 보여드리겠습니다.

변수 선언과 그 변수의 데이터 타입을 알아보자

변수를 선언할 때는

var 변수명 = 변수값;

이런 식으로 표현합니다.

그래서 이 화면에서는 one이라는 변수를 선언하고 그 안에 숫자 1을 넣도록 하겠습니다.

그리고 typeof는 변수의 데이터 타입을 알아보도록 도와주는 것이라고 생각하시면 됩니다.

그리고 alert는 그 결과값을 웹 브라우저에서 알림 박스로 알려주는 함수라고 생각하시면 되죠.

그럼 숫자 1은 무슨 타입인지 알아볼까요?

 

웹 브라우저로 실행해보자

Html에 있는 JavaScript를 테스트 해보기 위해 WebStorm 오른쪽에 있는 웹 브라우저 선택 버튼 중 하나를 클릭하세요.

웹 개발자의 경우 Chrome, Safari, IE, Opera, Firefox 등 메이저 웹 브라우저를 다 설치하는 것이 좋습니다.

왜냐하면 웹은 모든 브라우저에서 잘 작동해야하기 때문에 모든 브라우저 테스트를 위해 모두 설치하는 것이 좋겠죠? ㅎㅎ

 

숫자 1의 데이터 타입은 number

즉, 숫자라는 이야기 입니다.

one이라는 변수에 담겨진 숫자 1은 number 숫자 데이터죠.

다른 데이터 타입도 한번 볼까요?

위와 같이 hello 변수에 “안녕하세요” 라는 문자열을 넣어봅시다

어떻게 나올까요?

이번에는 단축키를 이용해서 브라우저를 실행합시다

Alt + F2를 누르시면 위와 같이 스냅 메뉴가 나오게 됩니다.

원하는 브라우저를 선택해 테스트 해봅시다.

안녕하세요 라는 문자열은 string 타입이네요

string은 사전적 의미로 문자열이라는 뜻입니다.

즉, 문자열 데이터 타입이라는 거죠.

논외로 string은 밧줄이라는 뜻도 있습니다.

그렇다면 null을 대입해주면 어떻게 나올까요?

그러면 null 타입이라고 나오겠죠?

 

헛! Object라니 이게 무슨소리요. 브라우저 양반

나는 null을 넣었는데 너는 나에게 object를 주었어.

 

그러면 이번엔 아무것도 넣지 않은 것(unknown)을 알아보죠

과연 null이라고 나올가요?

undefined 라니!!

아무것도 넣지 않는다면 undefined라고 나오는 군요.

아주 참으로 오묘한 자바스크립트 원리입니다.

 

더이상 너무 깊게 들어가지 않겠습니다.

어짜피 나중에 논하고 싶지 않아도 논해야하 하는 문제거든요. ㅎㅎㅎㅎ

오늘은 무엇을 넣으면 어떤 타입을 가지게 되는 지 정도만 눈으로 익히시는 것만으로 충분합니다.

아마 이정도도 이해하시기 어려운 분들이 있으실 겁니다.

그러나 걱정하지마세요. 원래 모르는 상태에서 쭉 가는 거죠. ㅎㅎㅎㅎ

하다가 보면 어느 순간 이해가 되는 때가 올 것입니다.

중요한 건 매일 매일 공부하는 습관이 중요하죠.

저도 되도록 매일매일 포스트를 작성하도록 하겠습니다.

이 글을 보시는 분들도 자주 들어오셔 그냥 제가 적어놓은 글을 쭉 읽으시는 것만으로도

도움이 될 수 있도록 하겠습니다.

긴글 읽어주셔서 감사합니다.

내일은 더 좋은 내용을 찾아뵐께요. ㅎㅎㅎㅎㅎ

[JavaScript] 자바스크립터 소개
Javascript

[JavaScript] 자바스크립터 소개

Click the link to go to the original blog site: 블로그 내용보러가기

웹스톰 설치 방법

http://tworab.tistory.com/51

 

1. 자바스크립트에 대해서

JavaScript(이하 : 자바스크립트)는 웹 프로그래밍에서 가장 중요한 중심에 있는 프로그래밍 언어입니다. 정적(움직임이 없는)인 HTML과 CSS로 이루어진 웹 페이지를 동적(움직임이 있는) 페이지로 바꾸어주는 중요한 역할을 하죠.

예를 들어, 사용자가 마우스를 통해 버튼을 클릭 한다든지, 멈춰있는 이미지를 애니메이션처럼 움직이도록 한다는 등 웹 페이지를 사용자와 소통할 수 있도록 해주는 중요한 매개체 입니다.

그래서 자바스크립트는 웹 프로그래머라면 반드시 배워야할 프로그래밍 언어인 것입니다. 꼭 프로그래머만 배워야 할까요?

웹을 통해 서비스를 구현하고자 하는 일반인 분들도 필수적으로 알아야 할 언어인 것입니다.

 

 

2. 자바스크립트로 할 수 있는 것은 무엇인가?

먼저 움직임이 있는 웹 사이트를 만들 수 있습니다. 아무런 움직임이 없는 웹 사이트는 일반적인 HTML과 CSS만 있어도 구현할 수 있습니다. 하지만, 좀 더 다양한 기능을 넣고자 할 때는 자바스크립트가 있어야 하죠.

두 번째는 게임을 만들 수 있습니다. 게임을 개발할 수 있도록 도와주는 자바스크립트 프레임워크를 이용해 자유롭게 만들 수 있고 이를 웹을 통해 누구나 이용할 수 있도록 배포할 수 있습니다. 데스크톱 컴퓨터, 휴대폰, 태블릿 PC 등 인터넷만 연결되어 있다면 다양한 플랫폼에서 실행 가능하죠.

세 번째는 서버를 만들 수 있습니다. 서버는 데이터베이스를 담고 있는 정보를 사용자들에게 뿌려주는 역할을 하죠. 예전 서버 프로그램을 구현하기 위해서는 C++, JAVA, C# 등 종합 컴파일 언어를 사용해야 했지만, 지금은 구글(Google)에서 발표한 Node.js 프레임 워크를 통해서 자바스크립트로 서버를 구현할 수 있습니다.

 

 

3. 자바스크립트를 만들어보자.

자바스크립트 파일은 아주 간단하게 만들 수 있습니다. OS를 윈도우를 이용하시든 Apple OS X를 이용하시든지 동일한 방법으로 만들 수 있죠.

먼저 윈도우 기준으로 설명 드리겠습니다.

 

1) 메모장 열기
– 윈도우 메모장을 열어줍니다. 사진과 같이 메모장을 만들어도 무방합니다.

 

 

 

2) 다른 이름으로 저장하기
– 아무 이름이나 저장합니다. 그냥 TXT 파일로 저장하는 거죠.

 

 

3) 확장자 바꾸기
– 확장명을 파일이름.js로 바꾸어 줍니다.

 

 

그러면 자바스크립트 파일이 완성이 되죠.

안에 아무것도 없지만 그냥 더블 클릭해서 열기를 하게 되면 다음과 같은 화면이 나오게 됩니다.

 

 

웹스톰을 설치하신 분들은 웹스톰을 클릭해주세요.

 

 

그럼 웹스톰이 실행되면서 이렇게 js 파일로 표시되게 됩니다.

여기에다가 실제 자바스크립트 프로그래밍을 진행하는 거죠.

 

 

 

4. 자바스크립트를 본격적으로 공부하기 전에

공부를 시작하기 전에 우선 아셔야 할 사항이 있습니다.

지금 제가 작성하는 기준은 기본적인 프로그래밍 지식이 부족해도 무방하지만 웹에 대한 기초는 가지고 있으셔야 합니다. HTML은 무엇인지 웹 브라우저는 무엇인지 정도 말이죠.

하지만, 자바스크립트 강좌를 아주 쉽게 설명해서 적을 예정입니다. 아이슈타인이 말하길

 

“무언가를 정확하게 알고 있다면 아무리 어려운 것이라도 유치원 아이에게 설명할 수 있다”

라고 말이죠.

저도 이 말에 동감하는 바입니다. 아주 쉽게 설명할 수 있어야 아주 정확하게 이해하는 것이 되는 것이죠.

최대한 쉽게 서술해서 보는 독자분들이 아주 친숙하게 접근할 수 있도록 제가 많은 도움을 드리도록 하겠습니다.

 

 

5. 그 외에 자바스크립트에 대해서

– 자바스크립트는 기본적으로 HTML과 같이 사용되어야 결과를 확인하고 프로그래밍을 할 수 있습니다.

– 자바스크립트는 코드를 한 줄 한 줄 읽어서 실하기 때문에 인터프리터 언어라고도 합니다.

– 자바스크립트(JavaScript)는 자바(Java)와 연관성 없는 프로그래밍 언어입니다.

– 자바스크립트는 넷스케이프(NetScape)사 프로그래머 브렌든 아이크(Brendan Eich)가 처음 모카(Mocha)라는 이름으로 만들었으며, 이후 라이브 스크립트(LiveScript)로 이름이 변경되었다가 최종적으로 자바스크립트(JavaScript)로 불리게 되었습니다.

 

이렇게 해서 자바스크립트 소개를 간단히 마치겠습니다.

추후에 추가적인 내용을 첨부해 더 나은 자료가 될 수 있도록 노력하겠습니다.

읽어주셔서 너무 감사합니다.

다음 시간에 또 만나요 ^.^

[JavaScript] WebStrom 설치하기
Javascript

[JavaScript] WebStrom 설치하기

Click the link to go to the original blog site: 블로그 내용보러가기

 

JetBrains 홈페이지 접속하기

http://www.jetbrains.com

 

– 홈페이지 상단에 PRODUCTS 클릭 –

여기 PRODUCTS를 클릭하게 되면 다양한 JetBrains 사의 제품들을 보실 수 있습니다.

하지만, 우리에게 필요한 것은 WebStorm이죠? ㅎㅎㅎ

 

 

 

– WebStorm 클릭 –

 

 

 

 

– Download WebStorm 클릭 –

 

 

 

– 다운로드 감사 페이지 –

웹스톰을 다운로드 해줘서 너무 감사하다는 문구가 나오는 군요.

저는 오히려 제가 감사하다고 생각합니다.

아주 훌륭한 프로그램을 이렇게 만들어서 배포해주니 말입니다.

이 페이지는 다운로드가 자동으로 이루어지는 페이지 입니다.

 

근데 가끔 인터넷 익스플로러 구 버전을 이용하시는 분들 같은 경우 자동 다운로드가 나오지 않을 수 있습니다.

 

해결책 : 화면에 파란색 큰 글씨로 HTTP or HTTPS 중 하나를 클릭하면 자동으로 다운로드가 시작됩니다.

 

[JavaScript] WebStrom과 함께
Javascript

[JavaScript] WebStrom과 함께

Click the link to go to the original blog site: 블로그 내용보러가기

 

오늘 소개드릴 내용은 WebStorm과 JavaScript입니다.

 

 

WebStorm은 JetBrain사에서 만든 IDE 프로그램 입니다.

 

JetBrains 공식 홈페이지

http://www.jetbrains.com

 

이름에 Web 이라는 단어가 붙었듯이 HTMLCSSJavaScript 등 Client Side 개발을 주로 할 수 있는 통합 개발 환경(IDE)입니다.

하지만, 요즘 JavaScript를 통한 서버 구현도 가능한 기술이 나오기 시작했는데 대표적인 예가 Google에서 발표한 Node.js다. 이것 또한, WebStorm으로 개발 가능하기 때문에 JavaScript 기반 Server Side 개발도 가능합니다.

 

 

JavaScript를 공부하는 개인적인 이유

.net 개발자로 활동하면서 웹 개발 같은 경우 C# 기반인 asp.net을 사용해었습니다. 하지만, 시대가 변화함에 따라 Server Side(서버 측)에서 해줄 일은 DB 통신뿐 실제로는 거의 대부분 JavaScript가 대체하고 있죠. 따라서, Client Side(사용자 측)에서 많은 일들을 해야 하므로 JavaScript를 필연적으로 공부해야 한다는 뜻이죠.

 

 

JavaScript IDE는 어디에?

그런데 JavaScript 개발에 있어 완벽한 편의성을 제공하는 IDE가 없었습니다. C# 같은 경우 Visual Studio, Java 같은 경우 Eclipse라는 도구들이 존재하지만 JavaScript는 아직까지 Full IDE가 존재하지 않았습니다.

하지만, 웹 기술의 발달에 따라 점차 JavaScript 개발 도구가 만들어지기 시작했고. JetBrains 사는 2010년 5월 27일 WebStorm을 발표하게 됩니다. 맨 처음 WebStorm은 JavaScript를 위한 것이라기 보다 Html 기반 웹 페이지 개발에 중점을 가지고 있었다. 그러다 JavaScript 개발에 편의성을 추가하기 시작해 오늘날의 WebStorm IDE가 되었습니다.

 

 

– JetBrains 홈페이지에서 찾은 WebStorm UI –

 

 

WebStorm을 선택한 이유

 

일단 첫 번째, JetBrains 사에서 개발한 개발도구들은 아주 견고하게 잘 만들어졌고 생각합니다.

JetBrains 사에서 만든 제품 중 Intelli J를 잠깐 이용해봤는데 Java 개발자들이 많이 쓰는 Eclipse와는 차원이 다른 경험을 제공해주었죠.

Eclipse(이하: 이클립스)같은 경우 IDE 내부 버그가 아직 존재하며 그 버그가 단시간에 수정되지 않는 점 입니다. 무료로 이용할 수 있다는 장점 외에는 개발 측면에서 장점이 될 수 있는 것들이 많지 않은 것이 사실입니다. 하지만, JetBrains사에서 제공하는 개발 도구는 모두 유료인데 유료인 만큼 이클립스와 다른 차원의 개발도구 품질을 제공합니다. 그래서 WebStorm 또한 믿음이 가는 제품이라 생각합니다.

 

두 번째, 외국 Front-end 엔지니어들이 추천하는 IDE이다.

Google에서 JavaScript IDE Recommendation 이라고 검색하면 꼭 빼놓지 않고 WebStorm을 추천한다. 그리고 자바스크립트에 관해 공부하는 방법을 알려주는 웹사이트에서도 WebStorm을 사용하도록 권장하고 있습니다.

 

제목: How to Learn JavaScript Properly

자바스크립트 제대로 공부하는 방법

 

원문 주소http://javascriptissexy.com/how-to-learn-javascript-properly/

번역 주소https://nolboo.github.io/blog/2014/03/13/how-to-learn-javascript-properly/

(놀부님 블로그)

 

이 외에도 다양한 이유가 있지만 차차 설명 드리도록 하겠습니다.

 

 

유료 버전인데 어떻게 이용하는가? 샀는가?

JetBrains 사에서 제공하는 ReSharper는 직접 구매했으나 WebStorm과 IntelliJ는 학생 라이선스를 통해서 이용하고 있습니다.

 

학생 라이선스 얻는 방법

http://tworab.tistory.com/47

 

아마 많은 분들이 이런 생각이 들 것입니다. 무료 다른 툴을 이용하면 되는데 굳이 유료 개발 도구를 이용해야 하는 지 말입니다. 개발의 완성도와 편의성을 생각한다면 그만큼의 가치가 있습니다. 꼭 구입해서 혹은 30일 평가판이라도 이용해보시길 권장합니다.

 

 

– 웹스톰 가격 –

 

어쨋든 이렇게 해서 저는 WebStorm이라는 강력한 IDE를 가지고 JavaScript 프로그래밍을 공부하려고 합니다.

주기적으로 작성해서 가치 있는 자료 올리도록 하겠습니다.

 

읽어주셔서 감사합니다.

내일 또 뵈요 ^.^

[node.js] socket.io를 이용한 간단한 웹 채팅 프로그램
Node.js

[node.js] socket.io를 이용한 간단한 웹 채팅 프로그램

1. 기본 환경은 셋팅되었다는 전제하에 시작하겠습니다.(node.js, eclipse, node plugin)

2. Node Project를 생성합니다.(여기선 이름이 ChatTest입니다.)

3. 생성되어진 package.json을 연후 아래와 같이 “socket.io”:”0.9.16″ 를 추가합니다.

(Express는 사용안하니 추가하지마세요.)

 

4. 그후 package.json파일에서 우클릭한후 npm install 을 클릭하여 socket.io 를 설치합니다.

 

5. 채팅에는 서버와 클라이언트가 필요하게 되는데 서버는 node.js로 만들고 클라이언트는 jQuery를 이용하여 만들었습니다.

– 서버(app.js)

var express = require(‘express’), app = express(), //

server = require(“http”).createServer(app), io = require(“socket.io”).listen(server), //

nicknames = [];

server.listen(3000);

app.get(“/”, function(req, res) {

res.sendfile(__dirname + “/index.html”);

});

io.sockets.on(“connection”, function(socket) {

socket.on(“new user”, function(data, callback) {

if (nicknames.indexOf(data) != -1) {

callback(false);

} else {

callback(true);

socket.nickname = data;

nicknames[socket.nickname] = socket;

updateNicknames();

}

});

function updateNicknames() {

io.sockets.emit(“usernames”, Object.keys(nicknames));

}

socket.on(“send message”, function(data, callback) {

var msg = data.trim(); // 앞과 뒤의 공백 제거

console.log(“after trimming message is : ” + msg);

if (msg.substr(0, 3) === “/w “) {

msg = msg.substr(3);

var ind = msg.indexOf(” “);

if (ind !== -1) {

var name = msg.substring(0, ind);

var sendmsg = msg.substring(ind + 1);

console.log(“whisper name send is : ” + name + “, ” + name.length);

console.log(“nicknames is : ” + nicknames + “, ” + (name in nicknames));

if (name in nicknames) {

nicknames[name].emit(“whisper”, {

msg : sendmsg,

nick : socket.nickname

});

console.log(“whisper message send is : ” + msg);

} else {

callback(“Error! Enter a valid user.”);

}

} else {

callback(“Error! Please enter a message for your whisper.”);

}

} else {

io.sockets.emit(“new message”, {

msg : data,

nick : socket.nickname

});

}

});

socket.on(“disconnect”, function(data) {

if (!socket.nickname)

return;

nicknames.splice(nicknames.indexOf(socket.nickname), 1);

updateNicknames();

});

});

– 클라이언트(index.html)

 

Enter a username:



/w 사용자명 귓속말




6. 두 파일을 생성후 app.js를 실행하고 http://localhost:3000 을 웹브라우저에 뛰우면 채팅이 실행되는것을 볼수 있습니다.
[출처] [node.js] socket.io를 이용한 간단한 웹 채팅 프로그램.|작성자 쐬주먹는재혀니

Angular란 무엇인가?
angularJs

Angular란 무엇인가?

AngularJS (앵귤러JS) _MVC 프레임워크 기본개념

Angular란 무엇인가?

AngularJS란 동적인 웹앱을 구현하기 위해 구글에서 제작 배포하고 있는 구조적 프레임워크라고 합니다. 특히, Angular의 데이타 바인딩(data binding)과 의존성주입(dependency injection)은 코드를 매우 간결하게 만들어 줍니다. 일반적으로, 동적 어플리케이션과 정적인 문서 사이의 문제점은 다음과 같이 해결합니다.

a library – 유용한 기능들을 모아 놓은 것을 말합니다. ex) jQuery
frameworks – 웹 어플리케이션에 대한 특별한 완성본을 말합니다.

이런 상황에서, Angular는 좀 더 진보되고 directives라는 것을 이용해서 브라우저에게 새로운 문구를 알려줍니다.
데이타 바인딩은 {{}} 으로 표현합니다.
DOM 제어 구조는 반복과, 보여주기, DOM의 일정 부분을 숨길 수 있습니다.
폼과 폼 유효성 검사에 사용할 수 있습니다.
DOM 엘리먼트에 이벤트 핸들링과 같은 새로운 행동을 부여할 수 있습니다.
HTML을 그룹핑하여 재사용가능한 컴포넌트로 제작할 수 있습니다.

호환성 알아보기
최신 브라우전인 크롬, 파이어폭스, 사파리와 IE 9-11버전까지 지원 합니다.
앵귤러JS는 제이쿼리 라이브러리를 사용하고 있습니다. (jQLite)
앵귤러 1.3은 제이쿼리 2.1과 상위 버전을 지원합니다.

기본개념 알아보기
Template: 추가적인 마크업의 HTML
Directives: 수정 가능한 속성과 엘리먼트가 추가된 HTML
Model: 사용자에게 보여지는 부분 또는 사용자 인터페이스
Scope: model이 저장되는 장소이며 controllers, directives and expression이 접근할 수 있음
Expressions: scope에서 변수와 함수에 접근할 수 있음
Data Binding: model과 view의 데이타 싱크
Controller: view 너머에 있는 비즈니스 로직 (business logic)
Dependency Injection: 객체와 함수를 생성 및 연결 가능
Module: 앱의 여러 파트를 담고 있는 것 ex) controllers, services, filters, directives

기본 사용 예제

My Angular App

{{yourName}}

위 예제에서 빨간색으로 표시한 문자는 angular와 관련있는 문구입니다. 양방향 데이터 방식을 이용해서 웹페이지에 표시될 데이터를 directives인 ng-model에 연결해서 사용합니다. 위 예시를 실행해 보시면 p 태그에 input에서 입력한 문자열이 실시간으로 바뀌시는 모습을 확인 할 수 있습니다. 즉, 인풋안에 있는 데이터가 변경될 때 ng-model의 내용이 업데이트 되면서 함께 연결되어 있는 p 태그에 텍스트를 변환합니다.

$watch 와 $apply

위 예시처럼 데이타 바인딩은 마법이 아닙니다. ng-model, ng-repeat 등을 사용할 때, 앵귤러는 내부에서 $watch를 그 값에 생성합니다. 그리고 실시간으로 값의 변화와 업데이트를 감지합니다. 만약, 앵귤러 밖에 코드가 있다면 scope.$apply()를 사용하여 연결 시켜줍니다.

ng-include

ng_include 를 사용하면 손쉽게 html파일을 include 시킬 수 있습니다. 다만 주의 할 점이 있다면, ajax호출을 기반으로 하기 때문에 로컬이 아닌 서버측에서 사용해야 합니다. 다음 예시는 main.html 파일에 header.html 파일을 include하는 방법입니다. ng-include 뒤에 첨부할 파일위치를 적어줍니다. 큰 따옴표와 작은 따옴표를 같이 적어주셔야 합니다. 아래는 main.html 실행화면 결과입니다.

-main.html

Awesome Framework

-header.html

AngularJS Works!!

: main.html에 header.html의 내용이 포함된것을 확인할 수 있습니다.

아래 링크 자료는 AngularJS를 활용해서 만들 수 있는 기초적인 예시를 확인 할 수 있습니다.
[출처] AngularJS란?|작성자 콩이

[2015.06.28] 안드로이드 개발 참고 사이트 / 약간의 소스
Mobile App

[2015.06.28] 안드로이드 개발 참고 사이트 / 약간의 소스

Click the link to read the article: Read the article…

=====

http://arabiannight.tistory.com/entry/%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9CAndroid-AsyncTask-%EC%82%AC%EC%9A%A9%EB%B2%95 – AsyncTask


http://pulsebeat.tistory.com/24 – 서버/클라이언트 소켓(Socket) 통신하기


http://cafe.naver.com/aphone.cafe?iframe_url=/ArticleRead.nhn%3Fclubid=17198535%26page=19%26menuid=14%26boardtype=L%26articleid=3612%26referrerAllArticles=false – 죽지않는 서비스 만들기
—————————————————————————————————-
<Android <-> C#>


http://tbjuni.tistory.com/36 – Json을 이용한 통신 Protocol (3. Java와 C#간의 통신-tcp socket)
http://stackoverflow.com/questions/14824491/can-i-communicate-between-java-and-c-sharp-using-just-sockets – 소켓통신

http://j07051.tistory.com/556 – [C#] HTTP/HTTPS 송수신 (HttpWebRequest/HttpWebResponse)
—————————————————————————————————-

<안드로이드 php mysql>
http://igoto.x-y.net/xe/247 – 웹, DB서버를 각각 구축한 후에 연동하는 법
http://blog.naver.com/skyhool/150098925512 – 파일 문자열 같이 서버로 보내기
http://www.androidside.com/bbs/board.php?bo_table=421&wr_id=137 – app<->php
http://www.androidside.com/bbs/board.php?bo_table=b49&wr_id=84643 – php인자
http://gongmille.tistory.com/5 – [Android]DB연동 – XML 파싱을 이용한 Mysql 연동
http://www.shop-wiz.com/document/php_lecture/lecture13 – php mysql
http://openuri.tistory.com/344 – php mysql 연동 소스
http://sexy.pe.kr/tc/339 – 게시판 글쓰기와 이미지 파일 DB 저장 및 불러오기 예제 
http://ra2kstar.tistory.com/59 – php와 mysql 연동시, 웹에서의 한글깨짐현상
http://unabated.tistory.com/entry/mysql-%EC%A0%91%EC%86%8D-%EC%97%AC%EB%B6%80-%ED%99%95%EC%9D%B8-%EB%B0%8F-%EC%97%90%EB%9F%AC – mysql 접속 여부 확인 및 에러
http://zzaps.tistory.com/30 – php 게시판
http://taetanee.tistory.com/entry/%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-php-%ED%8C%8C%EC%9D%BC-%EC%A0%84%EC%86%A1-%EC%98%88%EC%A0%9C – 사진 업로드
—————————————————————————————————-

<TTS>
http://www.slideshare.net/ssuser8f1bf3/text-to-speech-37715166
http://jcjeon.tistory.com/entry/Using-Text-to-Speech
https://code.google.com/p/humanoid-group/source/browse/trunk/AlarmPlus/src/com/humanoid/alarmplus/WordsToSpeakMainActivity.java?r=73 – TTS 포함된 어플 소스

http://www.codeproject.com/Articles/182881/Text-to-Speech – TTS C# Example
http://www.sysnet.pe.kr/2/0/1228

—————————————————————————————————-

<인트로>
http://zedd.tistory.com/1 – 인트로 화면 만들기
http://taeminimini.tistory.com/417

—————————————————————————————————-

<푸시알람>
http://cholol.tistory.com/169 – GCM
—————————————————————————————————-
<이미지>

http://ralf79.tistory.com/384 – URL이미지를 비트맵으로 바꾸기

http://cholol.tistory.com/154 – [안드로이드 프로그래밍] 서버에서 이미지 불러와서 이미지뷰에 띄우기

http://mantdu.tistory.com/778 – Android] URL을 이용하여 Bitmap을 생성하고 ImageView에 적용하기
http://sjava.net/?p=426 – Android에서 content:/// 스키마의 Uri를 file:/// 스키마의 Uri로 변경하기..
http://warmz.tistory.com/728 – Uri에 대한 절대경로 얻기

http://blog.naver.com/PostView.nhn?blogId=huewu&logNo=110084637531&redirect=Dlog&widgetTypeCall=true – 안드로이드 내부의 미디어 컨텐츠에 접근하는 두 가지 방법

http://www.androidside.com/bbs/board.php?bo_table=B49&wr_id=47683 – 사진 클릭 시 큰이미지 띄우는 방법
http://mainia.tistory.com/602 – 버튼 클릭 시 사진 회전하기

[아파치 라이센스 – 라이센스 명시]
http://www.alphafactory.co.kr/post/2013/07/13/pinch-to-zoom-library/
http://withcoding.com/16 – 안드로이드 ImageView 멀티터치 핀치 줌(Pinch Zoom) 기능 구현하기 (PhotoView 라이브러리 사용법, 두 손가락으로 이미지 확대 축소하기)

—————————————————————————————————-
<녹음>
http://androiddeveloper.tistory.com/91 – 녹음
http://onycomict.com/board/bbs/board.php?bo_table=class&wr_id=127 – 녹음 개굿
http://www.junn.net/wp/archives/4006
http://bonoogi.postype.com/post/642/%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-%EC%9D%8C%EC%84%B1-%EB%85%B9%EC%9D%8C-wave-%ED%8C%8C%EC%9D%BC%EB%A1%9C-%EB%BD%91%EC%95%84%EC%98%A4%EA%B8%B0-1-%EC%9D%8C%EC%84%B1-%EB%85%B9%EC%9D%8C%ED%95%98%EA%B8%B0

—————————————————————————————————-

<전화하기>
http://www.gooday.kr/bbs/board.php?bo_table=android&wr_id=91 – 바로 전화걸기
http://kitesoft.tistory.com/61
http://hankyoungj.blogspot.kr/2014/06/intent-intent-new-intent_30.html
http://moozi.tistory.com/214
http://www.androes.com/147
http://toring92.tistory.com/100 – 전화 바로 거는 거 있음
– 전화번호 코드안에 넣은것(그부분을 받아서 입력하게 구현하면 되지 않을까요?)

http://blog.yongseoklee.com/entry/%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-%EC%A0%84%ED%99%94%EA%B1%B8%EA%B8%B0-%EC%9D%B8%ED%85%90%ED%8A%B8-2%EA%B0%80%EC%A7%80

textview에 onClickListener추가 – 속성에 clickable 체크
—————————————————————————————————-

<문자>
http://maluchi.com/xe/?mid=MyAndroidTips&comment_srl=26749&listStyle=webzine&sort_index=voted_count&order_type=asc&page=4&document_srl=27226 – 문자 모든 메세지 읽어오는 방법
http://www.programkr.com/blog/MQTO5ADMwYT1.html – android 개발 의 전화, 문자, 방송 종합 연습


http://susemi99.kr/1465 – [android] messages in SMS inbox

http://www.androidside.com/bbs/board.php?bo_table=B46&wr_id=7667 
http://www.appsrox.com/android/tutorials/instachat/
– 안드로이드 채팅 프로그램

[제조사별, 기기별 sms inbox ]
lg 몇몇 기기 : content://com.lge.messageprovider/msg/inbox
삼성 기기 : content://com.sec.mms.provider/message
삼성 갤럭시A : content://com.btb.sec.mms.provider/message
일반적 위치(HTC, 팬택?) : content://sms/inbox


http://havehope.tistory.com/ – 19버전 검사

—————————————————————————————————-

<기타>
http://androiddeveloper.tistory.com/89 – intent
http://blog.daum.net/lhg96214/2 – 갤러리 연동
http://sampleprogramz.com/android/radiobutton.php – 투표 응용해야함
http://www.apmsetup.com/board.php?bid=513&mode=view&uid=23559 – AMPSETUP7 에서 ‘403 Forbidden’ 발생
http://it77.tistory.com/category/Programming/Android – 안드로이드 개발
http://www.gooday.kr/bbs/board.php?bo_table=android&wr_id=78 – 꺼져있는 화면 켜기
this.setRequestedOrientation(android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); – 가로화면
http://cybercafe.tistory.com/202 – db 한글
http://itmir.tistory.com/529 – 당겨서 새로고침

—————————————————————————————————-
<애니메이션>
애니메이션은 기존 방식과 동일하게 res/anim 폴더에 xml 로 작성하던가,
Animation 객체를 생성해 사용해도 된다.

overridePendingTransition(R.anim.right_in, R.anim.right_out);
[ Left_in – animation ]


<?xml version=”1.0″ encoding=”utf-8″?>
<set xmlns:android=”http://schemas.android.com/apk/res/android
android:interpolator=”@android:anim/accelerate_decelerate_interpolator”>
<translate 
android:fromXDelta=”-100%”
android:toXDelta=”0″
android:duration=”300″
/>
</set>

[ Left_out – animation ]

<?xml version=”1.0″ encoding=”utf-8″?>
<set xmlns:android=”http://schemas.android.com/apk/res/android
android:interpolator=”@android:anim/accelerate_decelerate_interpolator”>
<translate 
android:fromXDelta=”0″
android:toXDelta=”-100%”
android:duration=”300″
/>
</set>

[React.js] props에 대해 알아보자! 리액트 데이터 흐름 매커니즘
react.js

[React.js] props에 대해 알아보자! 리액트 데이터 흐름 매커니즘

Click the link to read the article: 내용 보러가기

====================

컴포넌트를 조합할 때 기본이 되는 props(속성)에 대해 알아보겠습니다!

리액트에서는 컴포넌트의 조합과 재사용을 위해 props를 제공합니다

부모 컴포넌트에서 자식 컴포넌트로 데이터를 전달하는 매커니즘이라고 할 수 있죠

props는 자식 컴포넌트 안에서 변경할 수 없고 부모 컴포넌트가 전달하며 소유하는 것입니다

예시를 보도록 하죠!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import React, { Component } from ‘react’;
//부모 컴포넌트
class Parent extends Component {
  render() {
    return (
      <ul>
        <Child name=”A” age=”10″ />
        <Child name=”B” age=”15″ />
        <Child name=”C” age=”20″ />
      </ul>
    )
  }
}
//자식 컴포넌트
class Child extends Component {
  render() {
    return (
      <li>
        {this.props.name} : {this.props.age}
      </li>
    )
  }
}
export default Parent;

결과화면은!

부모 컴포넌트에서 이름과 나이 값을 자식 컴포넌트의 props로 지정해줌으로써

자식 컴포넌트에 값이 전달됨을 알 수 있습니다 ^ㅡ^

매우 중요한 기본이므로 꼭 이해해야 합니다!

[React.js] 리액트 시작하기! 새로운 리액트 프로젝트 만드는 법
react.js

[React.js] 리액트 시작하기! 새로운 리액트 프로젝트 만드는 법

Click the link to read the article: 내용 보러가기

================

첫 리액트 프로젝트를 시작해 봅시다!

제 개발 환경은 다음과 같습니다 ^ㅡ^

OS : macOS Sierra

Editor : Visual Studio Code

macOS, Windows, Linux 어떤 OS 건 상관없이

터미널창을 통해 프로젝트를 간단하게 시작할 수 있습니다!

에디터의 경우엔 각자 취향 ㅎ_ㅎ

(개인적으로 VS Code 적극 추천..)

1단계

npm install -g create-react-app

글로벌로 맨 처음에 한번만 설치 해주면 됩니다

2단계

프로젝트 저장을 원하는 디렉토리로 cd 해준다음!

create-react-app my-app

여기서 my-app에는 원하는 프로젝트 명을 넣어주시면 됩니다~~

3단계

리액트 프로젝트 생성이 완료되었습니다!!

cd my-app

프로젝트 폴더로 이동한 다음에

npm start

잠시 후, http://localhost:3000 으로 아래와 같은 페이지가 뜨게 됩니다

기본적인 디렉토리는 자동으로 구성됩니다

정말 편하쥬~?

더 자세한 내용은 리액트 공식 홈페이지를 참조하세용~

리액트 개발자라면 즐겨찾기는 필수라는 사실!!

[React.js] 리액트란? 프론트 엔드의 대세!! 페이스북 오픈소스 라이브러리
react.js

[React.js] 리액트란? 프론트 엔드의 대세!! 페이스북 오픈소스 라이브러리

Click the link to read the article: 내용 보러가기

===============

리액트에 관심을 가지고 꾸준히 공부하고 있는 초보 개발자 염염2 입니다 ^ㅡ^

앞으로 제가 공부하면서 얻은 꿀팁들을 포스팅하며 공유할 예정인데요

오늘은 리액트가 무엇인지 한번 알아보려 합니다!!

구글, 애플, 아마존, IBM 등을 더불어 IT 기술의 선두에 있는

페이스북에서 만든 기술이란건.. 아시죠!?

보통 MVC 모델이란 말을 많이 쓰죠??

간단하게 리액트는 V! 바로 View에 초점이 맞춰진 기술입니다

리액트는 UI를 구축하기 위한 라이브러리로서 UI를 한 번만 정의하고 사용할 수 있게 해줍니다

이후 앱의 상태가 변경되면 별도의 조치 없이도

UI가 이에 반응해 자동으로 다시 재구성된답니다 ㅎ_ㅎ

리액트에서는 관리하기 쉬운 작은 컴포넌트로 크고 강력한 앱을 구축합니다!!

더 이상 함수 본체의 절반을 DOM노드를 찾는 데 허비할 필요 없이

보통의 자바스크립트 객체를 이용해 앱의 상태만 관리하면

나머지는 리액트가 알아~~~서~ 처리해준답니다 개이덕!!

그렇다면.. 리액트로 활용할 수 있는 분야는??

웹 앱

iOS, 안드로이드 앱

캔버스 앱

TV 앱

네이티브 데스크톱 앱

(출처 : 시작하세요! 리액트 프로그래밍 / 스토얀 스테파노프 지음)

리액트의 우수성은 가상 DOM 방식을 사용한다는 것이 매우 중요한 데요

(Angular도 Angular2로 업그레이드 하면서 이 방식을 배껴왔다는…. ㅎㅎ)

아래의 영상은 네이버 개발자 컨퍼런스 DEVIEW 2016년 영상의 일부 입니다!

React VS Angular2 주제로 강연한 영상인데요

가상 DOM 방식과 Angular2와의 차이를 쉽게 이해할 수 있는 영상이니

참고하시면 많이 도움 되실 거에요 ㅎㅎ

AngularJS 란 무엇인가?
angularJs

AngularJS 란 무엇인가?

Click the link to read the article: 내용 보러가기

========================

AngularJS 개념

AngularJS 는 SPA(Single Page Application) 프레임워크라고 합니다.

예를 들어, 하나의 웹 페이지가 실행할 때 View 단에 해당되는 부분이 페이지의 주소가 바뀌지 않으면서 또 다른 새로운 view 를  동적으로 로드하여  사용하는 것을 SPA 라고 합니다.

이러한 SPA 를 편하게 사용하도록 도움을 주는 것이 AngularJS 와 같은 자바스크립트 프레임워크입니다.

그래서 AngularJS 는 SPA 를 만들때 도움을 주는 프레임워크이고 자바스크립트 기반의 MV* 오픈소스 프레임워크라고도 합니다.

결론적으로 SPA & 자바스크립트 기반의 MV* 프레임워크입니다.

MVC

그렇다면, MV* 패턴은 무엇인가?

자바스크립트 공부를 시작하면서 생소한 용어들 중에 디자인 패턴이란 용어가 있습니다.

디자인 패턴은 건축으로치면 공법에 해당하는 것으로 소프트웨어의 개발 방법을 공식화 한 것으로써, 소수의 뛰어난 엔지니어가 해결한 문제들에 대한 규칙들을 다수의 엔지니어들이 문제를 처리 할 수 있도록 한 규칙들이면서, 구현자들 간의 커뮤니케이션의 효율성을 높이는 기법을 디자인 패턴이라고 합니다.

MVC란 Model View Controller의 약자로 에플리케이션을 세가지의 역할로 구분한 개발 방법론입니다.

아래의 그림처럼 사용자가 Controller를 조작하면 Controller는 Model을 통해서 데이터를 가져오고 그 정보를 바탕으로 시각적인 표현을 담당하는 View를 제어해서 사용자에게 전달하게 됩니다.

위의 그림을 웹에 적용해 보자면…

1. 사용자가 웹사이트에 접속한다. (Uses)

2. Controller는 사용자가 요청한 웹페이지를 서비스 하기 위해서 모델을 호출한다. (Manipulates)

3. 모델은 데이터베이스나 파일과 같은 데이터 소스를 제어한 후에 그 결과를 리턴한다.

4 .Controller는 Model이 리턴한 결과를 View에 반영한다. (Updates)

5. 데이터가 반영된 VIew는 사용자에게 보여진다. (Sees)

 

Controller

사용자가 접근 한 URL에 따라서 사용자의 요청사항을 파악한 후에 그 요청에 맞는 데이터를 Model에 의뢰하고, 데이터를 View에 반영해서 사용자에게 알려준다. 

Model

일반적으로 CI의 모델은 데이터베이스 테이블에 대응된다. 이를테면 Topic이라는 테이블은 topic_model이라는 Model을 만든다. 그런데 이 관계가 강제적이지 않기 때문에 규칙을 일관성 있게 정의하는 것이 필요하다.

View

View는 클라이언트 측 기술인 html/css/javascript들을 모아둔 컨테이너이다. 

MV* (통칭으로 MVstar 라고 말합니다)

– MVC

Model

View

Controller

– MVVM (Model-View-ViewModel)

– MVP (Model View Presenter)

MVC 패턴의 프레임워크를 통칭적으로 MV스타(MV*) 프레임워크라고 합니다.

AngularJS 참고사이트

Angular Seed

 – 처음 시작을 위한 기본구조 제공

 – http://github.com/angualr/angular-seed 

 – http://ionicframework.com

AngularJS 구성요소

1. 지시자(Directive) 

– 뷰(View) 영역 

– 특정한 html 태그에 AngularJS 의 기능을 적용하고자 할 때 사용하는 것이 Directive 란 지시자를 사용하는데 AngularJS 의 Directive 는 ng 로 시작하는 지시자들이 많이 있습니다. 예) ng-*

2. 필터(Filters) 

– 어떤 데이터를 화면에 출력하는데 있어서 원하는 데이터만을 필터링하여 가져다 사용할 수 있도록 해주는 기능입니다.

3. 데이터 바인딩(Data Binding) 

– 표형태의 데이터들을 원하는 위치에 사용하기 편하게 바인딩하도록 해줍니다.

4. 컨트롤러(Controller) 

– 메인 컴포넌트 

– 기능별로 묶어서 사용하도록 해줍니다.

5. 서비스(Service) 

– 비즈니스 로직

AngularJS Expressions(표현식)

표현식 (Expressions)

– {{ }} 로 사용됨 (표현식 안에는 자바스크립트 문법을 사용할 수 있습니다)

– JavaScript 의 모든 문법을 지원하지 않음.

– 배열 등 선언 가능합니다.

사용 예

– {{ 표현식 }}

– {{ name }} 

– {{ 3 % 5 }} 의 결과값이 출력됩니다.

– {{ “안녕” + “하세요“ }} 문자열과 문자열을 접합한 결과가 나타납니다.

지시자(Directive)

새로운 형태의 HTML 태그/속성/속성값을 만들어서 정의해주는 것을 지시자라고 합니다.

다음의 ng-app=”” 과 같은 태그와 속성/속성값을 정의할 수 있습니다.

ex) <body ng-app=””>

위의 코드와 같이 html 이나 body 태그에 ng-app=”” 을 지시자를 명시해 줌으로써 AngularJS 를 사용할 준비 단계를 설정합니다.

ng-app 은 data-ng-app 으로 사용할 수 있는데 ng 앞에는 모두 data 가 생략되어 있습니다.

다시말해서, ng-app 은 모듈을 정의해 주는 것입니다.

출처: http://webclub.tistory.com/206 [Web Club]

1장 Express.js란 무엇인가?
Node.js

1장 Express.js란 무엇인가?

Click the link to read the article: 내용보러가기

===============================

1장 Express.js란 무엇인가?

Express.js는 Node.js의 핵심 모듈인 http와 Connect 컴포넌트를 기반으로 하는 웹 프레임워크다. 그러한 컴포넌트를 미들웨어(middleware)라고 하며, 설정보다는 관례(convention over configuration)와 같은 프레임워크의 철학을 지탱하는 주춧돌에 해당한다. 즉, 개발자들은 특정 프로젝트에 필요한 라이브러리를 어떤 것이든 자유롭게 선택할 수 있으며, 이는 개발자들에게 유연함과 수준 높은 맞춤식 구성을 보장한다.

Node.js의 핵심 모듈만 이용해서 중요 앱을 작성한다면 다음과 같은 비슷한 작업을 위해 동일한 코드를 지속적으로 작성함으로써 바퀴를 재발명할 가능성이 높다.

  • HTTP 요청 본문 파싱
  • 쿠키 파싱
  • 세션 관리
  • URL 경로와 HTTP 요청 메서드를 기반으로 한 복잡한 if 조건을 통해 라우팅을 구성
  • 데이터 타입을 토대로 한 적절한 응답 헤더 결정

Express.js는 이러한 문제를 비롯해 다른 여러 문제를 해결함과 동시에 웹 앱에 MVC 형태의 구조를 제공한다. 이 같은 앱은 백엔드만 갖춘 REST API에서부터 온갖 기능을 제공하는 고도로 확장 가능한 풀스택(jade-browser와 Socket.IO를 포함하는) 실시간 웹 앱에 이르기까지 다양하다.

루비에 익숙한 일부 개발자들은 Express.js를 루비 온 레일스 프레임워크에 굉장히 다른 방식으로 접근하는 시나트라(Sinatra)와 비교하기도 한다.

2장 Express.js의 작동 방식

보통 Express.js에는 메인 파일이라고 하는 진입점이 있다. 메인 파일에서는 다음과 같은 단계를 밟는다.

  1. 컨트롤러, 유틸리티, 도우미, 모델과 같은 자체적인 모듈을 비롯한 서드파티 의존 모듈을 인클루드한다.
  2. 템플릿 엔진과 해당 템플릿 엔진의 파일 확장자와 같은 Express.js 앱 설정을 구성한다.
  3. 오류 핸들러, 정적 파일 폴더, 쿠키 및 기타 파서와 같은 미들웨어를 정의한다.
  4. 라우팅을 정의한다.
  5. MongoDB, Redis 또는 MySQL과 같은 데이터베이스에 연결한다.
  6. 앱을 구동한다.

고급 설정에서는 앱을 모듈로 공개하거나 up-time 모듈을 사용해야 할지도 모른다. 그뿐만 아니라 최근에 추가된 클러스터를 활용해(‘팁과 트릭’에서 설명하는 것처럼) 다수의 워커를 생성할 수도 있다.

up-time 모듈에 관해서는 “Node.js 계속 구동시키기“를 참고한다.

Express.js 앱이 실행되면 Express.js가 요청을 대기한다. 앱으로 들어오는 각 요청은 정의된 미들웨어와 라우팅에 따라 맨 위에서 시작해 맨 아래까지 처리된다. 이러한 측면은 실행 흐름을 제어하는 데 중요하다. 이를테면, 각 요청을 여러 개의 함수가 처리하게 할 수도 있다. 그러한 함수 중 일부는 중간에 위치할 것이며, 그래서 이름도 미들웨어다.

  1. 쿠키 정보를 파싱하고, 파싱이 완료되면 다음 단계로 이동한다.
  2. URL로부터 매개변수를 파싱하고, 파싱이 완료되면 다음 단계로 이동한다.
  3. 사용자가 인증되면(쿠키/세션) 매개변수의 값을 토대로 데이터베이스에서 정보를 가져와 일치하는 것이 있으면 다음 단계로 이동한다.
  4. 데이터를 표시하고 응답을 마친다.

3장 설치

Express.js는 두 가지 버전이 있다.

  1. 스캐폴딩을 위한 명령줄 도구
  2. Node.js 앱 안의 모듈(예: 실제 의존 모듈)

명령줄 도구를 설치하려면 맥/리눅스 장비의 아무 곳에서나 $ npm install -g express를 실행한다. 이렇게 하면 도구를 내려받아 $ express 터미널 명령어를 적절한 경로로 링크해서 나중에 새로운 앱을 만들 때 CLI에 접근할 수 있다.

물론 $ npm install -g express@3.3.5와 같이 NPM을 통해 좀 더 구체적으로 3.3.5 버전을 설치할 수도 있다.

참고

대부분의 경우 시스템에서 폴더에 쓰기 위한 루트/관리자 권한이 필요할 것이다. 이러한 경우 $ sudo npm install -g express를 실행하면 된다.

npm-g

그림 3.1 NPM에 -g와 $ express -V를 지정해서 실행한 결과

참고로 위 그림에서 지정한 경로는 /usr/local/lib/node_modules/express다.

이번에는 Node.js 앱 안의 모듈(예: 의존 모듈로 로컬 Express.js 모듈을 설치하는 경우)을 설치하기 위해 $ mkdir expressjsguide로 새 폴더를 만들자. 이 폴더는 이 책에서 사용할 프로젝트 폴더가 된다. 이제 $ cd expressjsguide로 해당 폴더로 이동할 수 있다.

프로젝트 폴더로 이동하고 나면 직접 텍스트 편집기에서package.json을 만들거나 $ npm init 터미널 명령어를 실행해서 만들 수 있다.

npm-init

그림 3.2 $ npm init을 실행한 결과

$ npm init만 실행했을 때 만들어지는 package.json 파일의 예는 다음과 같다.

{
  "name": "expressjsguide",
  "version": "0.0.1",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "BSD"
}

마지막으로 NPM을 활용하는 모듈을 설치하면 된다.

$ npm install express

또는 좀 더 구체적으로 지정하고 싶다면 된다(더 나은 방법이다).

$ npm install express@3.3.5

참고

package.json 파일이나 node_modules 폴더가 없는 상태에서 앞에서 언급한 $ npm install express 명령어를 실행하면 똑똑한 NPM이 디렉터리 트리를 탐색해서 package.json 파일이나 node_modules 중 하나가 들어 있는 폴더를 찾는다. 이러한 동작 방식은 Git의 로직을 다소 흉내 낸 것이다. NPM 설치 알고리즘에 관한 더 자세한 사항은 공식 문서를 참고한다.

아니면 package.json 파일에 의존 모듈("express": "3.3.x"나 "express": "3.3.5")을 지정해서 업데이트한 후 $ npm install을 실행하면 된다.

Express.js v3.3.5 의존 모듈이 추가된 package.json 파일은 다음과 같다.

{
  "name": "expressjsguide",
  "version": "0.0.1",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "dependencies": {
    "express": "3.3.5"
  },
  "author": "",
  "license": "BSD"
}
$ npm install

다음 그림에서 express@3.3.5 문자열 다음에 나오는 경로를 눈여겨보자.

npm-install

그림 3.3 $ npm install을 실행한 결과

기존 프로젝트에 Express.js를 설치해서 package.json 파일(이미 해당 프로젝트 폴더에 존재하는)에 의존 모듈을 저장하고 싶다면(이렇게 하는 것이 현명하다!) $ npm install express --save를 실행한다.

Express.js와 관련 의존 모듈이 설치됐는지 검사하려면 $ npm ls 명령어를 실행하면 된다.

npm-ls

그림 3.4 $ npm ls를 실행한 결과

4장 헬로 월드 예제

4장에서는 첫걸음을 떼기 위해 필수 프로그래밍 예제인 “헬로 월드(Hello World)” 앱을 만들겠다. 온라인 튜토리얼을 통해 이미 헬로 월드 앱을 만들어봤다면 2부(인터페이스)로 곧바로 건너뛰어도 된다.

expressjsguide 폴더에서 hello.js 파일을 만든다. VIM이나 이맥스(Emacs), 서브라임 텍스트 2(Sublime Text), 텍스트메이트(TextMate)처럼 즐겨쓰는 텍스트 편집기를 이용한다. hello.js 서버 파일에서는 Express.js를 활용할 것이므로 다음 라이브러리를 인클루드한다.

var express = require('express');

이제 애플리케이션을 생성한다.

var app = express();

애플리케이션은 로컬의 3000번 포트에서 동작하는 웹 서버다.

var port = 3000;

app.get() 함수를 이용해 와일드카드 라우팅(*)을 정의한다.

app.get('*', function(req, res){
  res.end('Hello World');
});

위의 app.get() 함수는 문자열 형식으로 URL 패턴에 대한 정규 표현식을 받는다. 위 예제에서는 와일드카드 * 문자를 통해 모든 URL을 처리한다.

app.get()의 두 번째 매개변수는 요청 핸들러(request handler)다. 일반적인 Express.js 요청 핸들러는 Node.js의 네이티브 메서드이자 핵심 메서드인 http.createServer()에 콜백으로 전달하는 것과 비슷하다.

http 모듈에 익숙하지 않은 분들을 위해 설명하자면 요청 핸들러는 서버가 특정 요청을 받을 때마다 실행되는 함수다. 여기서 특정 요청이란 보통 HTTP 메서드(예: GET), URL 경로(예: 프로토콜이 지정되지 않은 URL), 호스트와 포트로 정의된다.

Express.js 요청 핸들러에는 최소한 두 개의 매개변수(더 자세한 사항은 후반부의 “오류 처리”를 참고한다)를 필요로 하는데, 요청(간단히 req)과 응답(간단히 res)이 여기에 해당한다. 이와 비슷하게 res.pipe()와/또는 res.on('data', function(chunk) {...})를 통해 읽기 가능 및 쓰기 가능한 스트림 인터페이스를 활용할 수 있다.

마지막으로 Express.js 웹 서버를 구동하고 콜백에서 사용자 친화적인 터미널 메시지를 출력해보자.

app.listen(port, function(){
  console.log('The server is running, ' +
    ' please, open your browser at http://localhost:%s',
    port);
});

스크립트를 실행하려면 프로젝트 폴더에서 $ node hello.js를 실행한다.

node-hello

그림 4.1 $ node hello.js를 실행한 결과

이제 브라우저에서 http://localhost:3000(http://127.0.0.1:3000이나 http://0.0.0.0:3000/과 같다)로 들어가 보면 URL 경로와 상관없이 “Hello World”라는 메시지가 표시될 것이다.

hello

그림 4.2 브라우저에서 http://localhost:3000/ads를 연 모습

참고로 hello.js의 전체 코드는 깃허브 저장소에서도 확인할 수 있다.

var express = require('express');
var port = 3000;
var app = express();

app.get('*', function(req, res){
    res.end('Hello World');
});

app.listen(port, function(){
    console.log('The server is running, ' +
    ' please open your browser at http://localhost:%s',
        port);
});

“Hello” 문구와 함께 서버로 전달한 이름을 되돌려줌으로써 예제를 좀 더 상호작용이 풍부하게끔 수정할 수 있다. 그러자면 cp hello.js hello-name.js 명령어로 hello.js 파일을 복사한 다음 이전 예제에서 모든 것을 포괄하는 라우팅 앞에 다음과 같은 라우팅을 추가하면 된다.

app.get('/name/:user_name', function(req,res) {
  res.status(200);
  res.set('Content-type', 'text/html');
  res.send('<html><body>' +
    '<h1>Hello ' + req.params.user_name + '</h1>' +
    '</body></html>'
  );
});

/name/:user_name 라우팅 안에서는 적절한 HTTP 상태 코드(200은 ‘문제 없음’을 의미한다)와 HTTP 응답 헤더를 설정한 다음 동적 텍스트를 HTML body 태그와 h1 태그로 감쌌다.

참고

res.send()는 우리의 오랜 친구인 http 모듈의 res.end()가 하던 일보다 더 많은 일을 편리하게 해주는 특별한 Express.js 메서드다. 예를 들어, res.send() 메서드는 자동으로 Content-Length HTTP 헤더를 추가한다. 그뿐만 아니라 제공하는 데이터를 토대로 Content-Type 인자를 지정하기도 한다. 더 자세한 사항은 후반부의 “응답(Response)” 장을 참고한다.

hello-name.js 파일의 전체 소스코드 또한 깃허브 저장소에서 확인할 수 있다.

var express = require('express');
var port = 3000;
var app = express();

app.get('/name/:user_name', function(req,res) {
  res.status(200);
  res.set('Content-type', 'text/html');
  res.end('<html><body>' +
    '<h1>Hello ' + req.params.user_name + '</h1>' +
    '</body></html>'
  );
});

app.get('*', function(req, res){
  res.end('Hello World');
});

app.listen(port, function(){
  console.log('The server is running, ' +
    ' please open your browser at http://localhost:%s',
     port);
});

이전 서버를 종료했다가 hello-name.js 스크립트를 실행하고 나면 브라우저에서 http://localhost:3000/name/azat와 같은 식으로 들어갔을 때 다음과 같은 동적 응답을 볼 수 있다.

hello-name

그림 4.3 역동적인 헬로 사용자 예제
노드제이에스(Node.JS)란 무엇인가?
Node.js

노드제이에스(Node.JS)란 무엇인가?

Click the link to read the article: 내용 보러가기

================================

종종 node.js 를 사용하여 몇몇 업체에서 나오는 엔진 혹은 홈페이지 등 소식을 접할 때가 있습니다.

예로 WordPress 역시 php 플러그인 일부를 node.js 인 REST API 로 노선을 갈아탄 사례가 있습니다. 

여기서 node.js 란 무엇인지를 알아 보았습니다.

1. 노드제이에스는 정확히 무엇인가

– 노드제이에스는 무엇인가?

노드제이에스는 정확히 말을 한다면 자바스크립트를 서버에서도 사용을 할 수가 있도록 설계가 되어 있는 서버사이트 스크립트 언어로 서버

개발을 위해서 나온 언어로 v8이라는 자바스크립트 엔진위에서 동작하는 이벤트 처리 I/O 프레임워크로 웹서버와 같이 확장성 있는 네트워크

프로그램을 제작하기 위하여 고안이 된 것입니다.

 

– 그러면 등장을 한 이유가 무엇인가?

노드제이에스가 등장을 하게 된 이유에는 바로 서버와 관련이 있는데 기업에서는 한정적인 자원을 최대한 그리고 최적화 적으로 효율적인

사용을 할 수가 있도록 하는 것을 원한다고 보시면 되십니다.  이 노드제이에스는 기존의 서버처리방식과는 다르게 하나의 처리 방법을

변경해서 서버자원의 활용성을 극대화 시키기 위해서 나온 것입니다.

 

 

2. 그러면 어떠한 역할을 하고 있는가?

– 기존의 서버가 어떻게 작동을 하는지?

그러면 어떠한 역할을 하는지를 이해를 하고자 한다면 기본의 서버가 어떻게 작동이 되는지를 아실 필요성이 있으십니다.

기존의 네트워크 방식은 스레드를 기반으로 하는 동기 방식인데 이 처리 방식인데 이 방식을 쉽게 표현을 한다면 처리를 해야할 곳이

4군데 인데 몸은 하나라고 치고 또한 대기시간이 있으실 것입니다.

이럴 경우에 처리를 할 수가 있는 방식은 몸을 복제하여 동시에 처리를 하는 방식이 있는데 이 방법은 좋은 것 같아 보이지만

일이 많아질 수록 스레드를 더 많이 나누어야 하기때문에 메모리 사용량이 폭발적으로 증가를 하게 되어 결국에는 서버가 다운이 되는

원인이 되기도 하는 것입니다.

 

– node.js를 적용하면 어떻게 작동이 되는가?

그러면 기업에서 내놓을 수가 있는 해결책은 서버를 무한정 증설을 하는 것인데 문제는 기업에서는 이 서버를 계속 증설하는데 매우 제한적

이고 한계가 많고 또한 한번의 이슈가 지나가면 증설된 서버가 아무런 도움이 되지가 않는다는 것입니다.

그래서 node.js를 사용을 하게 된 것인데 이벤트형태로 일을 처리하기대문에 처리를 해야할 곳을 번호표로 주어서 처리를 하는 방식이기

때문에 스레드를 하나만 사용을 해도 굉장히 빠르게 일을 처리를 할 수가 있기때문에 어지간히한 서버로 다운이 되지가 않는 문제가

많이 나오지를 않는 것입니다.  이 방식은 전문가에게는 문제점을 볼 수가 있지만 그렇게 자주 나타나지를 않는 방식인 것입니다.

 

3. 이것을 배우게 된다면 어떤 부분에서 좋은 것일까?

– 노드제이에스가 사용이 되는 분야

노드제이에스가 많이 사용이 되는 분야는 당연히 서버와 밀접한 인터넷에서는 매우 좋다고 볼 수가 있습니다.  서버의 상태가 계속 유지가

되어야 지속적으로 서비스가 가능한 메신저나 혹은 대규모 거래사이트등에서는 매우 좋습니다. 그런 이유로 서버의 사용의 최적화이기때문에 다운현상이 매우 크게 줄어든다는 것도 인터넷분야에서는 매우 좋은 분야라고 보셔도 무관하십니다.

 

– 노드제이에스가 적용이 된 기업사례

이 부분은 해외에서 많이 사용이 되고 있는 그중의 하나가 전투기도 판다는 eBay가 대표적으로 이미 node.js가 적용이 되어있으며 클라우드

에서도 적용이 되어 있는데 그 예로 마이크로소프트의 windows Azure서비스에서도 사용을 하고 있으며 node.js SDK를 배포를 하고 있다는

것입니다.  이런 점만 보아도 노드제이에스가 많은 기업이 적용을 하고 있다는 것을 알 수가 있습니다.

4. 끝으로..

인터넷 서비스는 사용자의 요구에 빠르게 반응하는 것이 중요합니다. 생산성이 높은 node.js는 인터넷 서비스 개발에 사용할 수 있는 좋은 도구이며, 기존 코드를 고려하지 않아도 되는 새로운 서비스를 개발한다면 node.js를 사용하는 것을 고려해 보면 좋을거 같습니다. API를 하나씩 추가하다 보면 node.js 의 매력이 무엇인지 알 수 있을 것입니다.

[Node.js 강좌] Node.js 란? 개념과 소개
Node.js

[Node.js 강좌] Node.js 란? 개념과 소개

Click the link to read to the article: 블로그 내용보러가기

=====

요즘 웹언어에서는 정적인 홈페이지 뿐만 아니라 쇼핑몰, 티켓 예메사이트, 블로그 등 data가 변하는

사이트를 만들고 심지어 게임도 웹에서 만들고 있습니다. 과연 이것들은 어떤 방식으로 만들어져 오는 것일까요?

오늘은 네트워크 어플리케이션 개발에 사용되는 플랫폼 Node.js 를 소개해보겠습니다.

1. Node.js 란?


Node.js는 확장성 있는 네트워크 어플리케이션 개발에 사용되는 소프트웨어 플랫폼입니다. 특시 서버사이드에서 많이 사용되곤 합니다. 사용되는 언어로는 자바스크립트(Javascript)를 활용하며, Non-blocking I/O 와 단일 스레드 이벤트 루프를 통한 높은 처리 성능을 가지고 있는 특징을 가지고 있습니다.

내장 HTTP 서버 라이브러리르 포함하고 있어 웹 서버에서 아파치 등의 별도 소프트웨어 없이 동작하는 것이 가능하며, 이를 통한 웹 서버의 동작에 있어 더 많은 통제에서 벗어나 여러가지 기능을 가능하게 합니다.

즉 Node.js 를 통해 웹어플리케이션이 더욱 발전하게 되었으며, 정적인 홈페이지 뿐만 아니라 쇼핑몰, 티켓 예메사이트, 블로그 등 data가 변하는 사이트를 만들 수 있으며, 여러 개발자들이 만든 프로그램과 게임을 웹상에서 구동시켜 안드로이드폰, 아이폰, 윈도우PC, 맥 등 플랫폼의 제약에 벗어나 어디든 상관없이 실행이 가능하게 해줍니다.

물론 단순히 웹에서 실행가능한 게임을 만들려면 javascript 만으로도 가능하지만 좀더 진화된 프로그램으로 실시간 온라인 채팅, 실시간 온라인 게임 등 실시간 기능을 넣거나, 로그인 기능을 넣어 유저를 관리하고 점수를 관리하는 데이터베이스 기능을 Node.js 를 통해 만들 수가 있습니다.

2. Node.js 사용이유


Node.js 를 이해하려면 먼저 javascript를 배우셔야 합니다. 그 이유는 node.js는 javascript 기반으로 개조하여 만들어졌기 때문입니다.

Javscript는 C/C++, Java와 같은 프로그래밍 언어입니다. 하지만 이름에서 알 수 있듯이 Javascript는 독립적인 언어가 아니라 스크립트 언어입니다. 스크립트 언어는 특정한 프로그램 안에서 동작하는 프로그램이기 때문에 웹브라우저 프로그램 안에서만 작동을 하게 됩니다. 즉 웹브라우저(크롬, 파이어폭스, 사파리, 익스플로러 등등) 가 없으면 사용할 수 없는 프로그램이죠.

여기서 Node.js 가 나오는 이유가 됩니다. 즉 javascript를 웹 브라우저에서 독립시킨 것으로 Node.js를 설치하게 되면 터미널프로그램(윈도우의 cmd, 맥의 terminal 등)에서 node를 입력하여 브라우져 없이 바로 실행할 수 있습니다. 하지만 javascript에서 분리된 언어이기 때문에 문범은 같습니다. 이렇게 .node.js를 이용하여 웹브라우져와 무관한 프로그램을 만들 수 있게 되었고, 중요한 것은 node.js를 이용하여 서버를 만들 수 있다는 것입니다. 중요한 이유는 이전까지 server-clint 웹사이트를 만들 때 웹에서 표시되는 부분은 javascript를 사용하여 만들어야만 했으며, 서버는 ruby, java 등 다른 언어를 써서 만들어야 했는데, 마침내 한가지 언어로 전체 웹페이지를 만들 수 있게 된 것입니다.

3. node.js의 framework Express


Express는 node.js 의 framework 입니다. framework 라는 것은 어떠한 작업을 쉽게 완성하기 위한 라이브러리의 집합이라고 할 수 있습니다. 작업을 시작부터 끝까지 라이브러리로 지원한다는 점이 단순한 라이브러리와 차이가 나는 부분입니다. 예를 들면 JQuery는 javascript 라이브러리로 다양한 용도를 가지고 있지만, jquery 자체가 무엇 하나를 이루기 위한 목적을 가지고 있지는 않습니다. express는 node.js를 이용하여 웹 어플리케이션을 만들기위한 틀(frame)을 제공하는 라이브러리의 집합입니다.

현재 javascript는 git-hub(git을 이용한 소셜 코딩 사이트)에서 1위의 사용률을 보이는 언어이며 이는 node.js의 덕이 크다고 할 수 있습니다. 앞으로의 포스팅을 통해 node.js와 express를 이용한 웹어플리케이션을 만드는 방법을 강좌해보도록 할 예정입니다.

Node.js란?
Node.js

Node.js란?

Click the link to read the article: 블로그바로가기…

==============================

이 글을 쓰게 된 계기는 다음과 같다.

Q: Node.js는 서버인가요?
A: 네, 백엔드 개발자들이 Node.js를 씁니다.

‘백엔드 개발자 쓸 뿐, 프론트 엔드 개발자도 쓸 수 있다’가 내가 내린 결론이고,
오늘은 그에 대해 하나 하나 검증해보는 시간을 가져보고, 다른 사람들에게 잘못된 지식이 전파되는 걸 막고자 한다.
혹시 내가 내린 결론이 잘못된 부분은 무한 태클을 환영한다.

Node.js란…?

Node.js 공식 사이트에서 내린 Node.js의 정의Node.js 공식 사이트에서 내린 Node.js의 정의
Node.js는 Chrome V8 Javascript 엔진으로 빌드된 Javascript 런타임이다.
V8 자바스크립트 엔진은 여기서 중요한 포인트가 아니므로 직접 찾아보길 바란다.

런타임에 대해 정리한 다른 블로그의 포스트를 빌려보자면 다음과 같다.

런타임이란 프로그래밍 언어가 구동되는 환경

예전에는 자바스크립트 런타임이 브라우저 밖에 존재하질 않았다.
하지만 그러한 한계를 극복하고 Node.js가 나왔다.

Javascript 실행 환경?

첫 번째로 Node.js는 REPL(Read, Eval, Print, Loop)을 통해서 런타임을 제공한다.

  1. Read: 유저의 입력 값을 받아서 메모리에 저장
  2. Eval: 입력 값의 평가, 실행
  3. Print: Eval로 인해 반환된 값을 출력
  4. Loop: 1~3을 반복.

이러한 REPL은 Babel REPL과 같이 웹에서 제공해주기도 하고,
Node.js에서 제공하는 REPL은 윈도우의 CMD, 맥의 터미널 등등에서 제공을 해준다.
터미널에서 node라고 입력을 하면 node repl이 실행된다.터미널에서 node라고 입력을 하면 node repl이 실행된다.

두 번째로 따로 자바스크립트 파일을 Node.js에서 제공하는 자바스크립트 런타임을 통해 실행이 가능하다.
위와 같이 REPL에서 개발을 하면 간단한 테스트 정도면 몰라도 어플리케이션을 개발하는 데 적합하지 않다.
따라서 repl 보다는 따로 스크립트 파일을 만들어서 그 스크립트 파일을 node.js, V8이 해석 후 실행하는 형태로 작업을 많이 하게 된다.
아래 소스 코드를 node.js에서 돌리는 것은 위의 REPL에서 실행한 것과 동일하다.

1
2
3
4
5
// a.js
const a = 2;
a;
a + 4;
console.log(a);

그럼 왜 Node.js는 백엔드 영역이라는 오해가 생겼을까?

Node.js를 통해서 서버 만들 수 있기 때문이다.

1
2
3
4
5
6
// server.js
const http = require('http');
http.createServer((req, res) => {
    res.writeHead(200, {'Content-Type': 'text/plain'});
    res.end("Hello World\n");
}).listen(8080);

node.js를 통해 실행한 server.jsnode.js를 통해 실행한 server.js
node.js를 통해 구현한 서버node.js를 통해 구현한 서버

그럼 프론트 엔드 개발자는 언제 Node.js를 쓰는가?

매우 빈번하게 쓰이는데 그 중에서 대표적으로 ES2015+ 문법을 ES5 문법으로 트랜스파일 해주는 Babel을 예로 들어보겠다.
먼저 babel의 기본적인 요소들을 설치하겠다.

1
npm i -S babel-cli babel-preset-env

babel-cli, CLI이기 때문에 터미널 위에서 돌아간다는 점을 염두해두자.

그리고 간단한 바벨 설정 파일(.babelrc)을 만들어주자.

1
2
3
{
  "presets": ["env"]
}

그 다음에 package.json의 npm script 부분을 다음과 같이 추가해주면 된다.

1
2
3
4
5
{
  "scripts": {
    "babel": "babel"
  }
}

그리고 ES2015+의 간단한 파일을 하나 만들어보겠다.

1
2
// a.js
const a = 1;

터미널에서 babel-cli를 통해 해당 파일을 ES5로 트랜스파일 된 결과를 보자.
"use strict" 구문 부터가 실제로 트랜스파일 된 결과“use strict” 구문 부터가 실제로 트랜스파일 된 결과

이게 뭐가 Node.js를 통해 실행한 내용인지 확인해보자.
기본적으로 npm script는 node_modules 디렉토리 안의 .bin 디렉토리에 있는 디렉토리를 인식한다.
node_modules/.bin 디렉토리 안에 babel 파일이 존재한다.node_modules/.bin 디렉토리 안에 babel 파일이 존재한다.

그리고 그 내용은 다음과 같다.

1
2
3
#!/usr/bin/env node

require("../lib/babel");

#!/usr/bin/env node 요 구문으로 인해 node.js에서 cli를 만들 수 있게 해주는 것이라고 생각하면 된다.
그럼 직접 ../lib/babel을 찾아가보자.

node_modules/babel-cli/lib/babel 디렉토리가 존재한다.node_modules/babel-cli/lib/babel 디렉토리가 존재한다.
Node.js에서 기본적으로 디렉토리 뒤에 따로 파일이 명시되지 않으면 index.js 파일을 찾아가는 규칙이 있다.
index.js 파일의 상단 부분을 보면 다음과 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#!/usr/bin/env node
"use strict";

var _keys = require("babel-runtime/core-js/object/keys");

var _keys2 = _interopRequireDefault(_keys);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

var fs = require("fs");
var commander = require("commander");
var kebabCase = require("lodash/kebabCase");
var options = require("babel-core").options;
var util = require("babel-core").util;
var uniq = require("lodash/uniq");
var glob = require("glob");

// 이하 생략

소스 코드 첫 라인에 #!/usr/bin/env node을 보면 CLI임을 짐작할 수 있다.
그럼 다음과 같이도 실행을 해볼 수도 있다는 말이 된다.

npm script가 아닌 직접 파일로 접근해서 CLI를 실행npm script가 아닌 직접 파일로 접근해서 CLI를 실행

하지만 우리가 접근한 파일은 우리가 흔히 보고 있는 js 파일이다.
Node.js는 자바스크립트를 실행해줄 수 있는 환경인 런타임을 제공해주기 때문에 다음과 같이도 할 수 있다.
Node.js에서 바벨을 실행시킨 결과Node.js에서 바벨을 실행시킨 결과

즉, 바벨을 쓴다면, 프론트 엔드 개발자도 Node.js를 쓴다는 결론을 내릴 수가 있다.
바벨 뿐만 아니라 웹팩, 걸프, CRA, Vue-CLI 등등 npm으로 설치하는 모든 CLI는 Node.js를 이용한다고 보면 된다.
그리고 npm(Node Package Manger)을 쓴다는 것 자체가 Node.js를 이용한다고 보면 된다.

웹을 벗어난 Node.js

Node.js 공홈 about 페이지Node.js 공홈 about 페이지
Node.js는 확장성 있는 네트워크 애플리케이션을 위해 설계했다고 나온다.
네트워크 어플리케이션, 즉 서버, 서버를 위해서 설계된 플랫폼이다.
따라서 Node.js로 실제 구현하는 내용도 서버가 많다는 것에는 동의한다.
또한 많은 프론트 엔드 개발자들이 주로 노드를 이용하는 사례인
npm으로 의존성 모듈 관리, 바벨, 웹팩과 같은 CLI를 Node.js 위에서 구동하는 경우
이 경우에

나 노드 할 줄 안다

라고 누군가에게 어필하기에는 다소 무리가 있을 수가 있다.
왜냐면 노드로 서버를 구축하는 사례가 너무 많고, 이미 그런 오해가 정석처럼 받아들여지는 상황이라
필드에 나가서 노드 할 줄 안다고 했을 때

  • 나 노드로 서버 만들 줄 안다.
  • 나 노드로 의존성 모듈 관리하고 CLI를 Node.js 위에서 돌릴 줄 알아.
    둘 중에 누구의 말로 받아들이는 경우가 더 많을까…
    이런 고민을 하다보니 그럼 웹이 아닌 경우에는 무엇이 있을까 고민하게 됐다.

데스크탑 어플리케이션을 제작해주는 일렉트론(Electron)

Electron의 정의Electron의 정의
맥, 윈도우 등등의 크로스 플랫폼 데스크탑 어플리케이션을 HTML, CSS, JS를 통해 만들 수 있다.
자세히 몰라서 아래의 사진으로 대체하겠다.
출처: http://blog.dramancompany.com/2015/12/electron%EC%9C%BC%EB%A1%9C-%EC%9B%B9-%EC%95%B1-%EB%A7%8C%EB%93%A4%EB%93%AF-%EB%8D%B0%EC%8A%A4%ED%81%AC%ED%86%B1-%EC%95%B1-%EB%A7%8C%EB%93%A4%EA%B8%B0/출처: http://blog.dramancompany.com/2015/12/electron%EC%9C%BC%EB%A1%9C-%EC%9B%B9-%EC%95%B1-%EB%A7%8C%EB%93%A4%EB%93%AF-%EB%8D%B0%EC%8A%A4%ED%81%AC%ED%86%B1-%EC%95%B1-%EB%A7%8C%EB%93%A4%EA%B8%B0/
슬랙과 atom, vs code가 일렉트론으로 만들어졌다 하니 믿을만 하다고 할 수 있을 것 같다.

결론

Node.js를 할 줄 안다고 하면 Node.js로 서버를 구성할 줄 안다라고 인식되는 것은 어느 정도 이해할 수 있다.
하지만 Node.js 그 자체를 백엔드 자체만의 기술, 웹 서버 자체만으로 받아들이고
프론트 엔드 개발자들은 Node.js를 쓸 줄 모른다는 그런 잘못된 지식으로 남들에게 더 이상 인식되지 않는 환경이 조성되길 바란다.
명심하자.
Node.js는 백엔드, 웹 서버가 아니라 자바스크립트 실행 환경에 불과하다

Java-생활코딩
Java

Java-생활코딩

Java-생활코딩.

Click the link to read the articles: opentutorials.org

=====

 

XE에서 파비콘(favicon) 만들기
XE

XE에서 파비콘(favicon) 만들기

XE에서 파비콘(favicon) 만들기

Click the link to read the article: https://www.xpressengine.com/

===

1. 파비콘(Favicon)이란 무엇인가?
파비콘은 Favorite Icon을 줄여서 부르는 말로서,  인터넷 주소창에 인터넷 주소를 입력하거나
즐겨찾기에 떤 웹사이트를 추가하였을때 나타나는 작은 아이콘을 말한다. 제로보드 싸이트에서도
파비콘을 사용하고 있지요.

위 화면에서  이 파비콘이다. 이 파비콘을 어떻게 만드는가에 대한 설명이 서기님의 싱싱해
홈페이지에 잘 설명되어 있다.( http://www.singsinghe.co.kr 의 “홈페이지에 아이콘을 달아보자” 참고)
그럼에도 불구하고 여기에서 다시 파비콘을 언급하는 이유는 무엇인가? 그이유는 제로보드 XE의
경우 파비콘을 만드는 방법이 일반적인 홈페이지의 경우와 다르다는 데 있다. 일반 홈페이지의 경우
파비콘을 만드는 방법은 다음과 같다.
(1) 파비콘으로 쓸 16×16pixel의 아이콘을 준비한 후
     (2) favicon.ico 라는 이름으로 저장한다.
(파비콘을 만들어 주는 싸이트 들이 많이 있으니까 그곳에서 만들면 된다.)
(3) favicon.ico를 웹사이트의 원하는 폴더에 넣어두고,
(4) 아래의 태그를 index.html 파일의 <head> 태그 다음에 넣어주면 된다.
          <link rel=”shortcut icon” href=”경로/favicon.ico” type=”image/x-icon” />

* 파비콘을 만들어 주는 싸이트로 외국 싸이트는 http://www.html-kit.com/favicon/ 등이 있고,
국내싸이트는 http://www.faviconbox.kr/ 등이 있다.

2. 제로보드 XE에서 파비콘을 만드는 방법
    (1) 본인의 경우 사용하고 있는 서버의 디렉토리 구조는 다음과 같다.

(2)  제로보드 XE 폴더인 ZBXE폴더내에 favicon.ico 파일을 업로드 시킨다.
(반드시 파일명이 favicon.ico 이어야 함에 주의. 다른 이름을 쓰면 절대 않됨. 본인의 경우는 파비콘  만드는
싸이트를 이용하지 않고 네이버에서 다운받은 icoFX라는 프로그램을 이용해 파비콘을 만들었다.)

(3) 다음은 태그를 입력하기 위해 자신의 싸이트에 관리자로 입장하여, 레이아웃 관리의 헤더스크립트 란에
<link rel=”shortcut icon” href=”경로/favicon.ico” type=”image/x-icon” /> 을 입력하면 된다.

(4)  이상으로 제로보드 XE에서 주소를 입력했을때 파비콘을 보여주기 위한 작업은 모두 끝났다.
하지만 반드시 실시해야 할것이 하나 있다. 파비콘이 제대로 보여줄 준비가 되어 있는지를
첵크하는 것이다. validation 첵크를 위해 http://www.html-kit.com/favicon/validator/ 로 입장한다.
본인의 홈페이지인 http://www.nsh.kr/ 에 대해 첵크해 보았다.


(5) 이런과정을 거쳐 본인의 싸이트에 적용된 파비콘을 보면 다음과 같다.(직접보려면 ” 여기 “를 클릭하세요)


(6) 애드온의 민수님이 작성한 “기본메타태그입력기(http://www.zeroboard.com/16639894) “를 이용해서 파비콘을 작성할수
있음을 첨언합니다. 여기에 파비콘 프로그램을 만드는 방법이 있는줄 몰랐습니다. 괜히 고생했네요.

XE 데이터 이전하기
XE

XE 데이터 이전하기

XE 데이터 이전하기

Click the link to read the article: http://www.xeschool.com/

====

XE 데이터 이전하기

XE 코어의 포장이사와 셀프이사의 개념

XE 코어로 만들어진 웹사이트를 다른 서버의 계정으로 이전한다는 것은 루트(root) 디렉터리와 DB의 백업 그리고 새로운 계정에서의 복원을 이야기합니다. 이러한 일련의 과정을 XE스쿨에서는 포장이사라는 개념으로 설명 했습니다. 포장이사는 기존의 사용하던 XE 코어의 모든 디렉터리와 설정을 새로운 계정에 그대로 복원하고 계속 사용하는 것을 의미합니다. 포장이사가 완료된 경우에는 사용중인 레이아웃이나 게시판 모듈, 또는 게시물(첨부파일) 등의 추가적인 설치와 설정(수정)이 필요하지 않습니다. DB를 복원하고 캐시파일을 재생성하는 것만으로도 이전과 동일하게 웹사이트를 운영할 수 있습니다.

image

포장이사가 완료되면 이전 서버의 계정에서 사용하던 XE 코어는 더이상 필요하지 않기 때문에 도메인의 네임서버 설정을 변경하여 새로운 서버의 계정으로 연결시켜 줍니다.(인터넷 동사무소 신고 필) 그리고 이전 계정의 내용은 삭제를 하거나 문을 닫고 웹세상에서 영원히 사라지게 됩니다…^^ (철거는 자유롭게)

XE 코어에는 포장이사와는 반대로 셀프이사의 방법이 있습니다. 셀프이사란 기존의 웹사이트를 그대로 유지한채 새로운 서버의 계정에 XE 코어를 처음부터 다시 설치하고 사용자 레이아웃과 게시판 모듈 등을 모두 재 설치합니다. 말 그대로 처음부터 새집을 만드는 것이지요. 새집을 만든다는 것은 정확한 의미로 재설치가 아닌 “XE를 설치한다.”는 뜻의 이전의 웹사이트와는 전혀 연관성 없는 작업입니다. 왜냐하면 현재 운영하고 있는 서버의 웹프로그램이 XE 코어이든지, XE 코어의 어머니 제로보드4이든지 또는 기타 다른 웹프로그램(CMS)이어도 상관 없기 때문이죠. 따라서 재설치의 개념이 아닌 최초 설치와 같은 의미로서 셀프이사는 기존의 웹사이트에서 내용물(DB)만 추려 가져오는 것을 말합니다.

image

셀프이사의 정확한 의미를 이해하였다면, 편의상 새로운 웹사이트, 즉 새 집(New Homepage)이라는 말로 이야기를 계속 진행합니다. 새 집은 예전 집과는 달리 더 좋은 레이아웃을 설치하거나 게시판의 갯수도 늘어날 수 있습니다. 컨텐츠(내용)에 따라 메뉴의 트리구조도 다르고 XE 코어 운영 방법 또한 달라질 수 있습니다. 이것을 건축에서는 리모델링(Remodeling/주택 개보수)이라고 표현하는데 웹세상에서는 리뉴얼(Renewal/새롭게 하다/같은 계정에서 같은 XE로 새롭게 하는 것 모두가 리뉴얼 작업입니다.)이라고 말합니다.

웹사이트를 리뉴얼하든지, 최초 설치하든지 셀프이사를 하기 위해서는 반드시 레이아웃과 각종 모듈을 설치를 완료해 두어야 합니다. 왜냐하면 이전 웹사이트에서 사용되고 있는 게시판의 DB자료를 새 집에서 받아줄 게시판 모듈이 없다면 이사 자체가 불가능하기 때문입니다. 따라서 새 집에는 리뉴얼 계획에 따른 게시판 모듈을 반드시 생성해 두어야 합니다. (쉽게 설명드리면 새 집에는 안방, 건너방, 거실, 주방, 화장실, 다용도실 등이 미리 만들어져 있어야 하고 옛날 집에서 세탁기를 가져왔다면 다용도실에, 식탁은 주방에, TV는 거실에 둘 수 있도록 미리 준비해야 한다는 의미입니다…^^)

이렇게 이사 준비가 완료되면 XE 공식 홈페이지 자료실에서 마이그레이션 툴(데이터 이전 툴)을 다운로드 받아 이전 웹사이트에 업로드하고(위 그림에서 톱니바퀴의 위치를 확인하세요!) 이전에 모아 두었던 게시물과 첨부파일, 회원자료 등을 새집으로 빠른우편 등기발송을 하게 됩니다…^^

빠른우편 등기발송이란, 이전 DB자료를 서버에서 압축하여 다운로드 받는 것이 아니라 웹브라우저 또는 서버가 이해하고 읽어볼 수 있는 XML 문서를 만들어 보내기 때문에(DB백업.sql 문서와는 다릅니다.) 빠른우편 등기발송이라고 이해하시면 좋습니다. 첨부된 파일자료도 퀵으로 같이 배송됩니다.

이렇게 게시물과 첨부파일을 모두 새 집에 들여 놓으면 회원자료도 역시 같은 방법으로 XML 문서를 이용해 명단을 건네받고 이건 누가 작성한 글인지, 이건 누구의 물건(첨부파일)인지를 확인하고 연결시켜 주어야 셀프이사를 완료하게 됩니다. 이사를 모두 마쳤으면 마지막으로 캐시파일을 재생성하여 XE 코어를 정상적으로 운영할 수 있게 됩니다.


데이터 이전하기

데이터 이전 툴(마이그레이션 툴)은 현재 운영중인 웹사이트의 운영 프로그램에 따라 각각 해당하는 툴을 다운로드 받아야 합니다. XE 공식 홈페이지 다운로드 자료실에 접속하여 해당하는 툴을 선택하고 다운로드 받으세요. 대부분 데이터 이전은 같은 방법이기 때문에 여기서는 XE->XE 로 데이터를 이전하는 방법에 대해 알아보도록 하겠습니다.

image

위 그림과 같이 데이터 이전 툴의 압축파일을 다운로드 받아 풀게 되면 XE를 위한 툴은 xe 폴더 안에, 제로보드4를 위한 툴은 zeroboard4 폴더 안에, 워드프레스를 위한 툴은 wordpress 폴더 안에 PHP 파일이 들어 있습니다. 이것을 그대로 서버에 올리게 되면 xe 폴더 안으로 모두 들어가 버리기 때문에 xe/index.php를 덮어쓰게 됩니다. 반드시 압축파일을 풀어 나온 폴더의 이름을 변경하거나 새로운 폴더를 하나 만들어서 계정에 업로드하도록 해야 합니다. 이때 만드는 폴더의 이름은 migration 폴더로 합니다.

image

migration 툴은 새 집이 아닌 현재 운영중인 서버 계정에 업로드합니다. migration 폴더를 업로드 할 때에는 xe 디렉터리와 같은 위치에 업로드하도록 합니다. 어느 위치나 상관은 없지만 위 그림과 같은 방법이 좋습니다. 이때 migration 폴더 안에는 작업을 위해 불러야 할 index.php 문서가 있습니다. 이 문서가 일을 하기 시작하면 가정 먼저 물어보는 것이 “xe가 어디에 있습니까?” 입니다.(워드프레스인 경우 “지금 사용하고 있는 wordpress가 어디에 설치되어 있습니까?”)


image

관리자 로그인 후 새로운 웹브라우저를 열고 주소 입력란에 사이트의 도메인 주소와 함께 /migration/index.php를 입력하고 데이터 이전 툴의 index.php 파일을 불러옵니다. 그러면 가장 먼저 XE 코어가 설치된 경로를 묻게 되는데 상대경로 또는 절대경로를 입력합니다. 위 그림에서는 상대경로를 입력하였습니다.

TIP – 여기서는 XE->XE 에 대한 설명입니다. 다른 웹프로그램의 경우에는 해당 프로그램의 설치 경로를 확인하여 반드시 정확하게 입력해야 합니다. 만약 올바른 경로가 아닌 경우에는 XML 문서를 만들기는 하지만 빈문서를 제공할 수 있기 때문에 데이터 이전에 문제가 발생할 수 있습니다. 만약 문제가 발생하는 경우 XE 공식 홈페이지 묻고 답하기란에 문의하시기 바랍니다.


image

가장 먼저 게시물의 데이터를 이전합니다. 라디오 선택 버튼에서 게시판을 클릭하고 아래 나열된 게시판 모듈 중에서 원하는 게시판 모듈을 하나만 선택합니다. 그리고 추출 대상 선택 버튼을 클릭하세요.


추출 대상 수는 게시물의 갯수입니다. 게시판 모듈에서 게시물의 갯수가 많은 경우 반드시 분할하여 나누도록 하세요. 위에서 설명했듯이 셀프이사는 빠른우편 등기발송을 이용하게 됩니다. 따라서 한꺼번에 너무 많은 게시물과 첨부파일을 전송하려는 경우 전송속도 또는 전송상태에 따라서 오류가 발생할 수 있습니다. 게시물의 분할 갯수는 적당히 조절해야 합니다. 게시물마다 첨부파일이 존재하고 첨부파일의 용량이 크다면 여러개로, 첨부파일이 없는 게시물이라면 비교적 크게 나누어 보낼 수 있습니다. 첨부파일을 포함시키지 않는 경우에는 첨부파일 미포함에 체크하도록 합니다.

image

익스플로러인 경우에는 이렇게 추출된 XML 문서의 [URL 복사]를 클릭하면 스크립트의 도움을 받아 자동으로 경로가 복사 됩니다. 이것을 새집의 게시판 모듈(대상 모듈)에 Ctrl+V 키를 이용해 복사해 넣습니다.

image

파이어폭스(FF)에서는 [URL 복사]로 경로가 복사되지 않네요. 따라서 분할된 xml 문서의 이름 위에서 마우스 오른쪽 버튼을 클릭하여 “링크 주소 복사”를 하세요.


image

새 집(추출된 XML 문서를 이동할 새로운 XE 코어 계정)에 관리자로 로그인한 후 관리자 메뉴의 [콘텐츠] > [데이터 들여오기]를 클릭합니다.


▼▼▼ 다음의 내용은 수정 중 입니다. ▼▼▼

image

추출한 내용이 게시물이기 때문에 게시물 정보에 체크하고 [다음]을 클릭합니다.


image

순서대로 설정합니다. 추출한 게시물을 어느 게시판 모듈에 입력할 것인지 자유롭게 선택합니다. 그리고 복사해 두었던 [URL 복사]의 값을 XML파일 지정 입력란에 Ctrl+V 로 복사해 넣으세요. 그리고 다음을 클릭합니다.(XML 입력시 이전에 있던 ../ 은 삭제후 입력합니다.)


image

게시물의 정보입력이 완료되면 입력된 게시물의 갯수를 확인할 수 있습니다. 만약 전송과정에서 오류가 발생하는 경우 이전된 자료를 삭제하고 다시 시도해 보세요. 게시물의 데이터 이전은 위와 같은 방법으로 게시판 모듈별로 분할된 XML 문서를 순차적으로 반복하여 이전을 완료해야 합니다. 압축파일을 만들어 FTP를 이용해 완전한 파일로 입력하는 것이 아니기 때문에 항상 전송속도, 전송상태, 트래픽에 대해 염두해 두고 안전하게 작업을 완료해야 합니다.(빠른우편 등기발송을 잊지 마세요.)


image

회원정보와 쪽지의 데이터 이전 방법도 위와 동일합니다. 회원정보와 쪽지의 경우는 게시판 모듈을 선택하지 않습니다. 회원정보를 XML 문서로 추출한 후에 새로운 계정의 회원정보로 입력하면 됩니다. 회원정보와 쪽지의 데이터를 같은 방법으로 이전하세요.


image

image

게시물과 회원정보를 모두 이전하였다면 아래와 같이 회원정보 동기화를 선택하여 회원과 작성한 게시물을 연결시켜 줍니다.


image

입력된 게시물과 회원정보가 동기화 되면 포인트 시스템 항목에서 회원의 게시물에 대한 포인트 점수를 초기화하도록 합니다. 메뉴얼에서는 초인트 초기화를 데이터 이전 후 한번만 하도록 권하고 있습니다. 재차 반복해서 초기화하지 않토록 주의합니다.


image

마지막으로 모든 것을 한번 정리하는 의미에서 캐시파일 재생성 버튼을 클릭합니다…^^


image

데이터 이전을 완료하게 되면 위와 같이 새로운 홈페이지에서 이전과 동일하게 게시물이 이전 되어 있는 것을 확인할 수 있습니다.


데이터 이전 도움말

다른 웹프로그램(CMS)의 XE 데이터 이전 방법을 모두 설명할 수는 없어도 위의 방법과 동일하거나 비슷합니다. 다만 데이터 이전 툴(index.php)을 처음에 불러올 때 기존의 웹프로그램의 설치경로를 입력하는 과정에서 정확한 경로를 입력하지 못하는 경우 오류가 발생할 수 있습니다. 이런 경우 해당 프로그램의 설치경로를 확인하는 방법을 자세히 알아보고 데이터 이전 툴에 입력하시기 바랍니다.

★중요★
데이터 이전이 완료되면 이전 사이트에 업로드 된 migration 폴더를 삭제하세요. 만약 데이터 이전 직후에 사이트를 철거한다면 문제가 없지만 당분간 유지 할 계획이라면 데이터 이전 툴을 완전히 삭제하는 것이 바람직합니다. 데이터 이전 툴은 관리자 로그인과 상관 없이 XE의 설치경로를 안다면 XML 문서를 만들 수 있습니다.

XE 1.7 동영상 강좌입니다.
XE

XE 1.7 동영상 강좌입니다.

XE 1.7 동영상 강좌입니다.

Click to the following link to read the article: https://www.cameron.co.kr:47741/xe_tip/4657

Links/button disabled until another button is clicked:
Javascript

Links/button disabled until another button is clicked:

Links/button disabled until another button is clicked: 

Click to the following link to read the article: http://stackoverflow.com/questions/14654013/links-button-disabled-until-another-button-is-clicked

PHP mail with Multiple Attachments
PHP

PHP mail with Multiple Attachments

PHP mail with Multiple Attachments

Click to the following link to read the article: https://www.sanwebe.com/2015/12/php-mail-with-multiple-attachments

[CSS study] CSS Learning Site
CSS

[CSS study] CSS Learning Site

[CSS study] CSS Learning Site

Click the link to go to the blog site: http://jaewook.net/archives/375

===

▶ CSS개념을 잡기에 좋은 사이트 (아주쉽게 설명 카툰으로) -한글

▶ CSS에 대해 공부하기좋은 사이트틀 (영문)

▶ CSS로 구성된 사이트들

 

Making a contact form with file upload support
HTML

Making a contact form with file upload support

Making a contact form with file upload support

Click to the following link to read the article: http://www.html-form-guide.com/contact-form/contact-form-attachment.html

jQuery Column Chart Example
Ajax Jquery

jQuery Column Chart Example

jQuery Column Chart Example

Click to the following link to read the article: http://canvasjs.com/docs/charts/integration/jquery/chart-types/jquery-column-chart/

Ajax Contact Form with an Attachment (jQuery & PHP)
Ajax Jquery

Ajax Contact Form with an Attachment (jQuery & PHP)

Ajax Contact Form with an Attachment (jQuery & PHP)

Click to the following link to read the article: https://www.sanwebe.com/2014/04/ajax-contact-form-attachment-jquery-php