안녕하세요 오늘은 간단하게 짚고 넘어가야 할 리액트 에서 이벤트 핸들링에 특징 이 있어 작성하려고 왔습니다.

 

SyntheticEvent ( 합성 이벤트 )

onChange={
            (e)=>{
              console.log(e.type);
              console.log(e.target.value);

              setTimeout(()=>{
                console.warn(e.type);
              })
            }
          }

 

위와같이 코드를 작성 했을 시에 

setTimeout(()=>{

   console.warn(e.type); // null 값이 들어옵니다.

});

해당 이유는 리액트에서의 onChange , onClick 등에 들어오는 event 파라미터는 브라우저에서 사용되고있는 Event 인

https://developer.mozilla.org/ko/docs/Web/API/EventTarget

 

EventTarget

EventTarget은 이벤트를 받을 수 있으며, 이벤트에 대한 수신기(listener)를 가질 수 있는 객체가 구현하는 DOM 인터페이스입니다.

developer.mozilla.org

와는 다른 객체라고 보시면 됩니다.  해당 event 객체는 React 에서 작성한 SyntheticEvent 로 웹 브라우저에 있는 Event 를 이용한 새로운 객체입니다. 그렇기 때문에 위의 비동기 처리시에는 null 값이 되며 해당 경고가 나타납니다.

 

리액트 공식 홈페이지에서도 해당 부분을 해결하기 위해서는 e.persist 라는 함수를 사용하라고 되어있는데요 사용은 간단합니다.

 

위의 에러 코드에서 e.persist()를 호출해주면 됩니다.

          onChange={
            (e)=>{
              e.persist();
              console.log(e.type);
              console.log(e.target.value);

              setTimeout(()=>{
                console.warn(e.type);
              })
            }
          }>

 호출시에는 이제 setTimeout에서도 e.type이 노출됩니다.

e.persist를 사용하고 안하고의 차이를 결과로는 알았습니다.

하지만?   동작이 왜이렇게 바뀌는지에 대한 이유는 기본적으로 리액트에서 사용되고있는 SyntheticEvent 는 객체 풀링 방식을 사용합니다. (Object Pooling) 매 이벤트마다 해당 객체 사용되는것에 대해서 성능상의 이유로 리액트에서는 Object Pooling을 사용함으로써 객체 생성 시간을 줄이고 GC에 대한 노출도 줄이며 메모리관리에 소비되는 시간을 줄이는 방식을 사용하고 있기 때문입니다.  그렇기 때문에 객체가 호출되고 난 후에 이벤트 속성이 초기화 됩니다. 

 

그렇기 때문에 비동기로 호출하였을 경우에는 해당 객체가 비어있는 현상이 발생합니다.

그렇기 때문에 e.persist를 호출하게되면 기존에 사용하고 있던 이벤트 풀 ( Event Pool ) 에서 제거되고 사용자 코드로 사용이 됩니다.

 

 

여기까지 간단한 e.persist에 대해서 적어보았습니다. 

그냥 단순히 비동기에서 왜안되지? -> 아 호출시작부에서 e.persist를 쓰면되겠다 보다는

왜 e.persist라는 거를 써서 했을까 왜 Object Pooling을 사용했을까 등을 생각해보고자 작성하였습니다.

 

감사합니다~

create-react-app (cra)가 v2.0가 된지 벌써 몇달이 됐죠 곧 3.0으로 간다고 하는데 현재는 v2.0 버전을 쓰고 있으니까요~


eject는 프로젝트 막바지에 cra버전은 그대로 fixed하고 eject로 따로 포크떠서 진행할 예정인데요


그전에 sass 모듈이 cra 2.0에서는 기본 지원이여서 너무 편했지만!




import styles from './RecentPostWrapper.scss';


그냥 이렇게 ! 모듈을 불러오면 만사 OK!!


하지만 기본적으로 node-sass는 설치 해주어야 합니다!


"dependencies": {
"classnames": "^2.2.6",
"cross-env": "^5.2.0",
"include-media": "^1.4.9",
"node-sass": "^4.11.0",
"query-string": "^6.3.0",
"react": "^16.8.3",
"react-dom": "^16.8.3",
"react-redux": "^6.0.1",
"react-router": "^4.3.1",
"react-router-dom": "^4.3.1",
"react-scripts": "^2.1.8",
"redux": "^4.0.1",
"redux-saga": "^1.0.2",
"redux-thunk": "^2.3.0"
},


현재 저는 윈도우에서 사용하고있는데 일단 컴포넌트들에 대한 path 를 잡기 위해서


cross-env를 사용하고 있습니다.


cross-env를 설치 한 후에! package.json 에 start script 에 


"start": "cross-env NODE_PATH=src react-scripts start",


이와같이 cross-env를 통하여서 src를 루트로 잡아 주게 됩니다.



보시면 PageTemplate.js 에서 호출하고 있지만 Blog Header를 components/common/BlogHeader로 호출하고 있습니다.


cross-env가 없었다면  ../BlogHeader로 호출했을 것 같습니다. 더 짧아서 좋은거 아니냐! 할수 있지만  


같은 경로에 있기 때문에 그렇지 다른 경로에 있다면 루트 경로가 지정되어있지 않은건 상당한 불편함과 개발 진행이 늦어질수 있습니다.


자 그렇다면 Style을 사용하기위해 SASS를 쓰는데 이에 대한 util.scss는 어떻게 될까요?




@import '../../../styles/utils.scss';

 


???????     ../ ../ ../ ../ 이게 도대체 무엇인가요!!!! 컴포넌트도 이처럼 


@import 'style/utils.scss';


 이렇게 하고싶은걸요..


그러는 와중 CRA공식 문서를 보다보니 이런 글이..




NODE_PATH 처럼 node-sass는 SASS_PATH 를 지원한다고????? ../../ 너무 거슬렸는데;;;


(** 여기서 유의 저는 cra1.0에서 이것저것 해보다가 2.0으로 넘어왔다)


.env 파일을 수정하라고 되어있지만   윈도우에서 수정 부분을 이 아닌 것으로 보여 


// @import '../../../styles/utils.scss';
@import 'styles/utils.scss';


그냥 수정하니 .. 지원된다... 그냥 되는거였습니다... 공식홈페이지 자주보겠습니다.


@import '../PageTemplate/PageTemplate.scss';


확실한지 확인하기 위해서 해당 scss를 수정하겠습니다.


// @import '../PageTemplate/PageTemplate.scss';
@import 'components/common/PageTemplate/PageTemplate.scss';


음.. 잘되네요


** cra2초반버전에서는 안되는것으로 보여서


공식 홈 다시 보니! 2.1.2 밑으로 쭈욱 내리다 보면




!!!!!!!!! SASS_PATH???





#5917을 따라 들어가 보니


그렇다 추가 된 것이였다.

https://github.com/facebook/create-react-app/pull/5917




공식 홈을 자주보는 것을 생활화 합시다!!!


https://facebook.github.io/create-react-app/docs/adding-a-sass-stylesheet








안녕하세요 리액트를 제대로하기전에 


라이프 사이클 까지보았고 이번에는 리액트의 스타일에 대한 작성을 해보려고합니다.


기본적으로 앞서서 스타일을 작성하는 방법에서는


2가지 방법이 있었죠


1. Inline Style CSS 

인라인 방식의 CSS는 클래스 또는 컴포넌트형 함수들 에서 

js Object 형식으로 만들어서 직접 태그에 넣는 방식의 스타일 방식입니다.


인라인 스타일 방식입니다.


render 함수에서 직접 작성합니다.


render() {
const tempStyle={
display:"inline-block",
width:"100px",
height:"100px",
boder:"1px solid black",
background:"orange",
}
return (
<Fragment>
<div style={tempStyle}></div>
</Fragment>
);
}
}


const tempStyle 이라고 작성된 style을 직접 리턴하는 태그에 style로 넣어주게됩니다.

위의 코드에서는 변수를 만들어서 넣었지만 같은형식으로 태그에도 직접 넣어줘도 됩니다.


<div style={{
display:'inline-block',
width:'100px',
height:'100px'
}}></div>



해당 인라인으로 작성후 npm start 로 확인 시 


정상적으로 렌더링 된점을 확인 하실 수 있습니다.


이 방식이 인라인 스타일 방식입니다.



2. Import Style CSS

미리 작성해둔 CSS를 불러와서 (import) 태그에 className으로 작성하여서 사용하는 스타일 방식

import 하여서 css를 사용하는 경우 다른 경우(리액트가 아닌 경우) 에서는


<link rel="stylesheet" href="./style/styles.css"/> 와 같은 방식으로 가져오게 되지만


리액트에서는 import 구문을 통하여서 가져와야합니다.


import styles from './App.css';


해당과 같이 호출 하여서


<div className={styles.box} ></div>


.box{
display:inline-block;
width:100px;
height:100px;
border:1px solid black;
position:fixed;
top:50%;
left:50%;
transform:translate(-50%,-50%);
}


의 box 클래스를 가져와서 입힐 때는 위와같이 작성하여야 합니다.

하지만 작성엔 문제가 없지만


화면에 렌더링시에는 나타나지 않습니다.


왜!!!? webpack 설정이 안되어있기 때문이죠 


테스트용이기 때문에 webpack production 은 건드리지 않고 dev만 건드리면


webpack.config.dev.js 에  css-loader 부분이 있습니다.


** 만약에 create-react-app 으로 만들어졌는데 webpack.config.dev.js가 없다면??

해당 프로젝트에서 npm run eject 명령어를 입력하시면 해당 파일이 생성됨을 확인하실수 있습니다.


이부분에


loader: require.resolve('css-loader'),
options: {
importLoaders: 1,
// modules 지정안할시는 아예 import가 되지않음
modules:true,
},

modules 옵션을 추가해줍시다.!!


그러면 정상적으로 화면에 렌더링이 되는 점을 볼수 있습니다.


위의 코드에서 styles.box 로 넣었지만 리액트는 여러개의 클래스도 넣을 수 있습니다.


<div className={[styles.box,styles.blue].join(' ')}></div>



해당 방법은 너무 지저분하기도 하고 코드 가독성도 그냥 그래서 조금 더 줄이기 위해서 classnames라는 lib를 사용한다고 합니다.



npm i classnames


- .join 이 빠지고 단순 괄호로 묶어서 사용 ( 하지만 style.box style.box  style이 중복되는 현상 발생 )

>classnames에 bind라는 기능을 사용 !! 



import classNames from 'classnames';


<div className={classNames(style.box,style.blue)}></div>




결과


from classnames를 classnames/bind로 꼭 수정하셔야됩니다.


const st = classNames.bind(styles);


-> 해당 css파일들에 대한 클래스를 st가 묶어서 가지고 있는 것으로 보입니다.


그래서 결국 다중 클래스 를 집어 넣을시에는


st('box','second',third') 로 하게되면


App.css에 있는

.box{}   .second{} .third{} 가 순서대로 불려와집니다.


중복되는 클래스가 있을 경우 뒤의 css 스타일이 적용됩니다. (유의바람!)


import React, { Component,Fragment} from 'react';
import classNames from 'classnames/bind';
import PropTypes from 'prop-types';
import styles from './App.css';


const st = classNames.bind(styles);

class App extends Component {
static propTypes = {
name: PropTypes.string,
}
render() {
const isBlue = true;
const tempStyle={
display:"inline-block",
width:"100px",
height:"100px",
boder:"1px solid black",
background:"orange",
}
return (
<Fragment>
<div className={st('box',{
blue:isBlue
})}>
</div>
</Fragment>
);
}
}
export default App;



다음에는 sass에 대해서 작성하겠습니다!

안녕하세요 정말 중요한 부분인거 같아서 메인 포스팅 전의 서브 포스팅을 합니다.


React.js 에서의 라이프 사이클 에 대한 이야기인데요


**** 해당 라이프 사이클에 대한 내용은 현재 보고있는


" 리액트를 다루는 기술 " 책을 9할 이상 공홈에 1할정도 참고 하였습니다.

리액트 입문을 이책으로 하고 있는데 설명이 너무 좋습니다.


1. 마운트 

react 공식 홈 에서는  DOM 에 처음으로 렌더링 될때 라고 되어있습니다.


DOM이 생성되고 웹 브라우저상에 나타나는 작업입니다.  마운트 됐을때의 라이프 사이클

> 컴포넌트 생성


> constructor

-    컴포넌트를 새로 만들 때마다 호출되는 클래스 생성자


> getDerivedStateFromProps (update 사이클에서도 있는 메서드입니다.)

-    props에 있는 값을 state에 동기화하는 메서드

(16.3 새로운 메서드)


static getDerivedStateFromProps(nextProps,prevState){
if(nextProps.value != preState.value){
return { value : nextProps.value };
}
return null; // state 변경 이 필요 없을 시
}

> render

-    생성된 Component UI 를 렌더링 하는 메서드


> componentDidMount

-    컴포넌트가 웹 브라우저상에 나타나는 후에 호출되는 메서드  (마운트가 끝났을 때 겠네요)

 


2. 언마운트


DOM 에 생성되어있는 컴포터를 제거하는 과정

>    componentWIllUnmount

-    컴포넌트가 브라우저(DOM)에서 사라지기 직전에 호출


3. 업데이트 


*****업데이트 는 매우 중요할 것으로 보입니다.

업데이트가 되는 경우 

- props변경 시

- state 변경 시

- 부모 컴포넌트가 리렌더링시 

- this.forceUpdate() 로 강제 렌더링 트리거 시 


[ 참조 - 리액트 를 다루는 기술 ] 


3-1 getDerivedStateFromProps (마운트에도 있던 메서드)

마운트 과정에서도 호출되며 props가 바뀌여서 업데이트시에도 호출이 되는 메서드


3-2 shouldComponentUpdate - 메서드 명 대로 해야할지 말아야할지 를 결정합니다.

컴포넌트가 리렌더링을 할지 말지 결정하는 메서드 return 이 false인 경우는 이 다음에 나오는 메서드를 호출하지않습니다.


3-3 render 

컴포넌트를 리렌더링 합니다.


3-4 getSnapshotBeforeUpdate

컴포넌트 변화를 DOM 에 반영하기 바로 직전에 호출하는 메서드 (DOM 에 적용된게 아닙니다.) 

(16.3 새로운 메서드) - 리액트 공식홈

getSnapshotBeforeUpdate(prevProps, prevState) {
// Are we adding new items to the list?
// Capture the scroll position so we can adjust scroll later.
if (prevProps.list.length < this.props.list.length) {
const list = this.listRef.current;
return list.scrollHeight - list.scrollTop;
}
return null;
}

3-5 componentDidUpdate

컴포넌트의 업데이트 작업이 끝난 후 호출하는 메서드 



대충 10건 정도의 메서드들이 있네요 









안녕하세요 리액트 시작했는데 뭔가 하나하나씩 포스팅 을 직접 하자니 괜히 게시물만 늘리는거 같고 그래서


한땀한땀 보단 한번씩 정리 해서 포스팅을 하려고합니다.


1. 생성 (컴포넌트)

리액트 컴포넌트는 생성시 파스칼 케이스를 따릅니다. 

gdlbutton  - X

gdlButton  - X


GdlBUtton - O


2. 값 전달 

props 는 부모에서 컴포넌트로 값을 전달하기 위한 속성입니다.



기본 세팅은 와 같이 합니다.  (props로 전달된 basic이없을 경우는 '베이직'이 사용됩니다.)

static defaultProps= {

basic:'베이직'

}


<GdlButton name={test} />


this.props.test

하지만 props가 너무 많은 경우에 대비해서

      예를 들면

props로  name,age,grades, class, email 등이 넘어 오게 되면

this.props.name

this.props.age

this.props.grades

.... 너무 길어집니다.


const {name,age,grades,class,email} = this.props; ( 비 구조화 할당을 사용합시다.)



state 는 컴포넌트 내부에서 이동되는 값입니다.



절대로 this.state.name = "test" 같은 작업은 하지 않습니다.

this.setState({

name : 'test'

}); 

setState를 사용하셔야 리렌더링이 발생합니다.


ref 는 컴포넌트에 있는 함수를 외부에서 호출할수 있도록 해주는  속성입니다.


// 1. 컴포넌트 객체에 ref를 선언하고 => 를 통해서 this.GdlButton = ref를 생성한다.

// 이와같지 하지 않고 this.GdlButton.button으로 바로 사용시에는 렌더링 전에 값이 undefined 이기때문(this.GdlButton)

<GdlButton ref={ (ref) => this.GdlButton= ref} />


// 2. 만들어진 this.GdlButton 을 이용하여 함수 사용 

<button type="button"  

onClick={()=> this.GdlButton.buttonsetText("setText")}>Ref Test</button>



class GdlButton extends Component {

// ref를 달기 위한 함수 작성 

buttonsetText= (addText) =>{

const{ innerText} = this.button;    

this.button.innerText = innerText+addText;


}

render(){

return (

<div 

// ref를 달아서 현재 컴포넌트를 리턴

ref={(ref) => {this.button=ref}}>

{/* .... do thing */}

</div>


);

}

}


export default App;


3. 컴포넌트 여러게 생성 


내부의 count만큼 버튼을 생성하고 싶은 경우


const btnList = Array(this.props.count).fill(null).map((i,index) =>{
return <button type="button" style={btnStyle} key={"Btn_"+index} >
                        {this.props.name +"_"+index}</button>;
});


주의점 ** key 값을 유니크하게 설정 해주어야 합니다. ( 리액트자체 렌더링시 해당 key 값을 통하여서 DOM비교를 하는 알고리즘을 가지고있기 때문에 설정 안할시 warning이 뜨긴하지만 성능 문제가 발생합니다. 키 값이 중복되면 에러가 발생)


Array(count) 로 카운트 만큼 생성 후 .fill을 통해 내부값을 채웁니다. (채워야 map 이 순환)

map을 통하여 채워진 배열만큼 버튼을 생성하여 return 합니다.


사용은 render 함수에서


return (
<Fragment>
{/* porps 로 count가 넘어오면 개수만큼 카운트 없으면
기본 버튼 렌더 */}
{
this.props.count ?
btnList :
<button type="button" style={btnStyle}
onClick={ ()=>{
this.setState({
dName: this.state.dName.split('_')[0]+"_"+this.state.number,
number:this.state.number+1
})
} }> {this.state.dName} </button>
}
</Fragment>


이와같이 사용합니다.

{ btnList } 


4. 컴포넌트 이벤트 전달 


이벤트 생성시에는 캐멀케이스(CamelCase)를 따릅니다.


on-click => onClick

onkeypress ==> onKeyPress 


클래스 내부에 함수를 선언후 바인딩합니다.


4-1 미리 선언된 함수 바인딩


handleEvent = ()=>{
console.log("precondition Event");
}
return (
<Fragment>
<button type="button" onClick={this.handleEvent}>handleEvent</button>
</Fragment>
);


           4-2 생성과 동시에 익명함수 사용


<button onClick={ ()=>{
console.log("Test");
}}></button>


5. 스타일 지정,클래스 지정  및 조건부 렌더링 방법


render() {
const btnStyle ={
display:"inline-block",
width:"auto",
border:"1px solid transparent",
borderRadius:"4px",
margin:'1px',
backgroundColor:"#5cb85c",
color:"#FFFFFF",
fontWeight:"400",
fontSize:"14px",
lineHeight:"1.42857143",
height:"100%"

}
<button type="button" style={btnStyle} />


와 같이 사용하며 주의할점은


background-color = 와 같은 케밥 케이스들은 캐멀케이스로 바뀌어야 한다.

backgroundColor

font-size = > fontSize

border-radius  = borderRadius


<div class  > </div> 가 아닌 <div className > </div> 으로 class가 아닌 className 을 사용 하여야 한다.


6. 이외


태그는 무조건 닫아야 합니다. /> 로  그래서 처음에 </br>로 엔터 효과를 내려고했으나  오류가 나서


<br/> 로 사용하여야 합니다.


주석은 


{ /* */ } 로 사용 


propTypes는 props의 타입을 지정할수 있습니다. ( ts 타입스크립트)와 비슷해보이지만


결국 런타임 후에 지정되는 것이고 ts는 런타임전에 알수 있기 떄문에 ts의 하위 호환이라고 봐도 되겠네요


constructor는 컴포넌트를 새로 만들어질때 호출된다. (아직 까진 사용의미를잘 모르겠습니다.)


state는 state = {

basic:'베이직'

}


기존의 state값중 array 가 있을 경우 push 를 해서는 안된다.(타 이벤트 핸들러에서)

push 를 하게되면 기존의 배열에 추가 되어서 더해지는 것이기 때문에 concat 이나 ... spread 연산자 slice를 통해 새로 생성후 합쳐서 새로운 배열을 대입해주어야 한다.


다음 은 리액트 라이프 사이클에 대해서 쓸건데 그전에 spread연산자부터 적고 가야겠네요


리액트 key 에러 


Each child React element in a collection should have a 'key' prop.


자식 Element(요소) 를 map같은 걸로 여러개 생성시 key 값을 지정하지 않으면 해당 워닝을 뱉어냅니다.


그 이유는


리액트에서는  DOM 트리를 업데이트 할때 key 속성을 통해 (리액트에만 있음) diff 알고리즘을 적용하여


렌더링을 최적화한다고 해요


그래서 key 속성이 없어도 화면에 뿌리는데는 문제는 없지만 diff알고리즘을 활용하지 못하기 때문에


렌더링 성능에 영향을 주게 됩니다.


그래서 에러는 아니고 경고 로 뿌려주게 된다고 하더라구요


그래서 현재 작성된 요소가 부모 의 자식으로 들어가는 경우는 key 속성을 넣는 버릇(?) 습관(?) 을 들여야 할것 같습니다.



// 리액트 에서 컴포넌트들을 생성하는것은 파스칼 케이스에 해당되기 때문에 gdlButton 와 같이 생성하면 렌더링이 되지 않습니다.


-> GdlButon 과 같이 첫 문자가 대문자로 오는 파스칼 케이스여야 합니다.


The tag <gdlButton> is unrecognized in this browser. If you meant to render a React component, start its name with an uppercase letter.




안녕하세요


React 시작 전 준비 단계 3번째 입니다.  JSX  , 그리고 ReactDOM.render 및 제가 사용하면서 궁금했던 것들에 대해


그리고 이제까지 1,2단계에서 봤던 것들 정리 차원입니다.



리액트 시작 전 리스트 체크 


1. 준비물 챙겼는지?


IDE - vscode (관련 플러그인, ESLint, Guides)


Node.js 설치 

CRA(create-react-app) 설치 


create-react-app 설치 후 

> 1. create-react-app basic-react

> 2. cd basic-react 

> 3. npm start

> 짜잔. Hello React


github(깃허브)


JS,HTML5,CSS3

> ES6 


이외 사용 도구들 (시작하고 알아보기)

> webpack,babel ... 

2. 리액트는 왜하는건지?

노마드 코더의 말을 빌리자면 매우 멋진 UI 라이브러리이며 그냥 js만 잘하면 다 할수 있다. 모든 화면들을

컴포넌트화 하여서 쪼개서 사용이 가능하다 vue. angular는 그에 따른 문법을 배워야 하지만 리액트 는 그렇지 않다.

또한 리액트는 View만을 위한 라이브러리 이기 때문에 다른 프레임워크와 같이 사용이 가능 하다.



3. 리액트 (create-react-app)


3-1 모든 컴포넌트는 Component를 상속 받아야 한다.

class tempComponent extends Component

      3-2 모든 컴포넌트는 render () 함수가 있다.

render() {}

3-3 import React, { Component,Fragment } from 'react'; 는 필수

상속도 받고 render 부모로 Fragmnet 사용   <Fragment>


4. JSX

리액트에서 사용 되는 문법으로 마치 HTML 을 쓰는 것과 같지만 다른점이 하나있다.

기존 HTML에서는  여러 줄 입력시

'<button></button>'+

'<input></input>' 식을 거치지만 JSX에서는


<button></button>

<input></input> 와 같은 직접 HTML을 쓰는것 처럼 보이는 형태를 띄기 때문이다.


4-1    주석

주석은 단순하게 /* */ 가 아니라 { /* */ } 와 같이 작성한다.


4-2   위젯 생성

- 단순 버튼 생성

render() {

return(

<Fragment>

<button type="button" value="test"/>

</Fragment>

);

}

- js를 통한 생성 

const btnArr=["첫번째","두번째","세번째"];
const listinputTag = btnArr.map(item =>
<input type="button" style={btnStyle} value={item+1} key={item+1}></input>
);

render(){

return(

<Fragment>

{listinputTag}

</Fragment>

);

}

- CSS 속성 입히기 (외부 스타일)

App.js


<div className="react-CSS">
여기는 div입니다.
</div>

App.css


.react-CSS{
width:550px;
height:200px;
color:white;
background-color:black;

}


- CSS 속성 입히기 (인라인 스타일)

App.js


const btnStyle = {
backgroundColor:"#fafafa",
border : '1px solid #d3dbdf',
padding: '8px 13px 9px 15px',
margin:'0px 2px 0px 0px',
whiteSpace:'nowrap',
fontWeight:'600',
cursor:'pointer',
height: '50px',
width:'100px',
borderRadius:'3px',
WebkitTransition:'all',
MozTransition:'all',
msTransition:'all'
};


<button style={btnStyle} type="button" value="test"/>



index.js  (ReactDOM.render)


ReactDOM.render : 리액트 돔 말그대로 React코드를 DOM (Document Object Model) 에 붙이는 역할을 합니다.


다른 의미로 IOS나 AOS같은 모바일에 붙이는 경우는 ReactNative.render(?) 가 있었던것처럼


화면구성은 React + Component 로 구성하고 붙이는 지점은 브라우저냐 모바일이냐 에 따라서


ReactDOM 이냐 ReactNative로 갈리는 것 같습니다. 완전한 분리 좋네요


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

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



ReactDOM.render(만든컴포넌트, document.getElementById('root'))로 되어있는데


root는 어디있을까 했더니 public 폴더에 index.html 에 있는 <div id="root"> 에 붙는 것으로 보입니다.




결과 App.js






import React, { Component, Fragment} from 'react';

import './App.css';
// [React] 시작 전 준비 3단계( JSX && 스타일)
class App extends Component {

  render() {
    const isButton = true;
    const btnArr=["첫번째","두번째","세번째"];
    const btnStyle = {
        backgroundColor:"#fafafa",
        border : '1px solid #d3dbdf',
        padding: '8px 13px 9px 15px',
        margin:'0px 2px 0px 0px',
        whiteSpace:'nowrap',
        fontWeight:'600',
        cursor:'pointer',
        height: '50px',
        width:'100px',
        borderRadius:'3px',
        WebkitTransition:'all',
        MozTransition:'all',
        msTransition:'all'
    };
    const listinputTag =  btnArr.map(item =>
      <input type="button" style={btnStyle} value={item+1} key={item+1}></input>
    );
    const listbuttonTag = btnArr.map(item=>
        <button type="button" style={btnStyle} key={item+1} >  {item+1} </button>
    );
    // [...new Array(10)].map(x => 0);
    const btnCnt = 3;
    const countBtn = Array(btnCnt).fill(null).map( (i,idx) =>{
         let btnKey = "Count_"+idx;
         return <button style={btnStyle} type="button" key={btnKey}>Cnt_{idx}</button>
      }
    );
    return (
      <Fragment>
        <h2>
            { isButton ? '버튼이 있다': '버튼이없다'}
        </h2>
        <h2>
            { isButton && '버튼이 있다'}
        </h2>
            {/* 버튼이 있기 때문에 해당 버튼을 생성 btnCnt만큼 */}
            <button style={btnStyle} type="button" value="test"/>
        <h3> 'map 을 통하여 버튼 렌더링 input 태그 btnArr=[1,2,3];'</h3>
         {listinputTag}
        <h3> 'map 을 통하여 버튼 렌더링 button 태그 btnArr=[1,2,3];'</h3>
        {listbuttonTag}
        <h3> count 변수를 통하여 버튼 렌더링 button 태그  현재 cnt : {btnCnt}</h3>

        {countBtn}
        <div className="react-CSS">
                여기는 div입니다.
        </div>
      </Fragment>
    );
  }
}

export default App;

안녕하세요 언제까지 리액트 시작전인지 모르겠지만...


매번 느끼는 건데 기본기가 탄탄하지않으면 어느 순간 막히는 구간이 다시 오더라구요


하나하나 따져보면서 시작을 하려고해요


저번엔 class App extends Component 였었죠 기본앱을 만들수 있는 


Component 를 상속받기 위해서 import {Component} from 'react' 도 배웠고 이제 index.js 에서 


만들어진 App 을 어떻게 렌더링을 시키는지 확인하고자 index.js 을 보았습니다.


필요없는것들을 지우고 렌더링 에 초점을 맞추기 위해서 



코드를 수정하고 리액트 컴포넌트 쪼개기는 아직 부족한 상태라  기존의 샘플로 작성중인 코드들 을 옮기기 위해 여러 줄 태그를 써보았습니다만


render() { return 에서 사용되는 jsx 문법에는 덮는 부모가 꼭 있어야 한다고 에러가 납니다.


해당 이유는 virtual DOM 에서 컴포넌트 변화를 감지 하기 위해 컴포넌트 내부는 DOM 트리구조 하나로 되어야 한다는 규칙이기 때문이라고 하네요 


그래서 예전에는 해당 을 고치기 위해서


<div >

<tag>

<taG>

</div>


로 썻다고 하는데 


요즘{ React v16버전이후 부터는) Fragment 컴포넌트가 도입되어서 div로 감싸지 않고 Fragment를 사용한다고 합니다.



무슨 차이인지 궁금해서 한번 테스트 해보았습니다.


div로 감쌋을때


return (
<div className="onlyDiv">
<h1>리액트 한줄</h1>
<h2>리액트 두줄</h2>
</div>
);


렌더링 결과는


이와 같이 렌더링되네요  (create-react-app) 에서 App.js만 수정한거기 때문에 다른 변화들은 잘 모르지만 그 기준으로 봐주시길 바랍니다.


div가 아닌 Fragment 로 감쌌을 때

import React, { Component } from 'react';

class App extends Component {
render() {
return (
<Fragment>
<h1>리액트 한줄</h1>
<h2>리액트 두줄</h2>
</Fragment>
);
}
}

export default App;

앗.. 그냥 그대로 수정했더니 모른다고 에러가 나오네요 ;; ㅜ 


'Fragment' is not defined react/jsx-no-undef


import 에 비구조화 할당으로 Component가 아닌 Fragment도 가져와야 되는 걸 몰랐네요


import React, { Component ,Fragment } from 'react';


실행 결과 -

Fragment 로 감싸는 경우는 뭔가 렌더링 후에는 없던것 처럼 나오네요


위에 있던 불필요한 div의 렌더링을 없앨수 있어서 확실히 좋은것 같습니다.


Fragment를 생활화!!



그리고 JSX에서는


기존에 있던 JSP 템플릿 <%  여기에 자바 코드를 넣었었죠 


과같이 자바스크립트 코드를 넣을수도 있다고 하네요


render() {
const AppTitle = "앱 타이틀입니다";
return (
<Fragment>
<h1>리액트 한줄</h1>
<h2>리액트 두줄 {AppTitle}</h2>
</Fragment>
);
}


렌더를 이와같이 수정시에는 


{AppTitle} 부분이 동적으로 들어갈수 있네요 ㅜㅜ 이런거 너무좋아합니다.


여기 까지 해보니 JSX 렌더링에 대해서 한번 더 작성해야 할것 같아서  다시 한번 작성 하겠습니다.


JSX좋은것 같습니다.

안녕하세요 저번 에는 


React를 시작하기전에 create-react-app basic-react를 통해서 만들어진 basic-react 폴더에서 보면


기본적인 리액트 화면과 같이 리액트가 어떤식으로 이루어져있는지 코드 확인이 됩니다. 



import 구문이 있는데


저는 import 하면 자바에서 패키지 가져올떄 import java.lang.nullException~~.. 뭐 이런식으로


가져온것만 기억이 나서 js에도 있는것이 매우 신기 합니다.


프론트에서는 <script 태그를 통해서 가져오는데 그렇지 않은 경우에 대해서는 잘 몰랐었습니다.


import React, { Component } from 'react';


->

 

const React = require('react');

const Component = React.Component; 


와 같다고 볼수 있습니다.


위에서 보면  import React from 'react 랑 const React = require('react'); 는 알겠는데


import {Component} from 'react'는 잘모르겠네요


이부분에 대해서 알아 보니


비 구조화 할당 이라고 ES6 스펙에 있는 기능인데


비 구조화 할당에 대해서는 나중에 다시 한번 포스팅 하도록 하고


해당 비 구조화 할당 중 신기 한것이 있어 하나 가져와 봤습니다.



function f() {
  return [1, 2, 3];
}

var [a, , b] = f();
console.log(a); // 1
console.log(b); // 3

반환 값 무시인데요  return 으로 1,2,3 배열을 반환 했지만 


반환 을 위와같이 비 구조화 할당을 진행시 중간 반환값인 2 를 무시 할수 있다고 하네요 ㅋㅋ 매우 신기 ;


react라는 것을 임포트하여서 가져오는데 그중 {Component}로 받게 되면


react.Component로 받아서 할당 한다고 보면되겠네요 



정리를 하자면 


리액트 코드의 첫줄은 


import React, { Component } from 'react';는


해석하자면


react를 가져와서 React에 넣었고 Component는 비구조화 할당으로 react안에 있는 react.Component를 가져와서 할당했다고 봐도 되겠습니다.


그리고 리액트를 시작하기전에  번들링 도구에 대한 지식이 있어야 합니다. 


번들링 도구는 가장 유명한 웹팩 (webpack)을 알아야 할 것 같고 


여러 가지 파일들을 불러오는 것은 webpack 에서는 loader가 이 역할을 수행해냅니다.


css-loader는 CSS 파일을 


file-loader는 웹 폰트, 이미지, 미디어 파일 등 


babel-loader는  js 파일들을 불러오면서 ES6 -> ES5로 바꿔주는 역할


원래는 이 로더들을 통해서 설정해야 하는데  create-react-app 에서 이 작업들을 전부 로컬에서 해주는 것 같네요


(로컬 테스트용으로) 이후에는 직접 다 해야 하는것으로 보입니다.



import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';


이 구분에 대한 해석이 어느정도 끝난 것 같습니다.


react를 가져와서 React와 Component 에 할당 했고 


svg와 css의 경우는 css-loaderfile-loader등 로더로 설정을 해야 할것으로 보이네요


그다음


class App extends Component {


이 부분입니다.


js에서도 클래스를 만들었고 상속으로 Component를 받았습니다.


위의 비 구조화 할당으로 Component를 가져왔으니 가능하겠죠?


리액트의 컴포넌트를 만들어지는 기본방법으로 보입니다.


class frontButton extends Component로 하면 화면 버튼으로 제가 만들어서 쓸수 있을 것 같네요


벌써부터 재미..


그다음 render함수를 보겠습니다.


import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';

class App extends Component {
render() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h1 className="App-title">Welcome to React</h1>
</header>
<p className="App-intro">
To get started, edit 오오미 <code>src/App.js</code> and save to reload.
</p>
</div>
);
}
}

export default App;


바로 render() { 

// do thing;;

}}으로 되어있는데


내부함수에 function render(){}    도 아니고


var render = function() 도 아니네요;; 이게 뭘까 했습니다.


이 점도 찾아 보니 ES6에  생긴 


간결 메서드

Concise Method()


라고 하네요


ES 5에서


var beforeObj = {
        name : "beforeObj",

  objShow : function(){

   }

 };


였다면 ES6에서는


var beforeObj = {

name :"newObj",

objShow(){


}

}


와같이 사용이 가능하다는 점입니다. 그렇기 때문에 render 도 사실은


var render = function(){} 또는 render : function(){} 이어야 할것 같지만 ES6문법 에 의해서


render(){


}가 될수 있습니다. 




그리고 render() 함수에 대해서 보자면 리액트에서는 render라는 함수를 통해서 UI 렌더링 기능을 진행한다고 합니다


렌더링은 JSX라는 문법을 통해서 html 과 매우 유사한 형태로 반환되지만 실제적으로는 그렇진 않습니다.


' ' + ' 형식으로 추가하는것도 아니고 그냥 생 html처럼 보이거든요


js문법도 물론 아니고  리액트 문법이라 보는것이 좀더 맞겠네요 렌더링 시( render 함수 호출 시 ) 에는


render 에 있는 JSX들을 계속 반복하며서 HTML을 만들기 위한 오브젝트를 생성합니다.


오브젝트가 전부 생성되면 해당 정보를 통하여 HTML 을 마크업 그리고 실제 DOM 에 붙여서 화면에 나타나게 합니다.


render ()호출 - HTML를 그리기위한 정보 객체 생성 (내부에 다른 Component가 있을 경우다시 돌면서 생성)

-> 해당 정보로 HTML 맠업 생성 -> 실제 DOM 에 붙임













1. 리액트를 다루는 기술  (책) - 김민준 저자


2. VSCode(에디터)

     -> 관련 플러그인

> ESLint // 문법 정리 *

> Relative Path // 상대 경로 작성 도구 

> Guides   // 들여쓰기 가이드 라인 

> Reactjs code snippets(Karypidis) // 리액트 관련 스니펫 모음 제작자 Charalampos Karypidis *

> React-beautify // 리액트 코드 정리 




3. Node.js with NPM (노드는 10버전)

> create-react-app 설치   -g 로 


4. git 





* 코드 스니펫이 뭔가 해서 찾아봤습니다.


js에서 


arr에는 forEach 로 가져올수 있는 것처럼


arr.forEach(function(item,index,arr){


}); 를 입력해야되는데


arr.f 엔터 치면 저 위에부분들이 조각처럼 가지고있다가 한번에 나오는 기능을 말합니다.





global 옵션으로 create-react-app 설치 


npm i -g create-react-app

터미널에 create-react-app basic-react


** basicReact 라고 했더니 



Could not create a project called  ''  because of npm naming restrictions 

** name can no longer contain capital letters

네;; 대문자를 사용 못한답니다.


그래서 소문자로 만 하셔야 됩니다.


basic-react로 변경 



입력 후 


cd basic-react


npm start 시


리액트 화면 확인



신나네요 리액트 할 생각에 




+ Recent posts