Fetch 사용해 API를 불러와 response에서 status 200이 나오면 성공

회원가입

import React, { Component } from "react";
import { Link } from "react-router-dom";
import DaumPostcode from "react-daum-postcode";
import styled from "styled-components";
import * as URL from "../../../config";

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

    this.state = {
      even: true,
      open: false,
      id: "",
      pwd: "",
      pwdCheck: "",
      koreanName: "",
      englishName: "",
      birthDate: "",
      gender: "2",
      cpNum: "",
      pNum: "",
      authOpen: false,
      authRes: "",
      authNum: "",
      authBl: false,
      zipCode: "",
      realAddress: "",
      detailAddress: "",
      mail: "",
      selectValue: "",
      selectArr: [],
      error: {
        id: "",
        idColor: "",
        pwd: "",
        pwdCheck: "",
        koreanName: "",
        englishName: "",
        birthDate: "",
        cpNum: "",
        pNum: "",
        authNum: "",
        mail: ""
      }
    };
  }

  componentDidMount() {
    this.selectJob();
  }

  componentDidUpdate(prevProps, prevState) {
    if (prevState !== this.state) {
      this.props.onKeyUp(this.state);
      this.props.onClick(this.state);
      this.props.onChange(this.state);
    }
  }

  selectJob = async e => {
    const selectFetch = await fetch(`${URL.SMS_URL}/job`, {
      method: "GET"
    });

    const selectFetchJson = await selectFetch.json();

    if (selectFetch.status === 200) {
      this.setState({
        selectArr: await selectFetchJson.jobDate
      });
    }
  };

  handleChange = e => {
    this.setState({
      gender: e.target.value
    });
  };

  handleAuth = e => {
    if (this.state.cpNum.length < 11) {
      alert("휴대폰 번호를 입력하세요.");

      this.setState({
        authOpen: false
      });
    } else {
      this.setState({
        authOpen: true
      });

      fetch(`${URL.SMS_URL}/sms-auth`, {
        method: "POST",
        body: JSON.stringify({
          mobile: this.state.cpNum
        })
      })
        .then(res => res.json())
        .then(res =>
          this.setState({
            authRes: res.AUTHENTICATION
          })
        );
    }
  };

  hadnleAuthComplete = e => {
    alert(
      this.state.authNum === `${this.state.authRes}`
        ? "인증완료되었습니다."
        : "인증실패하였으니 다시 입력해주십시오."
    );

    this.setState(previousState => {
      return {
        authBl:
          previousState.authNum === `${previousState.authRes}` ? true : false
      };
    });
  };

  handleAddressClick = e => {
    this.setState({
      open: !this.state.open
    });
  };

  handleAddress = data => {
    this.setState({
      open: !this.state.open,
      zipCode: data.zonecode,
      realAddress: data.roadAddress
    });
  };

  handleSelect = e => {
    this.setState({
      selectValue: e.target.value
    });
  };

  handleInput = async e => {
    const target = e.target;
    const name = target.name;
    const error = this.state.error;
    let idValidError = null;
    const { pwd, pwdCheck, birthDate } = this.state;

    // console.log(URL.SERVER_URL + "/dataId.json");
    console.log("첫번쨰", e.target.value);

    switch (name) {
      case "id":
        idValidError = await this.idCont(target.value);
        error.id = idValidError.messeage;
        error.idColor = idValidError.idColor;

        break;

      case "pwd":
        error.pwd =
          /^(?=.*[a-z])(?=.*[0-9]).{8,20}/.test(target.value) === false
            ? "8~20자의 영문과 숫자를 혼용하여 입력주세요."
            : "";

        break;
      case "pwdCheck":
        error.pwdCheck =
          pwd === target.value
            ? ""
            : pwd.length > 0 && "비밀번호가 일치하지 않습니다.";

        break;
      case "koreanName":
        error.koreanName = /^[가-힣]+$/.test(target.value)
          ? ""
          : "한글로 정확하게 입력해주세요.";
        break;

      case "englishName":
        error.englishName = /^[a-zA-Z\\s]+$/.test(target.value)
          ? ""
          : "영어로 정확하게 입력해주세요.";
        break;
      case "birthDate":
        error.birthDate = /^(19[0-9][0-9]|20\\d{2})[\\/\\-](0[0-9]|1[0-2])[\\/\\-](0[1-9]|[1-2][0-9]|3[0-1])$/.test(
          target.value
        )
          ? ""
          : "생년월일을 정확하게 입력해주세요.";
        break;

      case "cpNum":
        error.cpNum =
          /(01[016789])(\\d{4}|\\d{3})\\d{4}$/g.test(target.value) ||
          target.value.length === 0
            ? ""
            : "핸드폰 번호를 입력해주세요.";

        break;

      case "authNum":
        error.authNum =
          /[^0-9]/g.test(target.value) || target.value.length === 0
            ? "숫자를 입력해주세요."
            : "";

        break;

      case "pNum":
        error.pNum = /^0(2|3[1-3]|4[1-4]|5[1-5]|6[1-4])-?\\d{3,4}-?\\d{4}$/.test(
          target.value
        )
          ? ""
          : "전화번호를 입력해주세요.";

        break;

      case "mail":
        error.mail =
          target.length < 1
            ? "이메일을 입력해주세요."
            : /^([0-9a-zA-Z_\\.-]+)@([0-9a-zA-Z_-]+)(\\.[0-9a-zA-Z_-]+){1,2}$/.test(
                target.value
              )
            ? ""
            : "이메일 형식을 다시 확인해주세요.";

        break;
      default:
        "";
        break;
    }

    this.setState({
      [target.name]: target.value,
      error
    });
  };

  idCont = async param => {
    if (param === "") {
      return {
        stat: false,
        messeage: "아이디를 입력해주세요.",
        idColor: "red"
      };
    } else if (/^(?=.*[a-z])(?=.*[0-9]).{8,20}/.test(param) === false) {
      // $ 달러는 문자의 마지막
      // ^ 꺽쇠는 문자의 시작

      return {
        stat: false,
        messeage: "8~20자의 영문과 숫자를 혼용하여 입력해주세요.",
        idColor: "red"
      };
    }

    if (this.state.even) {
      this.setState({
        even: false
      });

      this.setState({
        even: true
      });

      const idDuplicateCheck = await fetch(`${URL.SMS_URL}/id-verification`, {
        method: "POST",
        body: JSON.stringify({
          account: param
        })
      });

      return {
        stat: idDuplicateCheck.ok && idDuplicateCheck.status === 400,
        messeage:
          idDuplicateCheck.status === 400
            ? " 중복된 아이디입니다."
            : "사용가능한 아이디입니다.",
        idColor: idDuplicateCheck.status === 400 ? "red" : "yellow"
      };
    }

    return {
      stat: false,
      messeage: "잠시 기다려주십시오.",
      idColor: "red"
    };
  };

  hanldeCancel = e => {
    this.props.history.push({
      pathname: "/joinStep1"
    });
  };

  render() {
    const {
      open,
      id,
      pwd,
      pwdCheck,
      koreanName,
      englishName,
      birthDate,
      cpNum,
      pNum,
      authNum,
      zipCode,
      realAddress,
      detailAddress,
      mail,
      selectValue,
      selectArr,
      error
    } = this.state;

    return (

    );
  }
}

export default JoinStep2;

Render 내용

<SectionInputBoxCont>
        <SectionInputContainer>
          <SectionInputTitle>멤버십 정보</SectionInputTitle>
          <div>
            <SectionInput
              onKeyUp={e => this.handleInput(e)}
              name="id"
              defaultValue={id}
              maxLength="20"
              placeholder="아이디"
              type="text"
            />
            <SectionInputTextId color={error.idColor}>
              {error.id}
            </SectionInputTextId>
          </div>
          <div>
            <SectionInput
              defaultValue={pwd}
              onKeyUp={this.handleInput}
              maxLength="20"
              name="pwd"
              placeholder="비밀번호"
              type="password"
            />
            <SectionInputText>{this.state.error.pwd}</SectionInputText>
          </div>
          <div>
            <SectionInput
              onKeyUp={this.handleInput}
              defaultValue={pwdCheck}
              maxLength="20"
              name="pwdCheck"
              placeholder="비밀번호 확인"
              type="password"
            />
            <SectionInputText>{this.state.error.pwdCheck}</SectionInputText>
          </div>
        </SectionInputContainer>
        <SectionInputContainer>
          <SectionInputTitle>개인 정보</SectionInputTitle>
          <div>
            <SectionInput
              onKeyUp={this.handleInput}
              defaultValue={koreanName}
              name="koreanName"
              placeholder="성함"
              type="text"
            />
            <SectionInputText>{this.state.error.koreanName}</SectionInputText>
          </div>
          <div>
            <SectionInput
              onKeyUp={this.handleInput}
              defaultValue={englishName}
              name="englishName"
              placeholder="성함(영문)"
              type="text"
            />
            <SectionInputText>{this.state.error.englishName}</SectionInputText>
          </div>
          <SectionInputBox_v2>
            <SectionInputBox_v2_InputBox>
              <SectionInput
                onKeyUp={this.handleInput}
                defaultValue={birthDate}
                maxLength="10"
                name="birthDate"
                placeholder="생년월일(YYYY-MM-DD 형식)"
                type="text"
              />
              <SectionInputText>{this.state.error.birthDate}</SectionInputText>
            </SectionInputBox_v2_InputBox>
            <SectionInputBox_v2_CheckboxBox>
              <SectionInputBox_v2_Checkbox
                onChange={e => this.handleChange(e)}
                value={"2"}
                checked={this.state.gender === "2"}
                id="gender_male"
                name="gender"
                type="radio"
              />
              <label htmlFor="gender_male">
                <SectionInputBox_v2_CheckboxIcon>
                  checkbox
                </SectionInputBox_v2_CheckboxIcon>
                남자
              </label>
              <SectionInputBox_v2_Checkbox
                onChange={e => this.handleChange(e)}
                value={"1"}
                checked={this.state.gender === "1"}
                id="gender_female"
                name="gender"
                type="radio"
              />
              <label htmlFor="gender_female">
                <SectionInputBox_v2_CheckboxIcon>
                  checkbox
                </SectionInputBox_v2_CheckboxIcon>
                여자
              </label>
            </SectionInputBox_v2_CheckboxBox>
          </SectionInputBox_v2>
          <SectionInputBox>
            <SectionInput
              onKeyUp={this.handleInput}
              defaultValue={cpNum}
              maxLength="11"
              name="cpNum"
              placeholder="휴대전화번호 11자"
              type="text"
            />
            <SectionInputButton type="button" onClick={this.handleAuth}>
              인증
            </SectionInputButton>
            <SectionInputText>{this.state.error.cpNum}</SectionInputText>
          </SectionInputBox>
          {this.state.authOpen && (
            <SectionInputBox>
              <SectionInput
                onKeyUp={this.handleInput}
                defaultValue={authNum}
                name="authNum"
                maxLength="6"
                placeholder="인증번호 6자리"
                type="text"
              />
              <SectionInputButton
                type="button"
                onClick={this.hadnleAuthComplete}
              >
                확인
              </SectionInputButton>
              <SectionInputText>{this.state.error.authNum}</SectionInputText>
            </SectionInputBox>
          )}
          <div>
            <SectionInput
              onKeyUp={this.handleInput}
              defaultValue={pNum}
              name="pNum"
              placeholder="유선전화"
              type="text"
            />
            <SectionInputText>{this.state.error.pNum}</SectionInputText>
          </div>
          <SectionInputBox>
            <SectionInput
              placeholder="우편번호"
              value={zipCode}
              readOnly
              type="text"
            />
            <SectionInputButton type="button" onClick={this.handleAddressClick}>
              주소 찾기
            </SectionInputButton>
          </SectionInputBox>
          {open && (
            <DaumPostcode onComplete={this.handleAddress} autoClose={true} />
          )}
          <div>
            <SectionInput
              value={realAddress}
              placeholder="기본 주소"
              readOnly
              type="text"
            />
          </div>
          <div>
            <SectionInput
              onKeyUp={this.handleInput}
              defaultValue={detailAddress}
              name="detailAddress"
              placeholder="상세 주소(선택)"
              type="text"
            />
          </div>
          <div>
            <SectionInput
              onKeyUp={this.handleInput}
              defaultValue={mail}
              name="mail"
              placeholder="이메일"
              type="text"
            />
            <SectionInputText>{this.state.error.mail}</SectionInputText>
          </div>
          <div>
            <SectionSelect
              name=""
              id=""
              onChange={this.handleSelect}
              value={selectValue}
            >
              <option value="">직업(선택)</option>
              {selectArr.map((item, idx) => {
                return (
                  <option key={idx} value={idx + 1}>
                    {item.name}
                  </option>
                );
              })}
            </SectionSelect>
          </div>
        </SectionInputContainer>
      </SectionInputBoxCont>

로그인

import React, { useState, useReducer } from "react";
import { BrowserRouter as Route, withRouter, Link } from "react-router-dom";
import styled from "styled-components";
import * as URL from "../../config";

const Login = ({ location, history }) => {
  function reducer(state, action) {
    return {
      ...state,
      [action.name]: action.value
    };
  }

  const [idErrorStatus, SetIdError] = useState("");
  const [pwdErrorStatus, SetPwdError] = useState("");

  const [state, dispatch] = useReducer(reducer, {
    id: "",
    pwd: ""
  });

  const { id, pwd } = state;

  const onChangeInput = e => {
    dispatch(e.target);
  };

  const onClickLogin = async e => {
    if (id.length === 0 && pwd.length === 0) {
      console.log("a");
      SetIdError("아이디를 입력해주세요.");
      SetPwdError("비밀번호를 입력해주세요.");
    } else {
      const loginCheck = await fetch(`${URL.SMS_URL}/login`, {
        method: "POST",
        body: JSON.stringify({
          account: state.id,
          password: state.pwd
        })
      });

      const resStatus = loginCheck.status;
      const res = await loginCheck.json();

      if (resStatus === 200) {
        window.sessionStorage.setItem("Authorization", res.Authorization);
        history.push("/");
      } else {
        SetIdError("");
        SetPwdError(
          "아이디, 비밀번호를 확인해주세요. 클럽 라한에 등록되지 않았거나 가입정보와 일치하지 않습니다."
        );
      }
    }
  };

  return (
  );
};

Render 내용

    <>
      <LoginWrap>
        <LoginCont>
          <LoginBox>
            <LoginSubTitle>LOGIN</LoginSubTitle>
            <LoginTitle>
              클럽 라한에 오신 것을 환영합니다. 포인트 혜택 및 다양한 서비스를
              <span>이용해보세요.</span>
            </LoginTitle>
            <LoginInputBox>
              <li>
                <LoginInput
                  onChange={onChangeInput}
                  name="id"
                  value={id}
                  type="text"
                  placeholder="아이디"
                />
                <LoginError>{idErrorStatus}</LoginError>
              </li>
              <li>
                <LoginInput
                  name="pwd"
                  value={pwd}
                  onChange={onChangeInput}
                  type="password"
                  placeholder="비밀번호"
                />
                <LoginError>{pwdErrorStatus}</LoginError>
              </li>
            </LoginInputBox>
            <div>
              <LoginBtn onClick={onClickLogin}>Login</LoginBtn>
            </div>
          </LoginBox>
        </LoginCont>
      </LoginWrap>
    </>