블로그 내용은
Programming with Mosh React Tutorial for Beginners [React js]
을 공부하는 과정에서 작성되었습니다.

<작성 코드>

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

class Counter extends Component {
    state = {
        count : 0,  
        tags: ["tag1", "tag2", "tag3"]   
    };
    render() { 
        return (
            <div>                              
                <span className={this.getBadgeClasses()}>{this.formatCount()}</span>
                <button onClick={this.handleIncrement} className="btn btn-secondary btn-sm">Increment</button>
                <ul>{this.state.tags.map(tag => <li key={tag} >{tag}</li>)}</ul>
            </div>
        );
    }
    getBadgeClasses() {
        let classes = "badge m-2 badge-";
        classes += this.state.count === 0 ? "warning" : "primary"; //엘로우 블루
        return classes;
    }
    formatCount() {
        const {count} = this.state; 
        const x = "ZERO";
        return count === 0 ? x : count;
    }
    handleIncrement = () => {    
        console.log("Increment Clicked", this);
        this.setState({count: this.state.count + 1});
    }
}
export default Counter;

Composiong Components

tags: ["tag1", "tag2", "tag3"]  
 <ul>{this.state.tags.map(tag => <li key={tag} >{tag}</li>)}</ul>

앞선 코드에서 위 내용을 제거해줍시다.

리액트를 효율적으로 사용하기 위해서 부모 컴포넌트 (Counters)을 생성하고 자식 컴포넌트들을 연결시켜줍니다.(Counter)

(import와 파일생성하는 방법은 앞 블로그 내용 참고)

//Counters에 counter을 연결한다.
import React, { Component } from 'react';
import Counter  from './counter';

class Counters extends Component {
    state = { 
        counters: [
            {id:1, value: 0},
            {id:2, value: 0},
            {id:3, value: 0},
            {id:4, value: 0}
        ]
     };
    render() { 
        return (<div>
            { this.state.counters.map(counter => <Counter key={counter.id}/>) }
        </div>);
    }
}
 
export default Counters;

Passing Data to Components

data를 컴포넌트 사이에서 자유롭게 이용하기 위해서는 props를 이해하고 넘어가야합니다. props는 부모에서 자식에게 넘겨주는 객체입니다. 자식은 넘겨받은 props를 오직 읽는 용도로만 사용할 수 있고 수정은 할 수 없습니다.

<Counter key={counter.id} value={counter.value} />) }

Counters의 render()를 위와 같이 수정하였습니다. 이렇게 하면 {counter.value}를 value라는 이름으로 Counter에 전달하는 것입니다. 그리고 Counter을 다음과 같이 편집합니다

state = {
       count : this.props.value,
    };

value는 Counters로 부터 받은 값이고 자식 컴포넌트에서 사용할 수 있습니다. 여기서 key는 특수한 속성으로 props가 아닌점을 주의해야합니다. 구분을 위한 유니크한 값입니다.

앞으로 Counter의 count를 모두 value로 변경해줍시다. 용어 혼동이 적도록 하기 위함입니다.

Props vs State

위에서 Props에 대해 간단히 설명했으니 이제 앞에서 살펴본 State와 비교해 봅시다.

state는 local과 private한 성격을 갖는 data입니다. 따라서 다른 컴포넌트에서 state에 함부로 접근할 수 없습니다. 반면에 props는 개발자가 컴포넌트에 주는 data입니다. 즉 props는 컴포넌트를 넘나들 수 있습니다.

<Counter key={counter.id} value={counter.value} />) }

우리가 앞에 사용한 이 코드는 Counters의 state값을 Counter의 props로 넘기는 코드입니다. 자식인 Counter에서는 이것을 받아와 본인의 state로 저장해서 사용할 수 있습니다. 여기서 중요한 것은 State는 local과 private한 성격이기 때문에

1. 오직 본인의 state는 setState()를 사용해서만 변경이 가능하고
2. 다른 컴포넌트의 state는 변경할 수 없다는 점입니다.

Raising and Handling events react

이제 Delete를 위한 버튼을 만들려고 합니다.
우리가 여기서 생각해 볼 것이 'Delete 메서드를 어디에 구현시킬까' 입니다? Counter일까요? Counters일까요?

앞서 state를 살펴봤기 때문에 조금만 생각해보면 Counters에 메서드를 구현하는 것이 맞다는 생각이 드실겁니다. state의 성격은 다른 컴포넌트에서는 수정이 불가능해서 오직 Counters에서만 수정이 가능합니다.

그렇기 때문에 우리는 인터페이스인 button을 클릭하면
부모 컴포넌트 Counters에서 내용을 수정하고, 수정한 내용을 다시 Counter로, 다시 render시키는 작업을 수행해야만 합니다 이것을 Raising and Handling라고 합니다.

//Counter
 <button onClick={this.props.onDelete} className="btn btn-danger btn-sm m-2">Delete</button>

Counter의 render에 코드를 추가합시다.

 //counters render()
{ this.state.counters.map(counter => 
            <Counter 
            key={counter.id} 
            onDelete = {this.handleDelete}
            value={counter.value}  />) }
 handleDelete = () => {
 	console.log("Event Handler Called");
    }

Counters의 render은 위와 같이 편집하고 컴포넌트에서는 메서드를 추가하고 실행시켜서 제대로 연결됐는지 확인합시다!

Updating the State

연결이 제대로 동작하는지 확인되었기 때문에 이제
Delete 버튼을 동작시켜 봅시다.

//counters
 handleDelete = counterId => {
        const counters = this.state.counters.filter(c =>c.id !== counterId );
        this.setState({counters:counters}); 
        //key = value 같을때 {counters}로 쓸수잇음
    }

counters의 handleDelete 메서드는 위와 같이 수정하고

//Counter
 <button onClick={this.props.onDelete(this.props.id)} className="btn btn-danger btn-sm m-2">Delete</button>

Counter의 Delete button은 위와 같이 수정합니다.
onDelete(this.props.id)메서드는 버튼을 클릭하면 클릭된 엘레먼트의 id값을 인자로 보냅니다. Counters는 인자를 counterId로 받고 filter함수를 통해서 일치하는 것만 배열에서 빼버리고 나머지를 배열counters에 저장합니다. 마지막으로 setState를 통해서 state.counters를 수정합니다.
{counters:counters} 여기서 앞은 state 뒤는 const변수(배열)입니다.

마지막으로 코드 정리를 하겠습니다. Counters의 render을 수정합니다.

render() { 
        return (<div>
            { this.state.counters.map(counter => 
            <Counter 
            key={counter.id} 
            onDelete = {this.handleDelete}
            id = {counter.id}
            value={counter.value}  />) }
        </div>);    
    }
render() { 
        return (<div>
            { this.state.counters.map(counter => 
            <Counter              
            key={counter.id} 
            onDelete = {this.handleDelete}
            counter = {counter}/>) }
        </div>);    
    }

위 코드를 아래코드로 변경하고

state = {
        value : this.props.counter.value,
    };
<button onClick={() => this.props.onDelete(this.props.counter.id)} className="btn btn-danger btn-sm m-2">Delete</button>

Counter에서는 위와 같이 변경합니다.
여기까지 엘리멘트를 Delete하는 방법을 알아봤습니다.

참고자료
https://ko.reactjs.org/docs/getting-started.html

https://www.youtube.com/watch?v=Ke90Tje7VS0&t=916s

profile
익숙한 것에 작별을 고해야한다

0개의 댓글