[React] 생활코딩-4 이벤트

ji_silver·2020년 6월 30일
0

[React] 생활코딩

목록 보기
4/6
post-thumbnail

1. 이벤트 state props 그리고 redner 함수

  • props, state, event 이 3개가 서로 상호작용하여 애플리케이션의 역동성을 만듦

App.js

class App extends Component {
    constructor(props) {
        super(props);
        this.state = {
            ⭐mode: 'read',
            ⭐welcome: { title: 'Welcome', desc: 'Hello, React!!' },
            subject: { title: 'WEB', sub: 'World Wide Web!' },
            contents: [
                { id: 1, title: 'HTML', desc: 'HTML is for information' },
                { id: 2, title: 'CSS', desc: 'CSS is for design' },
                { id: 3, title: 'JavaScript', desc: 'JavaScript is for interactive' }
            ]
        }
    }

    render() { //어떤 HTML을 그릴것인가를 결정하는 함수
        var _title, _desc = null;
        if (this.state.mode === 'welcome') { //state의 mode값이 'weclome' 일 때 실행
            _title = this.state.welcome.title;
            _desc = this.state.welcome.desc;
        } else if (this.state.mode === 'read') { //state의 mode값이 'read' 일 때 실행
            _title = this.state.contents[0].title;
            _desc = this.state.contents[0].desc;
        }
        return (
            <div className="App">
                <Subject
                    title={this.state.subject.title}
                    sub={this.state.subject.sub}>
                </Subject>
                <TOC data={this.state.contents}></TOC>
              	<Content title={_title} desc={_desc}></Content>
            </div>
        );
    }
}

mode값이 welcome, read에 따라 실행되는 코드가 바뀜

props, state값이 바뀌면 그 state를 가지고 있는 컴포넌트의 render함수가 다시 호출.
그리고 render함수 하위에 있는 컴포넌트들도 다시 호출 (화면 다시 그려짐)

React에서는 링크 클릭시 event를 발생시켜
state, props를 변경함으로써 페이지 전체가 re-rendering

2. 이벤트 설치

...
return (
    <div className="App">
    
        {/* <Subject
            title={this.state.subject.title}
            sub={this.state.subject.sub}>
        </Subject> */}
        
        <header>
            <h1><a href="#" onClick={function (e) {
                e.preventDefault();
                //이벤트가 발생한 태그의 기본 동작방법을 못하게 막는 코드
            }}>{this.state.subject.title}</a></h1>
            {this.state.subject.sub}
        </header>
        <TOC data={this.state.contents}></TOC>
        <Content title={_title} desc={_desc}></Content>
    </div>
);

3. 이벤트에서 state 변경하기

  • 링크 클릭 시 App 컴포넌트의 mode 값을 welcome으로 바꿔보기
  • this.state.mode = 'welcome'; => ❌오류
<header>
    <h1><a href="#" onClick={function (e) {
        e.preventDefault();
        this.state.mode = 'welcome'; 
    }}
</header>
  • 위 코드로 작성시 2가지 문제점 발생
    1) 이벤트가 호출됐을 때 실행되는 함수 안에서는 this의 값이 컴포넌트 자기 자신을 가리키지 않고 아무 값도 세팅되어 있지 않음.
    => 함수가 끝난 직후 bind() 함수 추가
    2) 동적으로 state값을 바꿀때는 setState ()사용
<header>
    <h1><a href="#" onClick={function (e) {
        e.preventDefault();
        this.setState({
            mode: 'welcome'
        });
    }.bind(this)}>{this.state.subject.title}</a></h1>
    {this.state.subject.sub}
</header>

❗ 하지만 render() 함수 밖에서 onClick 이벤트 함수를 화살표함수로(ES6) 만들면 bind() 없이 this 사용 가능

4. 컴포넌트 이벤트 만들기

  • App.js에서 이전에 작업한 주석처리 했던 Subject 컴포넌트 다시 살리고 Subject.js에서 갖고 온 코드는 지우기

1) Subject 컴포넌트에 이벤트 설치해보기

App.js

...
<Subject
    title={this.state.subject.title}
    sub={this.state.subject.sub}
    //onChagePage 이벤트 만들고, 링크 클릭시 함수가 실행되게 하기
    onChangPage={function () {
        this.setState({
            mode: 'welcome' // 클릭시 mode값을 welcome으로 바꾸기
        });
    }.bind(this)}>
</Subject>

Subject.js

<header>
    <h1><a href="#" onClick={function (e) {
        e.preventDefault();
        this.props.onChangePage();
        //Subject 컴포넌트에 onChangePage로 함수가 전달되는데 그 함수를 호출하는 코드
    }.bind(this)}>{this.props.title}</a></h1>
    {this.props.sub}
</header>

2-1) TOC 컴포넌트 클릭 시 state의 mode를 read로 바꾸기

App.js

...
//onChangePage이벤트 만들기
<TOC onChangePage={function (id) { 
    this.setState({
        mode: 'read'
    });
}.bind(this)} data={this.state.contents}></TOC>

TOC.js

while (i < data.length) {
    lists.push(
        <li key={data[i].id}>
            <a href={"/content/" + data[i].id}
                onClick={function (e) {
                    e.preventDefault();
                    this.props.onChangPage();
                }.bind(this)}
            >{data[i].title}</a>
        </li>);
    i = i + 1;
}

2-2) 내가 선택한 내용을 본문에 나타내기

App.js

this.state = {
    mode: 'read',
 ⭐selected_content_id = 2, // 기본적으로 2번 contents가 선택되게 함
    welcome: { title: 'Welcome', desc: 'Hello, React!!' },
    subject: { title: 'WEB', sub: 'World Wide Web!' },
    contents: [
        { id: 1, title: 'HTML', desc: 'HTML is for information' },
        { id: 2, title: 'CSS', desc: 'CSS is for design' },
        { id: 3, title: 'JavaScript', desc: 'JavaScript is for interactive' }
    ]
}

render() {
    var _title, _desc, _article = null;
    if (this.state.mode === 'welcome') {
        _title = this.state.welcome.title;
        _desc = this.state.welcome.desc;
    }else if (this.state.mode === 'read') {
        var i = 0;
        while (i < this.state.contents.length) {
            var data = this.state.contents[i]; //현재 순번에 해당되는 contents를 data변수에 지정
            if (data.id === this.state.selected_content_id) {
                _title = data.title;
                _desc = data.desc;
                break; //조건문을 끝내는 코드
            }
            i = i + 1;
        }
    }
    return (
        <div className="App">
            <TOC onChangePage={function (id) {
                this.setState({
                    mode: 'read',
                    selected_content_id: Number(id)
                    // 인자가 문자로 넘어가기 때문에 숫자로 바꿔주는 Number 명령어를 사용
                });
            }.bind(this)} data={this.state.contents}>
            </TOC>
        </div>
    );
}

TOC.js

while (i < data.length) {
    lists.push(
        <li key={data[i].id}>
            <a href={"/content/" + data[i].id}
                data-id={data[i].id} // 
                onClick={function (e) {
                    e.preventDefault();
                    this.props.onChangPage(e.target.dataset.id);
                    //onChangePage 함수를 호출하는 코드의 인자로 e.target에서 얻어진 id 값을 넘겨줌
                }.bind(this)}
            >{data[i].title}</a>
        </li>);
    i = i + 1;
}
  • 저기서 e.target은 a태그를 가리키며, dataset을 통하여 data-id값을 알아낼 수 있음
  • 🔥하위가 상위에게 명령할 땐 이벤트를 실행해 state 값 변경 가능
profile
🚧개발중🚧

0개의 댓글