🍊 λ‚‘κΉ‘νŒœ_07 : Early return

BoriΒ·2022λ…„ 2μ›” 1일
3

Project_Kkingkkang.farm

λͺ©λ‘ 보기
7/9
post-thumbnail

진행 상황

signup.tsx

  • 문제점 : 이메일을 μž‘μ„±ν•˜λ‹€κ°€ μ§€μš°λ©΄ μ‚¬μš© κ°€λŠ₯ν•œ 이메일 μž…λ‹ˆλ‹€. 문ꡬ가 사라지지 μ•ŠλŠ”λ‹€.

  • μ½”λ“œμ˜ 일뢀

// signup.tsx
const Signup: NextPage = () => {
  ...
  const [emailValid, setEmailValid] = useState('');
  const handleBlur = async () => {
    const res = await axios(`${API_ENDPOINT}/user/emailvalid`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      data: JSON.stringify({
        user: {
          email: getValues().email,
        },
      }),
    });
    setEmailValid(res.data.message);
  };
  const handleChange = () => {
    setEmailValid('');
  };
  
  ...

  return (
    ...
    <BoxInp>
      <Label htmlFor="email">
        이메일
        <Input
        type="email"
        id="email"
        placeholder="이메일 μ£Όμ†Œλ₯Ό μž…λ ₯ν•΄ μ£Όμ„Έμš”."
        required
        {...register('email', {
          required: true,
          pattern: regExpEm,
          onBlur: handleBlur,
          onChange: handleChange,
        })}
        />
      </Label>
      {errors?.email?.type === 'required' && (
        <TxtError>* 이메일을 μž…λ ₯ν•΄μ£Όμ„Έμš”</TxtError>
      )}
      {errors?.email?.type === 'pattern' && (
        <TxtError>* 잘λͺ»λœ 이메일 ν˜•μ‹μž…λ‹ˆλ‹€.</TxtError>
      )}
      {emailValid === 'μ‚¬μš© κ°€λŠ₯ν•œ 이메일 μž…λ‹ˆλ‹€.' && (
        <TxtSuccess>* μ‚¬μš© κ°€λŠ₯ν•œ 이메일 μž…λ‹ˆλ‹€.</TxtSuccess>
      )}
      {emailValid === '이미 κ°€μž…λœ 이메일 μ£Όμ†Œ μž…λ‹ˆλ‹€.' && (
        <TxtError>* 이미 κ°€μž…λœ 이메일 μ£Όμ†Œμž…λ‹ˆλ‹€.</TxtError>
      )}
    </BoxInp>
	...
  );
};

export default Signup;
  • ν•΄κ²° 방법 : handleBlur 내에 early return μ‚¬μš©
const handleBlur = async () => {
  // λ°˜ν™˜κ°’ 없이 ν•¨μˆ˜κ°€ μ’…λ£Œ (early return)
  if (errors?.email?.type === 'pattern') return;
  
  const res = await axios(`${API_ENDPOINT}/user/emailvalid`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    data: JSON.stringify({
      user: {
        email: getValues().email,
      },
    }),
  });
  setEmailValid(res.data.message);
};

πŸ“Ž Early return / Return Early Pattern

πŸ”Έ The Return Early Pattern Explained with JavaScript Examples

  • ν•¨μˆ˜ λ‚΄μ˜ else문의 수λ₯Ό 0으둜 쀄일 수 μžˆλ‹€.

    • 전체 μ½”λ“œμ˜ 양을 쀄일 수 μžˆλ‹€.
    • 논리적 λ³΅μž‘μ„±(logical complexity)을 μ€„μ—¬μ„œ μ½”λ“œμ˜ 길이λ₯Ό 쀄일 수 μžˆλ‹€.
    • 가독성이 쒋아진닀.
  • early return의 λ³Έμ§ˆμ€ ν•¨μˆ˜ 내에 else문을 if문에 return ν‚€μ›Œλ“œλ‘œ λŒ€μ²΄ν•˜λŠ” 것

  • νŠΉμ • 쑰건 ν•˜μ— λ‹€λ₯΄κ²Œ λ™μž‘ν•˜λŠ” ν•¨μˆ˜ μ˜ˆμ‹œ

function willItBlend(someObject) {
  let itWillBlend;

  if (typeof someObject === 'object') { 
  	if (someObject.blendable === 'It will blend') {
  		itWillBlend = true;
  	} else {
  	itWillBlend = false;
  	}
  } else {
  	itWillBlend = false;
  }

  return itWillBlend; 
}
  • early return νŒ¨ν„΄μœΌλ‘œ μ½”λ“œ μž‘μ„±
    • λΆˆν•„μš”ν•œ μ½”λ“œλ₯Ό 제거 => elseλ¬Έ 제거
    • μ½”λ“œκ°€ κ°„κ²°ν•΄μ Έμ„œ 가독성이 높아짐
function willItBlend(someObject) {  
  if (typeof someObject !== 'object') {
    return false;
  }

  if (someObject.blendable === 'It will blend') {
    return false;
  } 

  return true; 
}

λ¦¬νŒ©ν† λ§_1 : ν•˜λ‚˜μ˜ if문을 λ¦¬νŒ©ν† λ§

function willItBlend(someObject) {  
  if (typeof someObject !== 'object' || someObject.blendable === 'It will blend') {
    return false
  }
 
  return true;
}

λ¦¬νŒ©ν† λ§_2 : μ‚Όν•­μ—°μ‚°μžλ₯Ό μ΄μš©ν•œ λ¦¬νŒ©ν† λ§

function willItBlend(someObject) {  
  return typeof someObject !== 'object' || someObject.blendable === 'It will blend' ? false : true
}

πŸ”Έ Early Returns in JavaScript

  • early return : ν•¨μˆ˜μ˜ λ‚˜λ¨Έμ§€κ°€ 싀행될 λ•ŒκΉŒμ§€ 기닀리지 μ•Šκ³ , 쑰건문의 κ²°κ³Όλ₯Ό μ¦‰μ‹œ λ°˜ν™˜ν•  수 μžˆλ„λ‘ ν•œλ‹€.
  • early return을 μ‚¬μš©μ΄ 가독성을 λ†’μ΄λŠ” 방법인가?
    • if/else문의 μ‚¬μš©λ³΄λ‹€ μ—¬λŸ¬ 개의 ifλ¬Έκ³Ό returnν‚€μ›Œλ“œμ˜ μ‚¬μš©μ€ ν•œ λˆˆμ— μ΄ν•΄ν•˜κΈ° μ–΄λ ΅κ²Œ λŠκ»΄μ§€κΈ°λ„ ν•œλ‹€.
  • 가독성보닀 μ€‘μš”ν•œ 것은 single exit function보닀 μ–Όλ§ˆλ‚˜ μ„±λŠ₯이 쒋은가?
    => Tests : JavaScript benchmark playground

* ops/sec = Operations Per Second, μ΄ˆλ‹Ή μž‘μ—… 수

πŸ“Ž React Hook Form

πŸ”Έ useForm

getValues: (payload?: string | string[]) => Object

  • 폼의 κ°’(value)λ₯Ό 읽을 λ•Œ μ‚¬μš©
  • watch와 차이점 : getValues λŠ” 트리거λ₯Ό λ¦¬λ Œλ”λ§ν•˜κ±°λ‚˜ input κ°’μ˜ λ³€ν™”λ₯Ό subscribe ν•˜μ§€ μ•ŠλŠ”λ‹€.
    • getValues() : 폼의 전체 값을 읽음
    • getValues('inputName') : ν•΄λ‹Ή name μ†μ„±μ˜ 값을 읽음
    • getValues(['inputName1', 'inputName2']) : μ§€μ •λœ μ—¬λŸ¬ input의 값을 읽음
import React from "react";
import { useForm } from "react-hook-form";

type FormInputs = {
  test: string
  test1: string
}

export default function App() {
  const { register, getValues } = useForm<FormInputs>();

  return (
    <form>
      <input {...register("inputName1")} />
      <input {...register("inputName2")} />

      <button
        type="button"
        onClick={() => {
          const values = getValues(); // { inputName1: "inputName1-inputValue", inputName2: "inputName2-inputValue" }
          const singleValue = getValues("inputName1"); // "inputName1-inputValue"
          const multipleValues = getValues(["inputName1", "inputName2"]);
          // ["inputName1-inputValue", "inputName2-inputValue"]
        }}

        Get Values
      </button>
    </form>
  );
}

πŸ”Έ μ΄λ©”μΌλ‘œ νšŒμ›κ°€μž…ν•˜λŠ” νŽ˜μ΄μ§€ μ½”λ“œ

import styled from '@emotion/styled';
import axios from 'axios';
import { useState } from 'react';
import { useForm } from 'react-hook-form';
import { API_ENDPOINT, BORDER, BUTTON, COLORS } from '../../constants';

export const SignupEmail = ({
  setPages,
  setUserInfo,
}: {
  setPages: (value: boolean) => void;
  setUserInfo: (value: { email: string; password: string }) => void;
}) => {
  const regExpEm =
    /^[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*@[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*\.[a-zA-Z]{2,3}$/i;
  const regExgPw = /^[A-Za-z0-9]{6,12}$/;

  const [emailValid, setEmailValid] = useState('');
  const {
    register,
    getValues,
    formState: { errors, isValid },
  } = useForm<{ email: string; password: string }>({ mode: 'onChange' });

  const handleBlur = async () => {
    if (errors?.email?.type === 'pattern') return;

    const res = await axios(`${API_ENDPOINT}/user/emailvalid`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      data: JSON.stringify({
        user: {
          email: getValues().email,
        },
      }),
    });
    setEmailValid(res.data.message);
  };

  const handleChange = () => {
    setEmailValid('');
  };

  const goToSetProfile = () => {
    setPages(false);
    setUserInfo({
      email: getValues().email,
      password: getValues().password,
    });
  };

  return (
    <MainSignup>
      <TitleMain>μ΄λ©”μΌλ‘œ νšŒμ›κ°€μž…</TitleMain>
      <FormLogin>
        <BoxInp>
          <Label htmlFor="email">
            이메일
            <Input
              type="email"
              id="email"
              placeholder="이메일 μ£Όμ†Œλ₯Ό μž…λ ₯ν•΄ μ£Όμ„Έμš”."
              required
              {...register('email', {
                required: true,
                pattern: regExpEm,
                onBlur: handleBlur,
                onChange: handleChange,
              })}
            />
          </Label>
          {errors?.email?.type === 'required' && (
            <TxtError>* 이메일을 μž…λ ₯ν•΄μ£Όμ„Έμš”</TxtError>
          )}
          {errors?.email?.type === 'pattern' && (
            <TxtError>* 잘λͺ»λœ 이메일 ν˜•μ‹μž…λ‹ˆλ‹€.</TxtError>
          )}
          {emailValid === 'μ‚¬μš© κ°€λŠ₯ν•œ 이메일 μž…λ‹ˆλ‹€.' && (
            <TxtSuccess>* μ‚¬μš© κ°€λŠ₯ν•œ 이메일 μž…λ‹ˆλ‹€.</TxtSuccess>
          )}
          {emailValid === '이미 κ°€μž…λœ 이메일 μ£Όμ†Œ μž…λ‹ˆλ‹€.' && (
            <TxtError>* 이미 κ°€μž…λœ 이메일 μ£Όμ†Œμž…λ‹ˆλ‹€.</TxtError>
          )}
        </BoxInp>
        <BoxInp>
          <Label htmlFor="password">
            λΉ„λ°€λ²ˆν˜Έ
            <Input
              type="password"
              id="password"
              placeholder="λΉ„λ°€λ²ˆν˜Έλ₯Ό μ„€μ •ν•΄ μ£Όμ„Έμš”."
              required
              {...register('password', { required: true, pattern: regExgPw })}
            />
          </Label>
          {errors?.password?.type === 'pattern' && (
            <TxtError>
              * λΉ„λ°€λ²ˆν˜ΈλŠ” 영문(λŒ€/μ†Œλ¬Έμž ꡬ뢄), 숫자 μ‘°ν•©ν•˜μ—¬ 6~12자리둜 μž…λ ₯ν•΄
              μ£Όμ„Έμš”.
            </TxtError>
          )}
        </BoxInp>
        <BtnNext
          type="button"
          onClick={goToSetProfile}
          disabled={!isValid || emailValid !== 'μ‚¬μš© κ°€λŠ₯ν•œ 이메일 μž…λ‹ˆλ‹€.'}
        >
          λ‹€μŒ
        </BtnNext>
      </FormLogin>
    </MainSignup>
  );
};

2개의 λŒ“κΈ€

comment-user-thumbnail
2022λ…„ 2μ›” 2일

μš°μ™• λ„ˆλ¬΄ μ‹ κΈ°ν•΄μš”~

1개의 λ‹΅κΈ€