브라우저의 이해 #1 Reflow, Repaint에 대하여 알아봅니다.
React Native #1 React 후려치기
2018-11-07
Explanation
그래도 오랜 시간을 사용한 게 WordPress, Angular(v1), React인데, 막상 블로그를 보니 관련해서 글을 쓴 게 얼마 없네요. 지금 WordPress나 Angular 관련해서 글을 쓰기엔 너무 늦은 감이 있는거 같고…
그러던 중 최근에 React Native를 공부해 보면서 이번에는 글로 좀 남겨보려 해요. 그리고 글을 쓰려다보니 React Native가 React와 관련이 많아서 첫번째 글을 짧게나마 생각해 본 React의 중요하다 생각되는 부분을 정리해보려 합니다.
글 재주가 없어서, 우선 예제로 사용할 코드를 미리 만들어 놓고 코드를 보면서 이야기하려 합니다. 그리고 Webpack, 핫로더, Babel 에 관한 부분은 생략하고 React에 관해서만 적어보려 합니다.
예제 소스: https://github.com/falsy/blog-post-example/tree/master/react-key-theorem
이제 그만 본론으로,
제가 생각하는 React의 중요한 부분은 component, state, props, life-cycle 정도 인거 같아요.
간단하게 이야기를 해보자면 ‘독립적으로 역할을 하는 단위’ 인데요. React는 그런 작은 단위들의 모임이이고 그 모임, 구조를 얼마나 잘 만드는지가 중요한거 같아요.
예제로 만든 소스는 총 Person, Arm, Finger, Leg 이렇게 4개를 만들었답니다.
가장 밖에 Person 이라는 컴포넌트가 있고 그안에 Arm, Leg 라는 컴포넌트가 있으며 Arm 이라는 컴포넌트 안에는 Finger 라는 컴포넌트가 있도록 되어 있습니다.
state와 props에 대해 자세히 알아보다 보면 정말 어려운 말들이 많은데요, 역시 간단하게 컴포넌트 내의 상태변수라고 생각하면 될거 같아요. 예전에 Angular는 Two way binding이고 React는 One Way binding이다 뭐 이런 이야기를 했었는데요, React의 state 값은 호출과 셋이 각각 다른, 하나의 길로 되어있다고 생각하면 될 거 같아요.
1 2 3 4 |
// 호출은 ... const stateData = this.state.data; ... |
1 2 3 4 5 6 |
// 셋은 ... this.setState({ data: 'new data' }); ... |
예제 코드를 보자면..
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 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
// ./src/components/Person.js ... class Person extends Component { constructor(props) { super(props); // Person 이라는 Componet에 초기 상태 변수를 선언합니다. this.state = { fingerNo: 1, skin: 'yellow' }; } ... changeSkin() { // 새로 셋할 값을 정하고 const newSkin = this.state.skin === 'yellow' ? 'black' : 'yellow'; // 새로 정한 값으로 셋합니다. this.setState({ skin: newSkin }); // setState가 샐행되어 this.state.skin 값이 변화하면 아래의 render()의 {this.state.skin} 값이 새로운 값으로 출력됩니다. } ... render() { return ( <div id={'body'}> ... // 상태 변수 값이 출력됩니다. <p>피부색은 {this.state.skin}</p> ... // 버튼을 클릭하면 this.changeSkin() 함수를 호출합니다. <button onClick={this.changeSkin.bind(this)}>피부색 바꾸기</button> ... </div> ); } } export default Person |
간단하게 props는 state 보다는 좀 더 큰 범위의 상태 변수인데요, 다음 글에서 Redux와 관련해서 글을 쓸 예정인데, 우선 그 전까지 props는 component의 상속 관계에서 부모가 자식에서 부모의 상태 값을 전해 받은 값이라고 생각할 수 있을 거 같습니다.
1번에서 이야기 했듯이 React는 많은 component의 모임에 또 그 모임의 집합이고 그 component 간의 상태를 공유할 필요가 있고 그렇게 사용되는 것이 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 29 30 31 32 33 34 35 36 37 38 |
// ./src/components/Person.js ... class Person extends Component { constructor(props) { super(props); this.state = { fingerNo: 1, skin: 'yellow' }; } ... changeFinger() { // 새로운 값을 설정하고 const newFingerNo = this.state.fingerNo > 4 ? 1 : this.state.fingerNo + 1; // this.state.fingerNo 라는 상태변수에 새로운 값을 설정합니다. this.setState({ fingerNo: newFingerNo }); } render() { return ( <div id={'body'}> ... // 상태 변수 값을 자식 Arm 이라는 컴포넌트에 전달합니다. <Arm fingerNo={this.state.fingerNo} /> ... // 버튼을 클릭하면 상태 변수의 값을 바꿉니다. <button onClick={this.changeFinger.bind(this)}>손가락 바꾸기</button> </div> ); } } export default Person |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
// ./src/components/Arm.js ... class Arm extends Component { constructor(props) { super(props); } render() { return ( <div id={'arm'}> ... // 부모에게 전달 받은 this.props.fingerNo 값을 다시 자식 컴포넌트인 Finger에게 전달합니다. <Finger fingerNo={this.props.fingerNo} /> </div> ); } } ... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
// ./src/components/Finger.js ... class Finger extends Component { constructor(props) { super(props); } render() { return ( <div id={'finger'}> // 부모에게 전달 받은 this.props.fingerNo를 출력합니다. {this.props.fingerNo}번째 손가락 </div> ); } } ... |
위 예제 코드를 보면 부모인 Person 컴포넌트에서 button의 클릭 이벤트를 통해서 Person 컴포넌트의 상태변수가 변경되고 그 변경된 값이 자식 컴포넌트인 Arm 그리고 그 자식 컴포넌트인 Finger에게 전달되어 Finger 컴포넌트에서 해당 내용이 출력되는 것을 확인 할 수 있습니다.
그리고 추가적으로..
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
// ./src/components/Finger.js import React, { Component } from 'react'; import PropTypes from 'prop-types'; class Finger extends Component { constructor(props) { super(props); } render() { return ( <div id={'finger'}> {this.props.fingerNo}번째 손가락 </div> ); } } Finger.propTypes = { fingerNo: PropTypes.number }; export default Finger |
위 코드를 보시면 ‘prop-types’라는 라이브러리를 불러와서
1 2 3 |
Finger.propTypes = { fingerNo: PropTypes.number }; |
이렇게 props의 타입을 검증하는데요. 이런 검증이 없다고 해서 동작하지 않는 것은 아니지만, 프로젝트가 커지다 보면 화두가 되는 건 역시 협업 부분인 거 같아요.
코드의 버그를 발견할 수 있게 하고 협업에서 코드의 이해를 돕기 때문에 처음부터 작성하는 습관을 들이면 좋을 거 같아요.
‘propTypes’은 타입 체크 뿐만아니라 디폴트 값을 설정하거나 검증의 기능도 할 수 있습니다. 보다 자세한 정보는 아래의 링크를 참고하시면 좋을 거 같아요.
https://reactjs.org/docs/typechecking-with-proptypes.html
그디어 마지막 라이프사이클(생명주기?)입니다. 역시 예제 코드를 보면..
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 |
// ./src/components/Finger.js ... class Person extends Component { constructor(props) { super(props); this.state = { fingerNo: 1, skin: 'yellow' }; } componentDidMount() { document.getElementById('body').style.background = '#f5f5f5'; } ... render() { return ( <div id={'person'}> <h1>사람</h1> ... </div> ); } ... |
위 코드에서 componentDidMount()에 해당하는 부분을 이야기 하는 건데요, ‘componentDidMount’는 render()로 DOM이 출력이 된 다음에 실행되는 함수에요. 저는 예로 DOM의 엘리먼트를 접근해서 스타일을 수정했습니다.
‘constructor'(생성자)에서는 아직 해당 컴포넌트의 DOM이 그러지기 전이기 때문에 엘리먼트에 접근할 수 가 없어요. 그렇기 때문에 ‘componentDidMount’ 메서드에서 설정을 해 줄 수 있답니다.
간단하게 Life-cycle에 관련해서 이해를 돕기위해 ‘componentDidMount’ 메서드만 작성했는데요, 그밖에 DOM이 렌더링되기 전, 또는 상태 변수가 변하는 시점 등.. 의 몇가지 메서드가 더 있답니다. 자세한 정보는 아래의 링크를 참고하시면 좋을 것 같습니다.
https://reactjs.org/docs/react-component.html
사실.. React에 관해서는 너무나도 깊이 있고 친절하게 설명해주신 글들이 참 많답니다. 제가 본 곳 중에서는 아래 두 블로그가 가장 검색도 많이 되고 글도 좋았던 거 같아요.
React에 관해 좀 자세히(바르게) 알고 싶은 분들은 참고하시면 좋을 거 같아요 :)
https://velopert.com/reactjs-tutorials
https://www.zerocho.com/category/React
글에는 잘못 설명된 부분이 많이 있을 수 있습니다. 가볍게 읽어주시고 잘못된 부분은 알려주세요~