본문 바로가기
관리자

Programming-[Frontend]/ReactJS

React / 기초2 / State, props와 클래스 컴포넌트 작성 : dark mode 구현해보기

728x90
반응형
이전글

React / 기초1 / React 설치, JSX, component

 

 


 

1. State

앞선 글에서 작성한 바와 같이, 클래스 컴포넌트는 상태를 변경할 수 있는 요소를 갖고 있는데, 그것이 바로 state 이다. 클래스 컴포넌트 안에서 state를 정의하고, 이벤트 등에서 활용하게 된다.

 

state는 직접적인 수정이 불가하고 반드시 setState라는 메서드를 이용해서만 변경해야한다.

 

가장 많이 사용되는 예제인 Counter 만들기를 해보자.

 

Counter 코드

 

 

1-1. State 부분만 집중해서 보기

다른 부분들은 다음 섹션에서 하나씩 기술할 것이다.

 

우선은 6번줄을 보면, this.state로 {count : 0} 이라는 객체가 정의되어 있음을 볼 수 있다. 사용자의 명령에 따라 반응할 정보를 객체 형태로 만들어 놓고, 초기값을 지정해 놓은 것이다. count 뿐 아니라 다른 값들도 객체 형태로 추가하여 만들 수 있고, 단순히 key: value 형태가 아니라 key : { key: value} 와 같이 객체를 중첩하여 깊이가 있는 구조로 만들 수도 있다.

 

13번 줄에서 countUp이라는 메서드를 구현하였다. 내부에 setState를 작성하여 count 객체의 값을 1 늘려주는 모습을 볼 수 있다. 단순히 setState 안에 count : this.state.count + 1 이라고 구현할 수도 있으나, react 공식문서에서는 비동기 함수로 setState를 구성할 것을 권장하고 있다. (공식문서 - 주요개념 - 5. State & Lifecycle 부분 / ko.reactjs.org/docs/state-and-lifecycle.html)

이것은 this.state와 추후에 기술할 this.props가 비동기적으로 한번에 업데이트 될 수 있기 때문에 연산을 즉각적으로 할 수 없는 경우를 방지하기 위해서라고 한다.

 

변경을 원하고자하는 객체(count)의 key를 작성하고, value 값으로 변경되기를 원하는 값 또는 논리를 작성하는 방식임을 기억하자!

 

30번 줄에서 this.state.count를 표시하도록 하였고, 31번 줄에서 onClick 이벤트를 만들어서 버튼이 클릭되면 countUp 메서드가 실행되도록 하였다. "버튼 클릭 -> countUp 메서드 실행 -> setState로 state 변경 -> 변경된 this.state.count가 웹페이지에 렌더링" 되는 방식인 것이다.

 

 

 

 


 

2. 클래스 컴포넌트 개요 : 코드 뜯어보기

 

다음으로 props에 대한 이해를 위해서 클래스 컴포넌트의 작성 방식 및 원리를 이해할 필요가 있다. 하나씩 코드를 뜯어서 살펴본다.

 

2-1. constructor

 

 

this.state

Constructor는 Javascript ES6 문법에서의 class와 유사한 점이 많다. 컴포넌트를 class로 정의하면서 constructor를 만들어 주었다. extends React.Component, props 부분은 다음 섹션에서 살펴보도록 하고, 일단 this.state라고 작성된 부분을 살펴보자. 당연히 여기서 this는 App 컴포넌트를 가리킨다. 이전 섹션에서 언급한 바와 같이 state를 정의해주는 문법이라고 생각하면 된다.

 


 

this binding

this.countUp = this.countUp.bind(this) 라는 부분은 countUp 메소드의 this를 App으로 바인딩 해주는 부분이다. 

(?)onClick으로 해당 메서드를 호출 시에 함수 호출의 형태가 되어 this가 App 컴포넌트와의 연결 고리를 잃게 되는데, 이것을 다시 바인딩 하는 것이다. (부정확)

 

>참조 : 정확한 부분은 아래 링크에서 읽기!

 

 


 

 

2-2. render()

 

 

React 컴포넌트가 실제로 웹페이지에 표현하고 싶은 내용을 적는 부분이다.(렌더링)

 

return 문을 작성해줘야 하는데, 여러 줄을 리턴 하고 싶을 때는 소괄호()를 이용하여 작성해준다.

처음에 배운 바와 같이, 하나의 태그만을 리턴해야함을 잊지 말자!

 

onClick 이벤트

onClick 이벤트에 constructor에서 작성한 메소드를 할당해주어 버튼이 클릭됬을 때 해당 메서드가 실행되게 한다. 지금 당장 배운 이벤트는 onChange 이벤트도 있는데, 주로 input tag에 달아주어서 사용자가 글자를 입력하면 해당 이벤트가 실행되게 하는 방식이다. 참고만 하고 넘어가자.

>>bind

onClick 이벤트에 this.countUp 형태로 할당해주었는데, 이것은 1.constructor - this binding 부분에서 작성된 this.countUp = this.countUp.bind(this) 부분이 있어서 정상작동 되는 것이다.

>>>constructor 부분에 this binding 부분을 적지 않고, onClick 이벤트에 할당 시 this.countUp.binding(this) 라고 작성해줘도 된다!

 

 

엘리먼트의 textContent 가져오기

return {props.children}은 해당 컴포넌트의 text를 반환한다.

 


 

 

3. import export

 

 

3-1. import

react에 내장된 컴포넌트를 import 해왔다.

(?) 정확히 모르겠지만, react에서 클래스 컴포넌트를 사용하기 위해서 내장 컴포넌트를 import 해오는 것 같다.

그리고, 이것을 extends 해와서 컴포넌트로 사용한다. 상속받는 것인데, 다음 섹션에서 다루도록 하자.

 

내장된 react 컴포넌트 뿐만 아니라, 본인이 작성한 여러가지의 컴포넌트들을 사용하고 싶다면 모두 import 해와야 한다.

 

여러 컴포넌트 import 해오기!

 

3-2. export

작성한 컴포넌트를 다른 컴포넌트에서 import 해와서 사용하기 위해서 export가 필요하다. export 문법에 대한 내용은 

모듈 글에서 복습! 

 

 


 

4. Props

 

Props는 Javascript ES6의 클래스의 this와 유사한 개념이다. props 안에 해당 컴포넌트에서 지정하는 state와 메서드들이 객체 형태로 담기게 된다. constructor에 props를 작성하고, super(props) 구문으로 부모 컴포넌트로부터 state와 메서드들을 상속받아올 수 있다.

 

다음 예제를 통해서 부모-자식 컴포넌트간 props 상속 및 props의 작성 조건에 대해서 상세히 알아보자.

props 뿐 아니라 react 프로그래밍을 어떻게 해야하는지 구체적으로 알 수 있다.

버튼을 클릭하면 DarkMode로 전환하는 기능을 가진 react 웹페이지이다.

 

DarkMode 전환 웹페이지. 실제 작동 영상은 다음 글 Lifecycle 부분에서 확인할 수 있다.

 

 

 

App.js 파일

 

 


 

4-1. 부모 컴포넌트 : App.js 살펴보기

위 코드는 메인이 되는 App 컴포넌트의 코드이다. 하나씩 뜯어보자.

 

1. (6~7번줄) constructor, super

constructor에서 props를 파라미터로 지정해주었고, super(props)를 통해서 props를 상속받았다. React의 내장 컴포넌트인 React.Component에서 컴포넌트를 작성하는데 필요한 객체를 props로 상속받아 온 것이다. 컴포넌트를 작성하는데 필요한 속성 및 메소드를 받아오는 것이므로, 항상 constructor의 가장 윗부분에 작성해주어야 한다.

 

2. (8~10번줄) this.state

여기서 '변할 수 있는, 변할 지도 모르는' state 변수값을 지정해주었다. 다크모드는 'True'값을 가질 때 css가 변경되게 할 것이므로 일단 'false'로 지정해놓았다.

 

3. (14~17번줄) modeChange 메서드 : this.setState

다크모드를 전환하기 위한 메서드를 정의해주었다. 앞선 글에서 설명한 바와 같이 비동기 처리를 위해서 콜백함수 형태로 setState 메서드를 작성해주었다. "isDarkMode : !this.state.isDarkMode" 라고 작성하였는데, 이것은 이후 코드 부분에서 onClick 이벤트가 발생하면 isDarkMode라는 state값을 반대값(True or False)으로 만들고자 함이다.

 

4. (24번줄) 조건문

삼항연산자 형태로 조건문을 작성하였고, 'isDarkMode'의 state에 따라서 해당 class의 className이 변경되도록 하였다. 'Board'라는 공통 class는 공유하되, 'dark'와 'light'라는 class는 변경되도록 했다.

 

5.(28~31번줄) 자식 컴포넌트 적용

아래에 기술할 자식 컴포넌트(DarkModeBtn)를 삽입해주었다.

 

>>29, 30번줄 : 자식컴포넌트에 전달할 props를 지정한다

isDarkMode라는 state와 modeChange라는 메서드를 전달해주는 부분을 볼 수 있다. 좌변은 내가 자식 컴포넌트에서 사용할 변수 명이 되고, 우변은 어떤 컴포넌트를 가져갈 것인지를 지정하는 부분이다. 자식 컴포넌트에 state와 메서드를 전달하여 자식 컴포넌트에서 부모 컴포넌트의 메서드를 활용할 수 있을 뿐 아니라 state를 바꿔줄 수 있게 된다.

 

자식 컴포넌트 또한 각자의 state를 가질 수 있다. 그러나 만약 부모 컴포넌트 아래에 여러 개의 자식 컴포넌트가 있어서 state를 통합적으로 관리해야한다면, 자식 컴포넌트는 수정이 불가하도록 props만 상속 받도록 만들고, state는 부모 컴포넌트에서 통합적으로 관리하도록 작성할 수 있다. 각 자식 컴포넌트에 있는 state를 부모 컴포넌트에서 통합적으로 관리되도록 하는 것을 state 끌어올리기, state lift-up 이라고 한다.

 

props는 읽기 전용(불변적)이여야 하고, 순수함수로서만 작성되어야 한다. 순수함수라 함은, 파라미터로 받은 인자를 수정하면 안된다는 것이다. 자세한 설명은 공식문서를 참조하자.

ko.reactjs.org/docs/components-and-props.html

>> 원본으로 받은 props를 변경하면 안되므로, 데이터를 변경하고 싶을 때는 .push가 아닌 .concat, spread operator 등과 같은 새로운 객체를 반환해주는 메서드를 활용해야 한다.

 

특히, 깊이가 있는 object의 경우 spread operator를 활용하여 값을 바꿔주는 것을 이용한다. 아래는 Javascript 예시이다.

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
let object = {
  movies : 'Titanic',
  books : {
    sciFi : "Artemis",
    computer : {
      Data_Structure : "2020",
      Algorithm :"2021"
    }        
  }
}
 
let changed = {
...object,
  books : {
    ...object.books,      
    computer : {
      ...object.books.computer,
        Algorithm : "2020"
    }
  }
 
//changed 조회
changed
 
{movies: "Titanic", books: {…}}
books:
computer:
Algorithm: "2020"
Data_Structure: "2020"
__proto__: Object
sciFi: "Artemis"
__proto__: Object
movies: "Titanic"
__proto__: Object
cs

 

기존 "object"에서 spread operator를 활용해서 새로운 객체인 "changed"를 생성하고, 안쪽에 있는 Algorithm의 값을 바꿔주었다. React에서도 이를 활용하여 state를 변경해줄 수 있다.

 

 

React에서 spread operator 활용

 

 

 


 

4-2. 자식 컴포넌트 : DarkModeBtn.js

 

자식 컴포넌트에는 <button> 태그를 만들고, className 및 onClick 이벤트를 달아주었다. 컴포넌트 자체의 state가 필요없으므로 함수 컴포넌트 형태로 작성하였다.

 

해당 예제에서는 props.modeChange를 바로 참조하는 형태로 onClick 이벤트를 할당했으나, 만약 fetch 등과 같이 비동기적으로 처리해야되는 상황이라면, 이 부분을 콜백함수 형태로 작성해주면 된다.

 

DarkModeBtn.js 파일

 

 

 


 

4-3. key 문제

 

리턴되는 각 엘리먼트에 key값을 지정하여 전달해주어야 한다. key값을 따로 지정해주지 않으면 최후의 수단으로 react가 index를 참조하여 key값을 달아주긴 하지만, 오류가 생기지 않을려면 key값을 지정해주는 것이 좋다.

(참조 : React 공식문서 : 리스트와 Key - ko.reactjs.org/docs/lists-and-keys.html#gatsby-focus-wrapper)

 

 

key를 추가해주는 예제

 

map 메서드를 사용하여 chars의 각 요소를 text로 갖는 <p> 태그 엘리먼트를 만들어주는 예제이다. key 값을 'i'로 받아와서 각 <p> 태그에 달아주도록 하였다.

> 보통 데이터를 외부에서 fetch 등으로 받아오면, 각 데이터가 가진 고유의 id나 이름 등을 이 key로 지정한다.

 

 

 


 

 

다음글

다음 글에서 컴포넌트의 Lifecycle(생명주기)에 대해서 알아본다.

React / 기초3 / LifeCycle

 

 

 

 

 

 

728x90
반응형

'Programming-[Frontend] > ReactJS' 카테고리의 다른 글

React / Router  (0) 2020.10.19
React / Hook / 개요  (0) 2020.10.18
React / 기초4 / 이벤트 처리하기  (0) 2020.10.06
React / 기초3 / LifeCycle  (0) 2020.10.06
React / 기초1 / React 설치, JSX, component  (0) 2020.10.05