JS에서 React로 구현하기(1) : 로그인 버튼 활성화

Yeseul·2021년 5월 4일
1
post-thumbnail

이메일 형식에 맞는 아이디를 입력하고, 비밀번호 5글자 이상 입력하면 로그인 버튼이 활성화된다.

그전에 html, css, 그리고 vanilla JS로 클론 코딩한 인스타그램 페이지들을 이번엔 리액트로 구현해보았다. JS에서와 리액트에서 이벤트 핸들링하는 방법이 어떻게 다른지 이해하고 연습할 수 있는 시간이었다 :) 해보니 따로 DOM에 접근하지 않아도 되기 때문에 훨씬 간단하고 쉽게 느껴졌다.


로그인 컴포넌트 구현하기

우선 로그인 페이지 (로그인 컴포넌트)의 기본 구조를 만든다.
리액트 라우터의 withRouterLink 를 사용하여 한 페이지 내에서 경로만 이동할 수 있도록 라우팅 기능만 추가해주었다.

import React, { Component } from 'react';
import { withRouter, Link } from 'react-router-dom';
import './Login.scss';

class LoginYeseul extends Component {
  goToMain = () => {
    this.props.history.push('/main-yeseul');
  };

  render() {
    return (
      <main className="login give-border">
        <h1 className="logo">westagram</h1>
        <form className="login-form">
          <div className="login-form__input-box">
            <input
              type="text" name="inputId"
              placeholder="전화번호, 사용자 이름 또는 이메일"/>
            <input
              type="password" name="inputPw"
              placeholder="비밀번호"/>
          </div>
          <button
            type="button" onClick={this.goToMain}>
            로그인
          </button>
        </form>
        <Link
          to="https://www.instagram.com/accounts/password/reset/"
          className="find-pw">
          비밀번호를 잊으셨나요?
        </Link>
      </main>
    );
  }
}

export default withRouter(LoginYeseul);

사용자 입력값 받아오기

JS에서는 DOM에 접근하여 엘리먼트.value 형태로 사용자의 입력값을 받아올 수 있었지만 리액트에서는 완전히 달랐다. 우선 폼 내부의 엘리먼트는 그 값이 엘리먼트 자체로 제어되기 때문에 input의 value값을 컴포넌트 내부 state 값에 저장하여 state값으로 제어한다. 제어하는 과정을 현재 상황(로그인 버튼 구현)에서 정리하면 다음과 같다.

이벤트 핸들러는 인라인 형태로 붙여주어야 하고 이때 표기법은 카멜케이스를 따른다. (ex. onclick -> onClick)

  1. 컴포넌트 내부의 state에 엘리먼트의 초기값을 저장한다.
    this.state = { inputId : '', ...}

  2. state에 저장된 값을 input 엘리먼트의 value값으로 전달한다. (연결시킨다)
    <input value={this.state.inputId} />

  3. input 엘리먼트의 value값이 변할 때마다 변한 값을 다시 state에 저장한다.
    onChange={ e => this.setState({ [e.target.name] : e.target.value }) }

  4. state값이 변하면 렌더 함수가 다시 호출되고 input의 value값은 state에 저장된 값을 다시 전달받는다. (온전히 state에 의해 제어된다)

state로 제어한다는 말은, 이제 state의 값으로 엘리먼트의 value도 바꿔줄 수 있다는 말과 같다. 예를 들어 로그인 버튼을 눌렀을 때 폼 엘리먼트의 모든 값을 리셋한다고 하면 this.state.id = '' 처럼 리셋을 시킬 수 있다.

constructor() {
  constructor(props) {
    super(props);
    this.state = {
      inputId: '',
      inputPw: '',
    };
  }
  
handleInput = e => {
  const { name, value } = e.target;
  this.setState({
    [name] : value
  });
}
  
  render() {
    const { inputId, inputPw } = this.state;
    return() {
      ...
      <input
      type="text" name="inputId"
      value={inputId} onChange={this.handleInput}
      placeholder="전화번호, 사용자 이름 또는 이메일"/>
      <input
      type="password" name="inputPw"
      value={inputPw} onChange={this.handleInput}
      placeholder="비밀번호"/>
      ...
  }

사용자 입력값에 따라 버튼활성화 하기

버튼 활성화는 state에 저장된 값을 가져와 그에 따라 엘리먼트의 disabled 속성을 true || false로 바꿔주면 된다.
이메일 형식의 아이딜 검사를 위해 정규표현식을 사용했다.

render() {
  const checkId = /^\w[\w\-.]*@\w+\.\w{2,}/;
  
  return(
    ...
    <button
      type="button"
      onClick={this.goToMain}
  disabled={!(checkId.test(inputId) && inputPw.length > 5)}
    >
    ...
  );
}

배운 것

  • 구조 분해 할당
    const { inputId, inputPw } = this.state;
    this.state.inputId 해야할 것을 저렇게 구조분해 할당을 하면 inputId 로 접근이 가능하다.

  • 계산된 속성으로 객체에 접근하기
    this.setState({ [e.target.name] : e.target.value })
    [] 를 사용하면 변수명으로 객체 키에 접근할 수 있듯이 계산된 속성값으로 키에 접근이 가능하다. 이렇게 하면 중복된 코드를 줄일 수 있다!


주의할 점

this가 가리키는 객체가 달라질 수 있는 문제때문에 컴포넌트 내부의 메소드는 되도록 화살표 함수로 정의하도록 한다.
일반 함수로 정의할 경우 함수를 전달할 때 bind함수로 this를 인자로 따로 전달해주어야 오류가 없다.

handleInput() {
  this.setState({...});
}

render() {
  return(
    ...
    <input
    onChage={this.handleInput.bind(this)} />
    ...
  )
}

// 또는
constructor() {
  super();
  this.state(...);
  this.handleInput = this.handleInput.bind(this);
}

handleInput() {
  this.setState({...});
}

React 공식문서 | 이벤트 처리하기
React 공식문서 | 조건부 렌더링
React 공식문서 | 폼

profile
하루하루, 차곡차곡 👩🏻‍💻

0개의 댓글