+ 알아야 할 것
함수를 props로 사용하여 자식 컴포넌트가 부모와 통신이 가능하도록 하는 방법
+ 실습
Player 컴포넌트를 삭제하는 것을 구현
자식이 부모와 통신
앞에서 부모가 자식에게 통신하기 위해서 props를 이용했고, props는 단방향 통신이고 위에서부터 아래로 흐리기 때문에 수정하면 안되는 read only 성격을 가진다고 하였다.
그러면, 반대로 자식이 부모에게 통신할려면 어떻게 해야 하나? 마찬가지로 props를 이용한다. 차이점은 props의 타입을 function 형태로 내려준다. 자식이 function 타입의 props를 받아서 호출하게 되면 부모의 function이 실행이 되므로 결국 자식이 부모와 통신하는 방법이 된다.
부모와 자식간의 통신, 자식이 부모와 통신하는 방법은 나중에 redux에도 그대로 적용되므로 잘 기억하자. 다음은 자식이 부모와 통신하는 방법을 순서대로 정리하면 다음과 같다.
Player 상태 관리
player 삭제를 구현하기 위해서는 먼저 player 데이터를 state로 관리해야 한다.
현재는 player가 4명에서 3명으로 변경이 된다는것은 시간에 따라 변하는 데이터이므로 최상위 부모인 App 컴포넌트에 player 를 state로 관리한다. 그러기 위해서는 먼저 App 컴포넌트를 class 컴포넌트로 변환 후 그다음 player 를 state로 정의한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
class App extends React.Component { state = { players: [ {name: 'LDK', id: 1}, {name: 'HONG', id: 2}, {name: 'KIM', id: 3}, {name: 'PARK', id: 4}, ] }; render() { return ( <div className="container p-3"> <Header title="My scoreboard" totalPlayers={this.state.players.length} /> {/*Players List*/} { this.state.players.map(item => <Player name={item.name} key={item.id} />) } </div> ); } } |
Player 삭제
player 삭제 로직을 추가하기 위해서는 개념적으로는 자식 컴포넌트인 player 컴포넌트가 삭제 요청을 부모에게 보내고 부모가 요청을 받은후 삭제를 처리해야한다. 그러면 변경된 데이터가 다시 props로 내려가게 된다.
개념을 기억하고 실제 코딩은 아래와 같은 순서로 하는것이 기억하기 쉽다.
1 ) 부모 컴포넌트에 콜백 펑션을 만든다. (App 11L ~17L)
2 ) 콜백 펑션을 자식에게 내려보낸다. (App 27L)
3 ) 자식컴포넌트에서는 props로 받은 콜백 펑션을 실행한다. (Player 6L)
1 ) App 컴포넌트에 삭제 함수를 추가한다. 이전 상태를 기반으로 변경한다. 2 ) 그리고 Player 컴포넌트에 삭제 함수를 props로 넘긴다. Player 컴포넌트에서 해당 함수가 넘어왔는지 devtools에서 확인한다. (
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 |
class App extends React.Component { state = { players: [ {name: 'LDK', id: 1}, {name: 'HONG', id: 2}, {name: 'KIM', id: 3}, {name: 'PARK', id: 4}, ] }; handleRemovePlayer = (id) => { this.setState(prevState => { return { players: prevState.players.filter(item => item.id !== id) } }) } render() { return ( <div className="container p-3"> <Header title="My scoreboard" totalPlayers={this.state.players.length} /> {/*Players List*/} { this.state.players.map(item => <Player name={item.name} key={item.id} removePlayer={this.handleRemovePlayer} id={item.id} />) } </div> ); } } |
3 ) Player 컴포넌트에서는 props 로 넘어온 함수를 이용하여 player를 삭제하는 클릭 이벤트를 추가한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
const Player = (props) => ( <div className="container"> <div className='player row align-items-center'> <div className="col-1"> <button className="btn btn-danger" onClick={() => props.removePlayer(props.id)}>x</button> </div> <div className="col-8"> <span>{props.name}</span> </div> <div className="col-3 counter"> <Counter score={props.score} /> </div> </div> </div> ); |
props 로 넘어온 players 는 read only 이므로 수정할 수 없다. 그러므로 players를 소유하고 있는 부모에게 삭제요청을 이벤트로 한다. 데이터의 흐름은 트리의 상단에서부터 아래로 단방향으로 흐르고 자식은 수정요청을 이벤트로 하게 된다.
그런데 부모와 자식간의 관계가 바로 아래 자식이 아니라 3단계이상 떨어진 경우라면 어떻게 해야 하나? 3단계 이상 떨어지면 계속 전달을 반복해야 하므로 이것을 해결하기 위해서 redux 등 3rd party 라이브러리를 이용해서 상태관리를 하게 된다.
+ ToDo
할일 목록에서 Delete 버튼을 누르면 할일을 삭제하는 코드를 완성하시오.