이번에는 글 목록을 클릭했을 때 <App>
컴포넌트의 state
의 모드("mode")
를 "read"
로 바꾸고 클릭한 글 목록에 해당하는 contents
내용이 본문에 나오도록 만들어 보자.
<Navi>
컴포넌트에 onChangePage
와 똑같은 이름의 경고창을 보여주는 이벤트를 만들어보자.
onChangePage
onChangePage={function(){ alert('Hello!'); }.bind(this)}
이렇게 생성한
onChangePage
이벤트<Navi>
컴포넌트 안에서props
형태로 전달받을 수 있다.
<Navi>
컴포넌트render
내부var lists = []; // 리스트 배열 var data = this.props.data; /* <App>컴포넌트로 가서 Navi를 확인하면 var data = this.state.contents[i]; 로 되어있으므로 this.props.data가 컴포넌트 프롭스(props)를 통해 값을 가져온다.*/ var i = 0; while(i <data.lenght){ lists.push( <li key = {data[i].id}> <a href={"/content/" + data[i].id} onClick={function(e){ e.preventDefault(); this.props.onChange(); }.bind(this)}>{data[i].title}</a> </li>);
<Navi>
컴포넌트 안에 각각 목록에 해당하는 <li>
부분에 링크를 클릭했을 때 onClick 이벤트
가 실행된다.
이벤트가 실행될 때 페이지가 바뀌지 않도록 e.preventDefault()
함수를 추가해준다.
this.props.onChangePage();
라고 props
속성 형태로 onChangePage()
함수를 실행시켜 정상적으로 작동하게 된다.
- 작동 확인
이벤트가 정상적으로 작동되는 것을 확인했다.
이제 App.js
파일로 들어가서
<Navi>
컴포넌트 props
에 정의되어있는 onChangePage
함수를 수정해
<App>
컴포넌트의 state "mode"의 값을 "read"로 바꾸도록 코드를 수정해보자.
App.js
><Navi>
>props
onChange = {function(){ this.setState({mode:'read'}); }.bind(this)}
- 결과화면
이제 링크를 mode라는 state가 변하는 것을 확인할 수 있다.
이번엔 글 목록에 선택한 content가 본문에 표시되도록 해보자.
여기서부턴 이벤트가 중심보다는 state에 집중을 하도록 한다.
<App>
컴포넌트의 state에 selected_content_id
와 같은 이름으로 우리가 현재 선택한 content를 표시할 것이다.
그 값을 바탕으로 contents
라고 하는 객체에 있는 id 값과 일치하는 selected_content_id
값과 일치하는 것을 본문에 표시할 것이다.
App.js > App > constructor > contents
this.state = { mode: 'read', selected_content_id: 2, welcome: { title: 'welcome', desc: 'Hello, React!!' }, subject: { title: 'SAMPLETITLE', sub: 'this is sub text!' }, artsub: { title: "NEW ARTICLE", sub: "this Arti has been updated" }, contents: [ { id: 1, title: 'Alpha', desc: 'this area is Section_alpha!' }, { id: 2, title: 'Delta', desc: 'this area is Section_delta!' }, { id: 3, title: 'Charlie', desc: 'this area is Section_charlie!' }, ] }
위 코드처럼 App 컴포넌트의 state에 selected_content_id
를 2로 설정함으로써 기본적으로 2번 content가 선택되게 한다.
mode가 read일 때 selected_content_id
의 값에 따라 content 배열 중 무엇이 본문에 나올 것인지를 지정하도록 한다.
App.js > App > render
// 렌더 실행할때 state mode가 read일 경우 else if(this.state.mode === 'read'){ _title = this.state.contents[0].title; // id : 1인 Alpha 타이틀 _desc = this.state.contents[0].desc; // id : 1인 Delta 타이틀 /* selected_content_id 활용구간 */ var i = 0; // 인덱스 while(i < this.state.contents.length){ // state콘텐츠 길이만큼 반복 var data = this.state.contents[i]; // data는 state의 content[i]번째 가져옴 if(data.id === this.state.selected_content_id){ // id값과 selected_content_id 일치하면? _title = data.title; // data의 title _desc = data.desc; // data의 desc break; // 루프 탈출 } i = i + 1; // 위 if문 만족하지 않을경우 인덱스 i 1 증가 } }
위 코드처럼 반복문을 수행하며 현재 순번에 해당하는 contents의 data.id
값과 this.state.selected_content_id
값이 일차하는 경우 _title, _desc에 해당된다.
이처럼 변경시 selected_content_id
가 2번이므로 2번에 해당되는 Delta content가 본문에 표시된다.
이를 이용하여 <Navi>
컴포넌트 list
의 onChangePage
이벤트가 발생했을 때 this.setState
를 이용하여 mode값과 함께 selected_content_id
의 값을 변경하면 된다.
App.js > App > render > Navi.props
<Navi onChangePage={function (id) { this.setState({ mode: 'read', selected_content_id: ..? }); }.bind(this)} data={this.state.contents} </Navi>
<Navi>
컴포넌트의 onChangePage
이벤트를 실행시키는 부분은 Navi.js
에서 a
태그의 onclick
이벤트가 발생했을 때
this.props.onChangePage()를 실행 시 App.js
에 있는 onChangePage
함수를 실행시키면 된다.
onChangePage()
함수를 실행시킬 때 항목의 id 값을 넘기도록 구현해보자.
Navi.js > render
var lists = []; var data = this.props.data; var i = 0; while (i < data.length) { lists.push( <li key={data[i].id}> <a href={"/content/" + data[i].id} data-id={data[i].id} // "data-" 로 시작되는 접두사를 붙이면? //dataset이라고 하는 특수한 형태에서 접근할 수 있다. onClick={function (e) { debugger; // e 구간 체크하기 e.preventDefault(); // 페이지 이동 해제 this.props.onChangePage(); // 사용자 이벤트 호출 }.bind(this)}> {data[i].title} </a> </li>); i = i + 1; }
<Navi>
컴포넌트의 a태그
에 "data-i = {data[i].id}"와 같은 속성을 주고 로드하면 해당하는 id 값인 1,2,3 을 확인할 수 있다.
Navi안에 있는 a태그의 props --> data-id 확인
그리고 디버거로 잠시 실행을 멈추고 onClick
발동시 e
라는 이벤트 객체는 어떤정보가 들어가 있는지 확인해보자.
이벤트 객체 e
체크
- 콘솔에 e를 입력하고 엔터를 친다.
위에 target
이라는 속성은 이벤트가 발생한 태그를 가리킨다.
이를 통해 a
태그를 알아내고 a
태그가 가지고 있는 data-id
값에 접근할 수 있다. (속성값 접근)
"data-"로 시작되는 속성은 dataset
이라고 하는 특수한 형태에서 접근할 수 있다.
위에서 사용한 속성은 data-id이므로 접미사는 id에 해당된다.
e
객체의 target 속성에서 dataset
의 해당하는 값이 data-id
의 값이 된다.
이렇게 알아낸 정보를 onChangePage()
함수를 호출하는 코드에 인자로 넣으면 된다.
Navi.js > render
var lists = []; var data = this.props.data; var i = 0; while...생략 <li key={data[i].id}> <a href={"/content/" + data[i].id} data-id={data[i].id} // "data-" 로 시작되는 접두사를 붙이면? //dataset이라고 하는 특수한 형태에서 접근할 수 있다. onClick={function (e) { e.preventDefault(); // 페이지 이동 해제 this.props.onChangePage(e.target.dataset.id); // 사용자 이벤트 호출 // 이벤트객체가 가르킨 a태그 속성중 접두사 data-가 있는 data-id의 정보를 얻음 }.bind(this)}>{data[i].title} </a> </li>
onChangePage
에 id 라는 매개변수를 주고 이 id 값을 selected_contnet_id
의 값으로 넣어준다.
이때 넘어오는 데이터는 문자니까 content
의 id
는 숫자이므로 Number()
를 사용하여 문자를 숫자로 바꿔준다.
App.js > Navi 컴포넌트
<Navi onChangePage={function (id) { // id는 Navi.js가 해당 함수를 호출하고 e객체가 가진 데이터를 사용 this.setState({ mode: 'read', selected_content_id: Number(id) }); }.bind(this)} data={this.state.contents} </Navi>
위 코드를 작성하고 실행하면
welcome
으로 바뀌고read
으로 바뀌고 클릭한 목록에 해당되는 selected_content_id
가 바뀌어 본문의 내용도 바뀌는 것을 확인할 수 있다.bind(this)의 두번째 인자로 data[i].id
값을 주면 onClick 이벤트에서 실행되는 함수의
첫번째 매개변수 값이 bind
의 두번째 인자로 불러온 값인 data[i].id
가 된다.
Navi.js > render
- 속성 이용 안하는 방법
<li key={data[i].id}> <a href={"/content/" + data[i].id} // data-id={data[i].id} // 속성이 정말 활용안되는지 주석처리 onClick={function (id,e) { e.preventDefault(); // 페이지 이동 해제 this.props.onChangePage(id); // 사용자 이벤트 호출 }.bind(this, data[i].id)}>{data[i].title} </a> </li>
위 처럼 a
태그 내에 data-id
라는 속성이 없어도 원하는 결과가 나오는 것을 확인할 수 있다.
Navi의 a태그 onClick시 매개변수 정리
- function(e) -> e 객체가 가르키는 태그의 속성을 dataset.id로 조회해서 보낼경우, 함수 끝날 때 bind(this)로 입력
- function(id, e) -> 인자로 이벤트객체 e 와 id를 사용하며 e는 위 그대로 사용,
인자 id는 해당 태그가 만들어낼때 id값을 가지고 있음
이때 this.props.이벤트 발생시 인자를 e가 아닌 id를 입력한다.
함수가 끝날 때 (this, data[i].id]) 입력