본문 바로가기
웹 프론트엔드/React 리액트 (기초)

[React] 재활용 가능한 기본적인 Input 컴포넌트

by 지구인한군 2020. 10. 6.

2020/09/29 - [Web프론트엔드/리액트] - [React] 리액트 기초 관련 글 정리 (개발환경, 데이터, 컴포넌트 등)


 이때까지의 포스팅은 리액트의 가장 기초적인 내용이었다면, 지금부터는 그 내용을 토대로 좀 더 활용 가능한 것들을 다루도록 하겠습니다. 그래서 오늘은 가볍게 지난 시간에 다루었던 아이디, 비번 입력 Input 컴포넌트를 재활용 가능하도록 뼈대만 남기는 작업을 해보도록 하겠습니다. 그럼 Input.jsx 만들어보시죠!

 

// ..\test_project\src\components\Input.jsx

import React, { PureComponent } from "react";
import PropTypes from "prop-types";

class Input extends PureComponent {
  constructor(props) {
    super(props);
    this.state = {
      value: props.value, // 상위 프로퍼티로 초기화
      isInputError: false, // 입력 오류가 있는지
      isFirstFocus: false, // 처음 입력창 포커스
    };

    // 콜백 함수 바인딩
    this.setRef = this.setRef.bind(this);
    this.handleChange = this.handleChange.bind(this);
    this.handleFocus = this.handleFocus.bind(this);
  }

  // ref 프로퍼티 연결
  setRef(ref) {
    this.ref = ref;
  }

  // 입력창 변경 이벤트
  handleChange(e) {
    const { name, onChange } = this.props;
    console.log(
      `handleChange() name : ${name} , e.target.value : ${e.target.value}`
    );

    // 에러 체크 변수
    let checkError = false;

    // 변경된 스테이트 값
    this.setState({ isInputError: checkError, value: e.target.value });

    // 상위 컴포넌트 콜백 함수 실행
    onChange(name, e.target.value);
  }

  // 입력창에 포커스
  handleFocus(e) {
    const { name, onFocus } = this.props;
    console.log(
      `handleFocus() name : ${name} , e.target.value : ${e.target.value}`
    );

    // 처음 포커스시
    if (this.state.isFirstFocus === false) {
      console.log(
        `First on focus -> name : ${name} , e.target.value : ${e.target.value}`
      );
      this.setState({ isFirstFocus: true });
    }

    // 상위 컴포넌트 콜백 함수 실행
    onFocus(name, e.target.value);
  }

  // 컴포넌트 마운트
  componentDidMount() {
    // 포커스 맞추기
    if (this.props.autoFocus) {
      this.ref.focus();
    }
  }

  render() {
    // 프로퍼티 받아서 화면 출력
    const { label, name, type, errorMessage } = this.props;
    return (
      <label>
        {label}
        <input
          id={`input_${name}`}
          value={this.state.value}
          type={type}
          ref={this.setRef}
          onChange={this.handleChange}
          onFocus={this.handleFocus}
        />
        {this.state.isInputError && errorMessage}
      </label>
    );
  }
}

Input.propTypes = {
  label: PropTypes.string,
  name: PropTypes.string.isRequired,
  value: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
  type: PropTypes.oneOf(["text", "password", "number", "price"]),
  autoFocus: PropTypes.bool,
  errorMessage: PropTypes.string,
  onChange: PropTypes.func,
  onFocus: PropTypes.func,
};

Input.defaultProps = {
  value: "",
  type: "text",
  autoFocus: false,
  onChange: () => {},
  onFocus: () => {},
};

export default Input;

 

// ..\test_project\src\App.js

import React, { Component } from "react";
import Input from "./components/Input";

class App extends Component {
  render() {
    return (
      <div>
        <Input name="id" autoFocus={true} />
        <br />
        <Input name="pass" type="password" />
      </div>
    );
  }
}

export default App;

 

 지난 포스팅인 아이디, 비번 입력 Input 컴포넌트를 보신 분들은 아시겠지만, 재활용이 가능하도록 뼈대는 남기고 아이디 비번 관련 기능들은 전부 삭제했습니다. 하지만 아직 범용적으로 사용할 Input 컴포넌트라 하기에는 부족한 부분이 너무 많습니다. 다음 포스팅은 스타일을 적용하는 방법을 다루도록 하겠습니다.

 

오늘은 참 가볍죠?


2020/10/06 - [Web프론트엔드/리액트] - [React] 테스트 도구인 스토리북(storybook)을 사용해보자

댓글