반응형

오늘은 자바스크립트 ES6에서 추가된 주요 기능 중 화살표함수( => )에 대해 알아보겠습니다. 

 

[ 목차 ]

     

    1. 화살표 함수

    기존의 function으로 함수를 표현하는 방식을 좀 더 간결하게 표현하기 위해 화살표( => ) 함수가 도입되었습니다. 아래의 두 함수는 모두 동일한 역할을 하는 함수입니다.

    const test1 = function(a,b){
    	return a+b;
    }
    
    const test2 = (a,b) => {
    	return a+b;
    };
    
    const test3 = (a,b) => a+b;

     

    2. 화살표 함수 주의점(this)

    일반적인 자바스크립트 함수에서의 this는

       - 전역 객체

       - 메소드 호출시 호출한 해당 객체

    를 나타냅니다.

    // 일반 함수
    const obj1 = {
      name: '홍길동',
      func1(){
        console.log(this.name);
      }
    };
    obj1.func1();
    // 홍길동
    
    const obj2 = {
      name: '홍길동',
      func1: function() {
        const func2 = function() {
          console.log(this.name);
        }
        func2();
      }
    };
    
    obj2.func1();	
    // undefined

    위 두번째 obj2에서 this는 함수를 호출했을 때 지정되지 않았습니다. 곧 전역객체인 Window를 가리킵니다. 하지만 전역 객체 Window에 name이란 속성이 존재하지 않아서 undefined가 나타납니다.

     

    반면 화살표 함수에는 this는 현재 환경에서 그 변수가 없으면 바로 상위 환경을 검색하고, 해당 스코프에서 없으면 다시 또 상위를 검색합니다.

    // 화살표 함수
    const obj2 = {
      name: '이순신',
      func1: function() {
        const func2 = ()=> {
          console.log(this.name);
        }
        func2();
      }
    };
    
    obj2.func1();	// 이순신

     

    javascript에서의 this는 상당히 헷갈리고 어려운 개념으로 가볍게 다루기엔 좀 부담되는 주제이긴 합니다. 자세한 사용법은 다음에 공부해서 포스팅 하도록 하고, 오늘은 이만 마치겠습니다.

     

     

    (ps) 참고로 메서드 축약선언

    var obj = {
      foo: function() {},
      bar: function() {}
    };
    
    // 이를 아래로 줄일 수 있습니다:
    
    var obj = {
      foo() {},
      bar() {}
    };




    반응형
    반응형

    자바스크립트 filter 메소드에 대해 알아보겠습니다. Filter 메소드는 배열 내부를 순환하면서 특정 조건에 부합하는 요소들을 새로운 배열에 담아 반환합니다.

     

    1. 기본사용법

    result = my_array.filter (a => {
        return [조건];
    });

     

    const my_array = [1,2,3,4,5,6,7,8,9,10]
    
    const result = my_array.filter(a => {
      return a % 2 == 0; // a중 2로 나눈 나머지가 0(즉, 짝수)인 요소
    });
    
    console.log(result);
    
    // [ 2, 4, 6, 8, 10 ]

     

     

    2. 객체 다루기

    const my_array = [
        {name:'홍길동', age:28},
        {name:'이순신', age:37},
        {name:'유관순', age:18}
    ];
    
    const result = my_array.filter(a => {
      return a.age > 20; // 20세 이상인 요소
    });
    
    console.log(result);
    
    // [ { name: '홍길동', age: 28 }, { name: '이순신', age: 37 } ]

     

    3. Map, Reduce로 filter 구현하기

     

    map, reduce함수로도 filter를 구현할 수 있습니다.

    [map 예시]

    const my_array = [
        {name:'홍길동', age:28},
        {name:'이순신', age:37},
        {name:'유관순', age:18}
    ];
    
    const result = my_array.map(a=>{
      if(a.age>20){
        return a;
      }
    })
    console.log(result);
    
    // [ { name: '홍길동', age: 28 }, { name: '이순신', age: 37 }, undefined ]

    그런데 이 경우 마지막에 undefined가 들어갑니다. map과 filter의 특성이 다르니 상황에 따라 적절히 사용하면 좋을 것 같습니다.

     

    [reduce 예시]

    const my_array = [
        {name:'홍길동', age:28},
        {name:'이순신', age:37},
        {name:'유관순', age:18}
    ];
    
    result = my_array.reduce((acc, cur) => {
      if (cur.age > 20) acc.push(cur);
      return acc;
    }, []);
    
    console.log(result);
    
    // [ { name: '홍길동', age: 28 }, { name: '이순신', age: 37 } ]

     

    오늘은 이름과 같이 직관적으로 사용할 수 있어서 자주사용하게되는 filter메소드에 대해 간단한 사용법 몇가지, 그리고 참고로 map과 reduce를 사용하여 filter 구현하는 법을 알아보았습니다.

    반응형
    반응형

    reduce 함수는 자바스크립트에서 배열 또는 리스트 안의 요소들을 정렬하거나 특정 조건에 부합하면 합계나 평균 등을 계산하는데 사용되는 함수입니다.  개인적으로 자주 쓰지는 않지만 잘 알고있으면 많이 유용하게 쓸 수 있을것 같아서 정리해놓겠습니다.

     

    1. 기본사용법

    result = my_array.reduce((acc, cur, i) => {
        return (acc~연산~cur);
    }, acc초기값);

    - acc: accumulate(누적값)

    - cur: current(현재값)

    - acc초기값: 누적하기 전에 시작값을 지정

    const my_array = [1,2,3,4,5]
    const result = my_array.reduce((acc, cur, i) => {
      console.log(acc, i);
      return acc + cur;
    }, 0);
    
    console.log(result);

    reduce함수는 주로 누적합 또는 누적곱을 구할때 많이 씁니다. 위 예제도 가장 기본적인 누적합을 나타내고 있습니다. acc초기값에 0을 주면 누구나 예상하는 배열의 누적값을 구하게 되고, 거기에 다른 값을 주게 되면 0이아닌 다른 시작값을 갖고 더해나간다고 보시면 되겠습니다.

     

    2. 홀짝 구분하기

    const my_array2=[1,2,3,4,5,6,7]
    
    const result2 = my_array2.reduce((acc, cur, i) => {
      acc.push(cur % 2 ?'홀수' : '짝수');
      return acc;
    },[])
    
    console.log(result2);
    
    // ['홀수', '짝수', '홀수', '짝수', '홀수', '짝수', '홀수']

    짝수만 Filter 

    const my_array3=[1,2,3,4,5,6,7]
    
    const result3 = my_array3.reduce((acc, cur, i) => { 
         if(i%2){
           acc.push(cur);
         }
         return acc; 
     },[]);
    console.log(result3);
    
    // [ 2, 4, 6 ]

     

    3. 객체 다루기

    - 나이에 3을 곱한 새로운 배열을 생성하는 예

    const obj_array=[
      {
        name: "one",
        age: 1,
      },
      {
        name: "two",
        age: 2,
      },
      {
        name: "three",
        age: 3,
      }
    ]
    
    const result = obj_array.reduce((acc, cur,i)=>{
      acc.push(cur.age*3)
      return acc;
    },[])
    console.log(result);
    
    //[ 3, 6, 9 ]

    위의 예제는 map함수와 비슷하게 사용이 가능합니다. 이처럼 reduce를 사용하면 map이나 filter, sort, find 등 다양한 함수들을 reduce로 직접 구현해서 사용할 수 있습니다.

     

    Reduce함수에 대해 간단한 사용법 몇가지를 알아보았습니다.

     

    반응형
    반응형

    Javascript에서 객체배열(Object Array) 내부의 요소를 변경해야할 경우가 자주 발생합니다. 예를 들면 아래와 같은 객체 배열이 주어질 경우 특정 요소 또는 전체 요소의 age값을 변경할 필요가 있습니다.

    const obj_array=[
      {
        name: "one",
        age: 1,
      },
      {
        name: "two",
        age: 2,
      },
      {
        name: "three",
        age: 3,
      }
    ]

     

    이때 유용하게 사용할 수 있는 함수로 Map 메소드가 있습니다. 

    Map은 내부에서 callback 함수를 실행한 결과를 가지고 새로운 배열을 만들 때 사용합니다.

     

    1. 모든 요소의 값 변경하기

    // age를 모두 4로
    const result = obj_array.map(obj => {
      return {...obj, age: 4}
    });
    console.log(result); 
    //[{ name: 'one', age: 4 },{ name: 'two', age: 4 },{ name: 'three', age: 4 }]
    
    // age에 4배하기
    const result = obj_array.map(obj => {
      return {...obj, age:obj.age*4}
    });
    console.log(result); 
    //[{ name: 'one', age: 4 },{ name: 'two', age: 8 },{ name: 'three', age: 12 }]

     

    2. 특정 요소들만 추출하기

    const result = obj_array.map(obj => obj.name);
    console.log(result); 
    //[ 'one', 'two', 'three' ]

     

    3. 특정 요소의 값 변경하기

    age가 3인경우 값을 4로 바꾸기

    const result = obj_array.map(obj => 
      {
        return obj.age===3 ? {...obj, age: 4} : obj
      });
    console.log(result);
    //[{ name: 'one', age: 1 },{ name: 'two', age: 2 },{ name: 'three', age: 4 }]

     

     

    반응형
    반응형

    이번에는 Webview 라이브러리를 사용하면서 HTML 파일을 별도로 분리하는 방법을 알아보겠습니다. 그리고, 좀더 보기좋은 GUI 구성을 위해 부트스트랩도 함께 적용하도록 하겠습니다. 사실 이부분은...CSS 파일을 별도로 인식시켰으면 좋겠지만, 아직까지 별도의 CSS파일을 적용시키는 것은 안되는 것 같습니다. 

     

    1. 라이브러리 설치

    라이브러리 설치는 이전 강좌를 참고하세요.

     

    2. main.go 파일 작성

    main.go 파일에 전체 프로그램 구동을 구현합니다. 아울러, 버튼을 클릭했을 때 동작할 함수(go_hello)를 작성하고, 바인딩해줍니다. Webview라이브러리를 활용하면, go에서 javascript를 실행할 수도 있고, html파일(javascript 포함)에서 go언어를 실행할 수도 있습니다. 그러나 프로그램 가독성을 위해, Bind 한줄이 더 들어가더라도, 함수구현은 go에서 하도록 하겠습니다.

    package main
    
    import (
    	"fmt"
    	"os"
    
    	"github.com/webview/webview"
    )
    
    var w webview.WebView
    
    func main() {
    	w = webview.New(true)
    	defer w.Destroy()
    	w.SetSize(600, 600, webview.HintNone) // Create a GoLang function callable from JS
    	w.Bind("go_hello", go_hello)	// Go_hello 함수 구현과 html에서 호출하는 go_hello를 Bind해줍니다. 
    
    	// Create UI with data URI
    	dir, _ := os.Getwd()
    	fmt.Println(dir)
    	w.Navigate("file:" + dir + "/hi.html")
    
    	w.Run()
    }
    
    // 함수 실행 시, javascript로 팝업 알람을 실행해서 데이터를 보여줍니다.
    // HTML문서에서 보여주는 부분만큼은...javascript로..ㅠㅠ
    func go_hello() {
    	name := "You"
    	w.Eval(`alert("Hello` + name + `");`)
    }

    데이터를 처리하는 것은 go 함수구현에서 할 수 있지만, 마지막으로 데이터를 HTML로 보내서 보여주는 부분은 Javascript로 할 수밖에 없겠네요..^^;;

     

    3. hi.html

    HTML로 뷰를 구현합니다. 서두에서 말했듯이 CSS 적용이 힘든 관계로 Bootstrap을 CDN으로 불러와 적용시키겠습니다.

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
    
        <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous">    
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
        <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
    
        <title>My App</title>
    </head>
    <body>
        <!--Header Section-->
        <div class="box-padding-big">
          <nav class="navbar navbar-expand-sm navbar-dark bg-dark">
            <div class="collapse navbar-collapse">
              <ul class="navbar-nav mr-auto">
                <li class="nav-item active">
                  <a class="nav-link" href="#" id=navbardrop" data-toggle="dropdown">File</a>
                  <div class="dropdown-menu">
                  <a class="dropdown-item" href="#" onclick="go_hello()">Sub1</a>
                  <a class="dropdown-item" href="#">Sub2</a>
                  <a class="dropdown-item" href="#">Sub3</a>
                  </div>
                </li>
                <li class="hav-item">
                	<a class="nav-link" href="#">Edit</a>
                </li>
                <li class="hav-item">
                	<a class="nav-link" href="#">View</a>
                </li>
                <li class="hav-item">
                	<a class="nav-link" href="#">Info</a>
                </li>
              </ul>
            </div>
          </nav>
        </div>
    
      <!--Main Section-->
      <div style="margin: 20px;">
      	<div style="font-size: 36px; color:chartreuse;font-weight:700">
          <div>GO-Webview HTML View Test <br/>
          with Bootstrap
          </div>
        </div>
        <p class="text-primary" style="margin-top:20px;">
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam eget magna eros. Cras sit amet nulla dignissim, pretium justo sit amet, vulputate orci. Curabitur in aliquam lorem. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Morbi quis pulvinar nunc, sed posuere enim. In hac habitasse platea dictumst. Ut sodales augue eu elit bibendum, ut malesuada felis auctor. Sed mattis ipsum malesuada sem feugiat ultricies. Fusce ultrices vel est id pretium. Sed vel congue augue, non tincidunt tellus. Vivamus facilisis mollis tellus ac vulputate. 
        </p>
      </div>
    </body>
    </html>

     

    4. 결과

    아래 명령으로 결과를 확인합니다.

    go run main.go

    File - Sub1을 클릭하면...

    알람 팝업이 잘 나옵니다.

     

    이상으로 webview를 이용하여 html 파일과 bootstrap을 적용하는 방법을 알아봤습니다. 너무 쉽게 구현이 가능한데, 성능은 어느정도일지, 어떤 점이 부족할지 계속 알아봐야겠습니다.

     

    ~~~끝~~~

    반응형
    반응형

    1. App.js

    import React from 'react';
    import Contact from './Contact';
    import './App.css';
    
    function App() {
      return (
        <Contact />
      );
    }
    
    export default App;
    

    2. Contact.js

    import React, { Component } from 'react';
    import ContactInfo from './ContactInfo';
    
    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'
                }]
            }
    
        }
    
        render() {
    
            const mapToComponents = (data) => {
                return data.map((contact, i) => {
                    return (<ContactInfo contact={contact} key={i} />);
                })
            }
            return (
                <div>
                    <h1>Contacts</h1>
                    <div>{mapToComponents(this.state.contactData)}</div>
                </div>
            );
        }
    }
    
    export default Contact;

     

    3. ContactInfo.js

    import React, { Component } from 'react';
    
    class ContactInfo extends Component {
        render() {
            return (
                <div>{this.props.contact.name}{this.props.contact.phone}</div>
            );
        }
    }
    
    export default ContactInfo;
    반응형
    반응형

    LocalStorage에 저장하여 update되어도 데이터가 초기상태로 돌아가지 않도록 하는 기능을 구현하겠습니다. 

    componentWillMount API와 componentDidUpdate API만 구현해주면 됩니다.

     

    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);
    
        }
    
    	// 로컬 스토리지 데이터 가져오기 부분
        componentWillMount() {   // 컴포넌트가 마운트 되기 전에 실행되는 API
            const contactData = localStorage.contactData;
    
            if (contactData) {    // 로컬 스토리지에 값이 있으면 JSON 변환하여 불러옴 
                this.setState({
                    contactData: JSON.parse(contactData)
                })
            }
        }
    
        componentDidUpdate(prevProps, prevState) {   // 컴포넌트가 업데이트될 때마다 실행되는 API
            if (JSON.stringify(prevState.contactData) != JSON.stringify(this.state.contactData)) {  // 이전 값과 지금 값이 다르면
                localStorage.contactData = JSON.stringify(this.state.contactData);                  // 지금 값을 입력해 줌
            }
        }
    
        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) {
            var newContact = Array.from(this.state.contactData);
            newContact[this.state.selectedKey] = { name: _name, phone: _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}
                    />
                    <ContactCreate
                        onCreate={this.handleCreate}
                    />
                </div>
            );
        }
    }
    
    export default Contact;
    반응형
    반응형

    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;

     

    반응형

    + Recent posts