함께 성장하는 프로독학러

5-5. 전화번호부 어플리케이션 만들기 - 추가기능 구현(ref), localStorage 본문

Programming/react.js

5-5. 전화번호부 어플리케이션 만들기 - 추가기능 구현(ref), localStorage

프로독학러 2018. 4. 20. 17:48

안녕하십니까 여러분, 프로독학러 입니다.


저번 포스팅에 이어 전화번호부 어플리케이션을 만들어 보도록 하겠습니다.

*velopert 님의 Youtube 강의를 정리한 내용이라고 보시면 될 것 같습니다. (4강)

<Contact application - velopert>


이번 포스팅이 전화번호 어플리케이션 만들기의 마지막 포스팅입니다.

이번 포스팅까지 열심히 따라하고, 이해하고, 반복하셔서 리액트와 좀 더 친해지길 바라겠습니다!

물론 저두요...!


이번 포스팅에서 추가적으로 구현해 볼 기능은 총 세 가지 입니다.

살펴보시죠.


1) Create new user , Edit user 를 할 때 입력후 엔터를 쳤을 때 기능이 동작하도록 하기


Create new user 나 Edit user 를 할 때 input 창에 값을 입력한 뒤, (지금까지는) button 을 눌러 추가, 수정을 했습니다.

버튼을 직접 누르지 않고 엔터키를 활용해서 기능이 동작하도록 해 봅시다.

이는 input 태그의 이벤트 중 하나인 onKeyPress 를 이용합니다.


먼저 ContactCreate 컴포넌트에 적용해 보도록 하겠습니다.

ContactCreate 의 두 번째 input 태그에 onKeyPress 이벤트를 주고, 해당 이벤트가 호출되었을 때 실행될 함수를 정의 합니다.


(./src/components/ContactCreate.js)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
_handleKeyPress = (e) => {
  if(e.charCode === 13){
  this._buttonClick();
  }
}
...
    <p>
       <input
             ...
       />
       <input
          name="phone"
          type="text"
          placeholder="phone"
          value={this.state.phone}
          onChange={this._handleChange}
          onKeyPress={this._handleKeyPress}
        />
    </p>
...
cs


위 코드의 18번째 줄에 input 태그의 onKeyPress 이벤트 주고, 이벤트가 호출될 때 실행될 함수를 _handleKeyPress 로 주었습니다.

_handleKeyPress 함수는 코드의 2번째 줄에서 정의돼 있습니다.

함수의 인자로 들어오는 e 는 이벤트 객체를 의미합니다.

3번째 줄의 조건문은 이벤트객체의 charCode 가 13 이면 (onKeyPress 의 이벤트가 엔터를 쳤을 경우) _buttonClick 메소드를 실행하는 것입니다.

_buttonClick 메소드는 Create new user 의 메소드로 버튼을 누르면 발생하는 메소드입니다.

즉, 두 번째 input 태그에서 엔터를 치면 _buttonClick 메소드가 동작해 Contact 컴포넌트의 state.conatactData 에 유저를 추가합니다.


똑같은 방법으로 ContactDetail 컴포넌트의 수정모드에서 두 번째 input 에 적용시켜줍니다.


(./src/components/ContactDetail.js)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
...
_handleKeyPress = (e) => {
      if(e.charCode === 13){
        this._editButtonToggle();
      }
    }
...
const edit = (<div>
                <p>
                  <input
                     ...
                   />
                   <input
                     name="phone"
                     type="text"
                     placeholder="phone"
                     onChange = {this._inputChange}
                     value = {this.state.phone}
                     onKeyPress = {this._handleKeyPress}
                    />
                  </p>
               </div>);
...
cs


ContactCreate 경우와 같지만 다른점은 코드의 4번째 줄에서 실행하는 함수의 이름입니다.

수정은 _editButtonToggle 메소드로 하기 때문에 실행되는 함수를 _editButtonToggle 로 지정했습니다.


2) Create new user 한 뒤에 마우스 포커스를 자동으로 input (name) 태그로 이동


전화번호부에 추가할 정보가 여러개라면 추가한 뒤에 바로 키보드를 입력할 수 있게 focus 가 input 태그로 입력되면 편리할 것입니다.

이를 구현해보도록 하겠습니다.

이를 하기 위해서 리액트의 ref 를 이용합니다.

ref(reference) 는 컴포넌트의 메소드에서 컴포넌트의 태그에 접근할 때 사용되는 방법입니다.

사용법은 접근하려는 태그에 ref 속성을 주고, 콜백함수를 주는 것 입니다.


<HTMLtag ref={(ref)=>{this.refName=ref}}>


위와 같이 태그에 ref 속성을 준 뒤 콜백함수를 주는데, 인자로 들어오는 ref 가 ref 자체를 의미해서, this,refName 을 ref 로 사용하겠다는 의미입니다.


ContactCreate 컴포넌트에서 적용시켜 보도록 하죠.


(./src/components/ContactCreate.js)

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
29
30
31
32
...
  _buttonClick = () => {
    const newContact = {
      name : this.state.name,
      phone : this.state.phone
    };
    this.props.onCreate(newContact);
    this.setState({
      name:'',
      phone:''
    });
    this.focusTarget.focus();
  }
...
        <div>
          <h2>Create new user</h2>
          <p>
            <input
              type="text"
              name="name"
              placeholder="name"
              onChange={this._inputChange}
              value={this.state.name}
              ref = {(ref) => {this.focusTarget = ref}}
            />
            <input
              ...
            />
          </p>
          <button onClick={this._buttonClick}>Create new user</button>
        </div>
...
cs


코드의 24번째 줄에서 input(name) 태그에 ref 속성을 주었습니다.

이 input 태그를 ref 로서 사용할 때 this.focusTarget 이라는 이름으로 사용하겠다는 의미입니다.

코드의 12번째 줄을 보면, 버튼을 클릭하면 실행되는 메소드의 마지막 단계에서 this.focusTarget 에 포커스를 주겠다고 했습니다.

this.focusTarget 는 input (name) 태그이므로 정보가 추가되고 나서 자동으로 해당 태그에 포커스가 맞춰지게 됩니다.



브라우저를 통해 확인해 보면, Prestar 정보를 추가하고 자동으로 name input 태그에 포커스가 이동 된 것을 볼 수 있습니다.


3) localStorage 이용


마지막으로 localStorage 에 대해 알아보고, 이를 우리의 전화번호부 어플리케이션에 적용시켜 보겠습니다.

기존에 우리는 데이터를 컴포넌트의 state 안에 저장했습니다.

이는 메모리에 저장하는 것이므로 새로고침을 하거나 브라우저가 종료되면 메모리의 데이터가 삭제되고 데이터는 처음 정의한 코드의 state 로 초기화 됩니다.

이를 해결하기 위해 localStorage 를 사용할 것입니다.


localStorage 는 브라우저를 저장소로 사용하는 개념입니다.

session 과 비슷하지만, session 과 구분되는 점은 브라우저가 종료되도 정보가 지워지지 않고 남아있다는 점입니다.

(session 에 저장된 정보는 브라우저가 종료되면 자동으로 삭제됩니다.)

localStorage 에 저장할 수 있는 데이터 타입은 String 입니다.

따라서 우리가 어떤 객체를 저장하고자 할 때 객체를 JSON.stringify 메소드를 이용해 문자열로 바꿔줘야 합니다.

반대로 localStorage 에 저장된 데이터를 사용하고자 할 때는 JSON.parse 메소드를 이용해 문자열을 객체로 복원시켜 사용해야 합니다.


localStorage 에 저장하는 방법은 다음과 같습니다.


localStorage.저장소명 = 저장할 데이터(문자열 데이터)


그리고 저장소에 저장된 데이터를 꺼내 쓰는 방법은 아래와 같습니다. (원본 데이터가 객체 형식일 때)


JSON.parse(localStorage.저장소명)


그럼 우리의 어플리케이션에 적용해 보도록 하겠습니다.

먼저 Contact 컴포넌트가 렌더링 되기 전에 localStrage 에 contactData 가 있는지 확인하고 있다면 Contact 컴포넌트의 state 값을 localStrage 의 contactData 값으로 변경합니다.

(브라우저를 재시작해도 유지시키기 위함)


(./src/components/Contact.js)

1
2
3
4
5
6
7
8
9
10
...
  componentWillMount(){
    const contactData = localStorage.contactData;
    if(contactData){
      this.setState({
        contactData:JSON.parse(contactData)
      })
    }
  }
...
cs


데이터를 저장할 localStrage 의 이름은 contactData 로 정했습니다.

위의 코드를 통해 컴포넌트가 렌더링되기 전에 localStrage 에 contactData 이름으로 저장된 데이터가 있는지 확인합니다.

있다면 데이터를 객체형으로 변환해 (6번째줄) Contact 컴포넌트의 state.contactData 값으로 변경합니다.


그리고 컴포넌트가 업데이트 될 때마다 이전 state와 현재 state를 비교해 값이 달라지면 달라진 값을 localStrage 에 저장하도록 하겠습니다.

컴포넌트가 업데이트 된 이후에 실행되는 Component Lifecylce API 는 componentDIdUpdate 입니다.

componentDIdUpdate 의 인자로는 prevProps 와 prevState 가 오는데 이는 이전의 프롭스와 이전의 state 를 의미합니다.


(./src/components/Contact.js)

1
2
3
4
5
6
7
...
  componentDidUpdate(prevProps, prevState){
    if(JSON.stringify(prevState.contactData) !== JSON.stringify(this.state.contactData)){
      localStorage.contactData = JSON.stringify(this.state.contactData);
    }
  }
...
cs


이전의 state 인 prevState.contactData 와 현재의 state 인 this.state.contactData 를 비교하여 값이 다르면 달라진 값을 localStrage 에 저장합니다.

(객체를 비교할 때 문자열으로 변경한 뒤 비교하면 간단하게 비교가 가능하다 - JSON.stringify)


자 이제 브라우저를 통해 확인해 보도록 하겠습니다.


데이터를 추가, 수정 삭제한 뒤에 브라우저를 종료하고 재시작해도, 새로고침 해도 데이터가 그대로 보존되어 있습니다.

만약 localStorage 를 초기화 하고 싶다면 브라우저의 콘솔창에 


localStorage.clear();


를 입력하고 엔터를 치면 됩니다.


여기까지 전화번호부 어플리케이션 만들기의 포스팅이 끝났습니다.

다음 포스팅부터는 Redux 에 대해서 다뤄보도록 하겠습니다.

감사합니다.


**참고 자료 (항상 감사드립니다)

https://velopert.com/reactjs-tutorials


*다녀가셨다는 표시는 공감으로 부탁드릴게요! (로그인 하지 않으셔도 공감은 가능합니다 ㅎㅎ)

Comments