본문 바로가기
Programming/Javascript

React강좌2, 전화번호부 - 5.Update 기능

by Wilkyway 2020. 8. 3.
반응형

Update기능은 좀 어렵습니다. 구현해야 할 내용으로는 ContactDetails 컴포넌트에서

 

  1. Edit 버튼을 만듭니다. 이 버튼은 Edit모드와 비 Edit모드사이를 토글할 수 있도록 합니다.

  2. 토글 함수를 선언해줍니다. isEdit 값이 false이면 Edit 폼에 name과 phone이 변경 가능하도록 데이터를 보여주며, true이면(수정 완료버튼 클릭) name과 phone 값을 상위요소인 Contact 컴포넌트로 전달해줍니다. 전달함수는 별도로 3번에서 만듭니다.

  3. handleEdit 함수를 선언합니다. 이 함수에서 isEdit가 true일 때 name과 phone 을 Contact 컴포넌트로 전달해줍니다.

  4. Edit 폼을 만들어줍니다. 그리고 isEdit 값에 따라 표시되는 상황이 변경되도록(수정폼/뷰폼) 수정합니다.

 

그리고 Contact 컴포넌트에서

  5. handleEdit 함수를 선언합니다.  ContactDetails 컴포넌트의 handleEdit함수에서 전달된 name과 phone 값을 이용하여 state를 변경합니다. 동일한 함수 이름이지만 컴포넌트 내부에서만 쓰이므로 역할이 다릅니다. 다른 이름으로 해도 상관없습니다.

  6. <ContactDetails> 컴포넌트 내부에서 onEdit 이벤트를 handleEdit 함수와 연결해줍니다.

 

 

ContactDetails.js

import React, { Component } from 'react';

class ContactDetails extends Component {
    constructor(props) {
        super(props);

        this.state = {
            isEdit: false,  // 토글시킬 변수를 선언하고 초기값은 edit하지 않도록 false선언
            name: '',
            phone: '',
        };

        this.handleToggle = this.handleToggle.bind(this);   // isEdit를 토글시킬 함수 바인딩 선언
        this.handleChange = this.handleChange.bind(this);   // Edit 폼에서 입력 가능하도록 바인딩 선언
        this.handleEdit = this.handleEdit.bind(this);       // 진짜 edit하는 함수 바인딩 선언
    }

    handleToggle() {
        if (!this.state.isEdit) {   // Edit 폼에 수정할(선택할) 데이터가 보이도록 함.
            this.setState({
                name: this.props.contact.name,  // state로 선언된 name에 선택하면서 넘겨온 props의 name을 줌
                phone: this.props.contact.phone // state로 선언된 phone 선택하면서 넘겨온 props의 phone을 줌
            });
        } else {
            this.handleEdit();
        }
        this.setState({
            isEdit: !this.state.isEdit  // isEdit 변수를 토글함
        });
        console.log(this.state.isEdit);
    }

    handleChange(e) {           // edit폼에서 입력(변경) 가능하도록 함수 선언
        let nextState = {};
        nextState[e.target.name] = e.target.value;
        this.setState(nextState);
    }

    handleEdit() {      // state를 props의 onEdit 함수로 전달만 함.
        this.props.onEdit(this.state.name, this.state.phone);
    }

    render() {


        const details = (
            <div>
                <p>{this.props.contact.name}</p>
                <p>{this.props.contact.phone}</p>
            </div>
        );

        const edit = (   // edit 가능하도록 하는 폼 선언
            <div>
                <p>
                    <input
                        type="text"
                        name="name"
                        placeholder="name"
                        value={this.state.name}
                        onChange={this.handleChange}
                    />
                </p>
                <p>
                    <input
                        type="text"
                        name="phone"
                        placeholder="phone"
                        value={this.state.phone}
                        onChange={this.handleChange}
                    />
                </p>
            </div>
        )
        const view = this.state.isEdit ? edit : details;   // isEdit가 true이면 edit 화면, false이면 details를 보여줄 변수(view)선언

        const blank = (<div>Not Selected</div>)
        return (
            <div>
                <h2>Details</h2>
                {this.props.isSelected ? view : blank}  {/*선택된 상태이면 view를, 아니면 blank를 보여주도록 detail -> view로 수정*/}
                <p>
                    <button onClick={this.handleToggle}> {/* Edit 버튼 추가, 토글 함수에 연결 */}
                        {this.state.isEdit ? 'OK' : 'Edit'}  {/* isEdit가 true이면(수정 완료) OK가 표시되도록 */}
                    </button>
                    <button onClick={this.props.onRemove}>Remove</button> {/* 삭제 버튼 추가 */}
                </p>
            </div>
        );
    }
}

ContactDetails.defaultProps = {
    contact: {
        name: '',
        phone: ''
    },
    onRemove: () => { console.error('onRemove not defined'); },
    onEdit: () => { console.error('onEdit not defined'); }
}

export default ContactDetails;

 

 

Contact.js

import React, { Component } from 'react';
import ContactInfo from './ContactInfo';
import ContactDetails from './ContactDetails';
import ContactCreate from './ContactCreate';

class Contact extends Component {
    constructor(props) {
        super(props);
        this.state = {
            selectedKey: -1,
            keyword: '',
            contactData: [{
                name: 'Abet',
                phone: '010-000-0001'
            }, {
                name: 'Betty',
                phone: '010-000-0002'
            }, {
                name: 'Charlie',
                phone: '010-000-0003'
            }, {
                name: 'David',
                phone: '010-000-0004'
            }]
        }
        this.handleChange = this.handleChange.bind(this);
        this.handleClick = this.handleClick.bind(this);

        this.handleCreate = this.handleCreate.bind(this);
        this.handleRemove = this.handleRemove.bind(this);
        this.handleEdit = this.handleEdit.bind(this);

    }

    handleChange(e) {
        this.setState({
            keyword: e.target.value
        })
    }

    handleClick(key) {
        this.setState({
            selectedKey: key
        })
    }

    handleCreate(contact) {
        var newContact = Array.from(this.state.contactData);
        newContact.push(contact);
        this.setState({
            contactData: newContact
        });
    }

    handleRemove() {
        if (this.state.selectedKey < 0) {
            return;
        }
        var newContact = Array.from(this.state.contactData);
        newContact.splice(this.state.selectedKey, 1);
        this.setState({
            contactData: newContact,
            selectedKey: -1
        });

    }

    handleEdit(_name, _phone) {  // onEdit 이벤트 발생시 실행할 함수 선언
        var newContact = Array.from(this.state.contactData);    // 배열 복제
        newContact[this.state.selectedKey] = { name: _name, phone: _phone };    // 선택된 키의 요소에 대해 name과 phone에 전달된 값을 넣어준다.
        this.setState({
            contactData: newContact
        });
    }

    render() {

        const mapToComponents = (data) => {
            data = data.filter((contact) => {
                return contact.name.toLowerCase().indexOf(this.state.keyword.toLowerCase()) > -1;
            })
            return data.map((contact, i) => {
                return (<ContactInfo
                    contact={contact}
                    key={i}
                    onClick={() => this.handleClick(i)}
                />);
            })
        }
        return (
            <div>
                <h1>Contacts</h1>
                <input
                    name="keyword"
                    placeholder="Search"
                    value={this.state.keyword}
                    onChange={this.handleChange}
                />
                <div>{mapToComponents(this.state.contactData)}</div>
                <ContactDetails
                    isSelected={this.state.selectedKey != -1}
                    contact={this.state.contactData[this.state.selectedKey]}
                    onRemove={this.handleRemove}
                    onEdit={this.handleEdit}    // onEdit 이벤트를 handleEdit 함수로 연결
                />
                <ContactCreate
                    onCreate={this.handleCreate}
                />
            </div>
        );
    }
}

export default Contact;

 

반응형

댓글