State는 props와 유사해 보이지만 State는 컴퓨터 내부에서 사용하는 자료이므로 비공개 자료이다.
그리고 State는 데이터를 수정할 수 있는 공간이라고 할 수 있다.
즉, props가 component에 정보를 전달한 후 DOM으로 호출된다고 할 수 있다.
이때 component 안에 들어 있는 것이 State이다. 따라서 State는 컴포넌트에 의해 완전히 제어된다.
컴포넌트 캡슐화
메인 어플리케이션으로부터 독립되어 있는 컴포넌트를 의미합니다.
이를 통해 컴포넌트 내부에서 발생하는 업데이트, 테스트 케이스, 재사용에 용이하게 컴포넌트를 설계할 수 있습니다.
Clock 컴포넌트를 재상요하고 캡슐화하는 방법을 알아보도록 하겠습니다.
함수에서 클래스로 변환하기
다섯 단계로 Clock과 같은 함수 컴포넌트를 클래스로 변환할 수 있습니다.
1. React.Component 를 확장하는 동일한 ES6 class를 생성한다.
2. render() 라고 불리는 빈 메서드를 추가한다.
3. 함수의 내용을 render() 안으로 옮긴다.
4. render 안에 있는 props를 this.props로 변경한다.
5. 남아있는 빈 함수 선언을 삭제해준다.
이렇게 되면 이제 함수가 아닌 클래스로 정의됩니다.
render 메서드는 업데이트가 될 때마다 호출되지만 같은 DOM노드로 을 렌더링 하는 경우 Clock 클래스의 단일 인스턴스만 사용됩니다.
이때의 장점은 로컬 state와 생명주기에서 사용하는 메서드 같은 부가적인 기능을 사용할 수 있게 된다는 것입니다.
클래스에 로컬 State 추가하기
date를 props에서 state로 이동하도록 하겠습니다.
1. render() 메서드 안에 있는 this.props.date를 this.state.date로 변경합니다.
2. 초기 this.state를 지정하는 class constructor를 추가합니다.
= 여기서 props를 기본 constructor에 전달하는 방법을 잘 살펴야 합니다.
클래스 컴포넌트는 props로 기본 constructor를 호출해야 합니다.
3. 이후 render을 통해 <Clock />을 불러줍니다.
이렇게 한 후 앱을 키면, 현재 시각이 UI에 나타납니다.
하지만 업데이트 되는 동적인 화면은 볼 수 없습니다.
따라서 Clock이 스스로 업데이트할 수 있도록 만들어 보겠습니다.
생명주기 메서드를 클래스에 추가하기
컴포넌트가 많이 있는 어플리케이션에서 컴포넌트가 삭제될 때
해당 컴포넌트가 사용중이던 리소스를 확보 하는 것은 중요합니다.
Clock이 처음 DOM에서 렌더링 될 때마다 타이머를 설정하도록 하겠습니다.
이것을 React에서는 '마운팅'이라고 부릅니다.
또한 Clock에 의해 생성된 DOM이 삭제될 때마다 타이머를 해제하도록 하겠습니다.
컴포넌트 클래스에서 특별한 메서드를 선언하여 컴포넌트가 마운트 되거나 언마운트 될 때
일부 코드를 작동시킬 수 있습니다. 이러한 메서드들을 '생명주기 메서드'라고 부릅니다.
componentDidMount() 메서드는 컴포넌트 출력물이 DOM에 렌더링 된 후에 실행됩니다.
여기서 타이머를 설정하도록 합니다.
this(this.timerID)에서 어떻게 타이머 ID를 저장하는지 잘 살펴봐야 합니다.
this.props가 React에 의해 스스로 설정되고 this.state가 특수 의미가 있지만
타이머 ID와 같이 데이터 흐름 안에 포함되지 않는 어떤 항목이 있다면
클래스에 수동으로 부가적인 필드(공간)를 추가해도 됩니다.
componentWillUnmount() 생명 주기 메서드 안에 있는 타이머를 분해하도록 하겠습니다.
그다음 Clock 컴포넌트가 매 초 작동하도록 하는 tick()이라는 메서드를 구현해 보겠습니다.
이것은 컴포넌트에서 단순히 state가 아니라 계속 업데이트되는 자료이기에 this.setState()를 사용합니다.
이제 결과 코드를 보도록 하겠습니다.
이 결괏값을 통해 시계는 매초 업데이트된 상태로 UI에 나타나게 됩니다.
1. <Clock />가 ReactDOM.render()로 전달되었을 때
React는 컴포넌트의 constructor를 호출합니다.
Clock이 현재 시각을 표시해야 해서 현재 시간이 포함된 객체로 this.state를 초기화합니다.
2. React는 Clock 컴포넌트의 render() 메서드를 호출합니다.
이를 통해 React는 화면에 표시되어야 할 내용을 알게 됩니다.
그다음 React는 Clock의 렌더링 출력 값을 일치시키기 위해 DOM을 업데이트합니다.
3. 출력 값이 DOM에 삽입되면 리액트는 componenetDidMount()
생명주기 메서드를 호출합니다. 그 안에서 Clock 컴포넌트는 매초 나타내는
tick() 메서드를 호출하기 위한 타이머를 설정하도록 브라우저에 요청합니다.
4. 브라우저가 tick() 메서드를 호출하는데 그 안에서 Clock 컴포넌트는
setState()를 통해 현재 시각으로 계속 업데이트를 진행합니다.
이 호출로 인해 리액트는 state가 변경된 것을 인지하고 화면에 표시될
내용을 알기 위해 render() 메서드를 다시 호출합니다.
이때 render 안의 this.state.date 가 달라지고 렌더링 출력 값은 업데이트된 시간을 포함합니다.
이에 따라 리액트는 DOM을 업데이트합니다.
5. Clock 컴포넌트가 DOM으로부터 한 번이라도 삭제된 적이 있다면
리액트는 타이머를 멈추기 위해 componentWillUnmount() 메서드를 호출합니다.
State 바르게 사용하기
- 직접 state를 수정하지 않는다.
대신 setState를 사용합니다. this.state를 지정할 수 있는 공간은 constructor 안입니다.
- state 업데이트는 비동기적일 수도 있다.
리액트는 성능을 위해 setState() 호출을 단일 업데이트로 한꺼번에 처리할 수도 있습니다.
this.props와 this.state가 비동기적으로 업데이트될 수 있기에 다음 state를 계산할 때 해당 값에 의존하면 안 됩니다.
- state 업데이트는 병합된다.
setState()를 호출할 때 리액트는 제공한 객체를 현재 state로 병합한다.
병합은 얕게 이뤄지기에 this.setState({comments})는 this.state.posts 에 영향을 주진 않지만 this.state.comments는 대체할 수 있습니다.
데이터의 흐름은 아래로 흐른다
부모나 자식 컴포넌트 모두 특정 컴포넌트가 유상 태인지 무상 태인지 알 수 없을 때,
그것들이 함수인지 클래스인지 크게 상관을 둘 필요가 없습니다.
이것은 state의 로컬, 즉 캡슐화 때문에 생기는 일입니다.
state가 소유하고 설정한 컴포넌트 이외에는 어떤 컴포넌트에도 접근할 수 없습니다.
컴포넌트는 자신의 state를 자식 컴포넌트의 props로 전달할 수 있습니다.
그리고 사용자 정의 컴포넌트에도 사용 가능합니다.
<p> It is { this.state.date.toLocaleTimeString() }</p> - 자신의 state를 자식 컴포넌트 props로 전달
<FormattedDate date = {this.state.date} /> - 사용자 정의 컴포넌트에 적용
FormatteDate 컴포넌트는 date를 자신의 props로 받았지만
이것이 Clock의 state로부터 온 것인지 props에서 왔는지 수동인지 알 수 없습니다.
일반적으로 이것을 "하향식(top-down)" 또는 "단방 향식" 데이터 흐름이라고 합니다.
모든 state는 항상 특정한 컴포넌트가 소유하고 있으며 그 state로 파생된
UI나 데이터는 오직 트리 구조 내에서 자신의 아래에 있는 컴포넌트에만 영향을 미칩니다.
트리 구조가 props의 폭포라면 각 컴포넌트의 state는 임의의 점에서 만나지만
동시에 아래로 흐르는 부가적인 수원(water source)이라고 할 수 있겠습니다.
모든 컴포넌트는 독립적이고 각각 업데이트를 하게 됩니다.
리액트 앱에서 컴포넌트가 유상태 또는 무상태에 대한 것은 시간이 지남에 따라
변경될 수 있는 구현 세부사항으로 간주합니다.
유상태 컴포넌트 안에서 무상태 컴포넌트를 사용할 수 있으며 그 반대도 사용 가능합니다.
참고자료 : https://ko.reactjs.org/docs/state-and-lifecycle.html
State and Lifecycle – React
A JavaScript library for building user interfaces
ko.reactjs.org
'Today Learning _' 카테고리의 다른 글
Part 12-6. 리액트 살펴보기(조건부 렌더링) (0) | 2020.03.19 |
---|---|
Part 12-5. 리액트 살펴보기(이벤트 처리하기) (0) | 2020.03.18 |
Part 12-3. 리액트 살펴보기(Components 와 Props) (0) | 2020.03.16 |
Part 12-2. React 살펴보기(엘리먼트 렌더링) (0) | 2020.03.14 |
Part 12-1. React 살펴보기(JSX의 이해) (0) | 2020.03.14 |