๐Ÿ’ป My Work/๐Ÿ”ฅ React

[React/JS] Firebase - ๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณ€๊ฒฝ ๊ตฌํ˜„ํ•˜๊ธฐ

Jaeseo Kim 2022. 12. 16. 23:46
 

Firebase์—์„œ ์‚ฌ์šฉ์ž ๊ด€๋ฆฌ

Google์€ ํ‘์ธ ๊ณต๋™์ฒด๋ฅผ ์œ„ํ•œ ์ธ์ข…์  ํ‰๋“ฑ์„ ์ถ”๊ตฌํ•˜๊ธฐ ์œ„ํ•ด ๋…ธ๋ ฅํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ž์„ธํžˆ ์•Œ์•„๋ณด๊ธฐ ์ด ํŽ˜์ด์ง€๋Š” Cloud Translation API๋ฅผ ํ†ตํ•ด ๋ฒˆ์—ญ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. Switch to English ์˜๊ฒฌ ๋ณด๋‚ด๊ธฐ Firebase์—์„œ ์‚ฌ์šฉ

firebase.google.com

 

๋ณด์•ˆ์„ ์œ„ํ•ด ๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณ€๊ฒฝ์€ ์ฃผ๊ธฐ์ ์œผ๋กœ ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๐Ÿ˜

 

 

๊ทธ๋Ÿผ ๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณ€๊ฒฝ์„ ๊ตฌํ˜„ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค!

๊ตฌํ˜„ ์˜ˆ์‹œ
๊ตฌํ˜„ ์˜ˆ์‹œ

 

01. ์ปดํฌ๋„ŒํŠธ ๊ตฌํ˜„

์—ฌ๋Ÿฌ ๊ฐœ์˜ input ๊ตฌํ˜„์„ ์ž‘์„ฑํ•œ ๊ธ€์ž…๋‹ˆ๋‹ค.

 

[React/JS] useState - ์—ฌ๋Ÿฌ ๊ฐœ์˜ input ์ƒํƒœ ๊ด€๋ฆฌํ•˜๊ธฐ

์ €๋Š” ๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณ€๊ฒฝ์„ ์˜ˆ์‹œ๋กœ ๊ตฌํ˜„ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค! ์šฐ์„  ์ตœ์ข… ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค. ๐Ÿ˜Š import * as React from "react"; export default function PasswordChange() { // input ์ปดํฌ๋„ŒํŠธ์˜ id ์„ ์–ธ // ํ˜„์žฌ ๋น„๋ฐ€๋ฒˆํ˜ธ const CURRENT_PASSWORD =

avoc-o-d.tistory.com

 

์ปดํฌ๋„ŒํŠธ ๊ตฌํ˜„ ์˜ˆ์‹œ

๊ธฐ๋Šฅ ๊ตฌํ˜„์— ํ•„์š”ํ•œ ๋ถ€๋ถ„๋งŒ ๊ฐ€์ ธ์™”์Šต๋‹ˆ๋‹ค. ๐Ÿ˜† (์ฐธ๊ณ . ๋ฉ”ํ…Œ๋ฆฌ์–ผ ๋””์ž์ธ ์ปดํฌ๋„ŒํŠธ ์‚ฌ์šฉ)

// id
const CURRENT_PASSWORD = "currentPassword";
const NEW_PASSWORD = "newPassword";
const NEW_PASSWORD_CONFIRM = "newPasswordConfirm";

// input ๋ณ€์ˆ˜
const [inputs, setInputs] = React.useState({
    currentPassword: "", // ํ˜„์žฌ ๋น„๋ฐ€๋ฒˆํ˜ธ
    newPassword: "", // ์ƒˆ ๋น„๋ฐ€๋ฒˆํ˜ธ
    newPasswordConfirm: "", // ์ƒˆ ๋น„๋ฐ€๋ฒˆํ˜ธ ํ™•์ธ
});
const { currentPassword, newPassword, newPasswordConfirm } = inputs; // ๋น„๊ตฌ์กฐํ™” ํ• ๋‹น์„ ํ†ตํ•ด ๊ฐ’ ์ถ”์ถœ

// ๋น„๋ฐ€๋ฒˆํ˜ธ ์ž…๋ ฅ
const handlePasswordInput = (event) => {
    const { id, value } = event.target;

    setInputs({
      ...inputs, // ๊ธฐ์กด์˜ input ๊ฐ์ฒด๋ฅผ ๋ณต์‚ฌํ•œ ๋’ค
      [id]: value, // name ํ‚ค๋ฅผ ๊ฐ€์ง„ ๊ฐ’์„ value ๋กœ ์„ค์ •
    });
};

// ๋น„๋ฐ€๋ฒˆํ˜ธ ํผ ์ œ์ถœ ํ•จ์ˆ˜
async function handleSubmit(event) {
	...
}

// ๋ณ€๊ฒฝํ•˜๊ธฐ ๋ฒ„ํŠผ ํ™œ์„ฑํ™”
const [isDisabled, setIsDisabled] = React.useState(true);
React.useEffect(() => {
    if (
      currentPassword === "" ||
      newPassword === "" ||
      newPasswordConfirm === ""
    )
      setIsDisabled(true);
    else setIsDisabled(false);
}, [currentPassword, newPassword, newPasswordConfirm]);

return(
    //  ํ˜„์žฌ ๋น„๋ฐ€๋ฒˆํ˜ธ
    <TextField
      type="password"
      id={CURRENT_PASSWORD}
      placeholder="ํ˜„์žฌ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”."
      variant="outlined"
      value={currentPassword}
      onChange={handlePasswordInput}
    />

    // ์ƒˆ ๋น„๋ฐ€๋ฒˆํ˜ธ
    <TextField
      type="password"
      id={NEW_PASSWORD}
      placeholder="์ƒˆ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”."
      variant="outlined"
      value={newPassword}
      onChange={handlePasswordInput}
    />

    // ์ƒˆ ๋น„๋ฐ€๋ฒˆํ˜ธ ํ™•์ธ
    <TextField
      type="password"
      id={NEW_PASSWORD_CONFIRM}
      placeholder="์ƒˆ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ๋‹ค์‹œ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”."
      variant="outlined"
      value={newPasswordConfirm}
      onChange={handlePasswordInput}
    />

    <Button
        onClick={handleSubmit}
        disabled={isDisabled}
    >
     ๋ณ€๊ฒฝํ•˜๊ธฐ
    </Button>
)

๐Ÿ“Œ ์ฐธ๊ณ ๋กœ input ๋ถ€๋ถ„์ด ์ค‘๋ณต๋˜๋‹ˆ ์ปดํฌ๋„ŒํŠธํ™” ํ•ด์„œ ํ˜ธ์ถœํ•˜๋ฉด ๋˜๋Š” ๊ฑฐ ์•„๋‹Œ์ง€.. ์˜๋ฌธ์„ ๊ฐ€์ง€์…จ๋‹ค๋ฉด ์•„๋ž˜ ๊ธ€์„ ์ฐธ๊ณ ํ•ด์ฃผ์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค.๐Ÿ˜‚

 

[React/JS] input์—์„œ ํ•œ ๊ธ€์ž ์ž…๋ ฅ ํ›„ focus๋ฅผ ์žƒ๋Š” ํ˜„์ƒ

00. input์—์„œ ํ•œ ๊ธ€์ž ์ž…๋ ฅ ํ›„ focus๋ฅผ ์žƒ๋Š” ํ˜„์ƒ input ํƒœ๊ทธ์—์„œ ํ•œ ๊ธ€์ž๋ฅผ ์ž…๋ ฅํ•˜์ž๋งˆ์ž input์˜ focus๊ฐ€ ์‚ฌ๋ผ์ง€๋Š” ํ˜„์ƒ์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค... ๊ทธ๋Ÿฌ๋ฉด, ํ•œ ๊ธ€์ž ์น˜๊ณ  ๋‹ค์‹œ ์ž…๋ ฅ์ฐฝ ํด๋ฆญํ•˜๊ณ ,, ์น˜๊ณ  ํด๋ฆญํ•˜๊ณ ,,

avoc-o-d.tistory.com

 

 

02. ํ˜„์žฌ ๋น„๋ฐ€๋ฒˆํ˜ธ ์ž…๋ ฅ ์ œ์–ด (์žฌ๋กœ๊ทธ์ธ)

๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณ€๊ฒฝ์€ ๋ณด์•ˆ์— ๋งค์šฐ ๋ฏผ๊ฐํ•œ ๋ถ€๋ถ„์ด์ฃ .

๋”ฐ๋ผ์„œ, ๊ฐ€์žฅ ์ตœ๊ทผ์— ๋กœ๊ทธ์ธ์ด ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰, ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ ํ˜„์žฌ ๋น„๋ฐ€๋ฒˆํ˜ธ๋กœ ์žฌ๋กœ๊ทธ์ธ์„ ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

import {
  auth,
  EmailAuthProvider,
  reauthenticateWithCredential,
} from "../../service/firebase";

// ๋น„๋ฐ€๋ฒˆํ˜ธ ํผ ์ œ์ถœ ํ•จ์ˆ˜
async function handleSubmit(event) {

    const user = auth.currentUser; // ํ˜„์žฌ ์‚ฌ์šฉ์ž์˜ ์ •๋ณด์— ์ ‘๊ทผ

    // 01. ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ ํ˜„์žฌ ๋น„๋ฐ€๋ฒˆํ˜ธ๋กœ credential ๋ฐœ๊ธ‰
    const credential = EmailAuthProvider.credential(
      user.email,
      currentPassword
    );

    // 02. ๋ฐœ๊ธ‰๋ฐ›์€ credential๋กœ ์žฌ๋กœ๊ทธ์ธ
    // => ์˜ˆ์™ธ์ฒ˜๋ฆฌ ) ๋งŒ์•ฝ ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ ํ˜„์žฌ ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ํ‹€๋ ธ๋‹ค๋ฉด? ์—๋Ÿฌ ๋ฉ”์„ธ์ง€
    await reauthenticateWithCredential(user, credential)
      .then(() => {
      // ๋กœ๊ทธ์ธ ์„ฑ๊ณต
      })
      .catch((error) => {
      // ๋กœ๊ทธ์ธ ์‹คํŒจ
      });
}

 

ํ˜„์žฌ ๋น„๋ฐ€๋ฒˆํ˜ธ ์ž…๋ ฅ ์˜ค๋ฅ˜

์œ„์ฒ˜๋Ÿผ ํ˜„์žฌ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ž˜๋ชป ์ž…๋ ฅํ–ˆ์„ ๊ฒฝ์šฐ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๋ฅผ ๊ตฌํ˜„ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค!

 

๐Ÿ“Œ ์ฐธ๊ณ  : error๋ฅผ ์ฝ˜์†”๋กœ ์ฐ์œผ๋ฉด, auth/wrong-password ์ฒ˜๋Ÿผ ์—๋Ÿฌ์ฝ”๋“œ๊ฐ€ ๋‚ ๋ผ์˜ต๋‹ˆ๋‹ค.

์ด๋ฅผ ์ด์šฉํ•˜์—ฌ "auth/wrong-password" ๋ฅผ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฐ›์„ ์‹œ, "๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ์ž˜๋ชป๋˜์—ˆ์Šต๋‹ˆ๋‹ค." ๋กœ error ๋ฉ”์„ธ์ง€๋ฅผ ๋ณ€๊ฒฝํ•ด์ฃผ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ํ˜„์žฌ ๋น„๋ฐ€๋ฒˆํ˜ธ input ์ปดํฌ๋„ŒํŠธ๋ฅผ error ์ฒ˜๋ฆฌํ•ด์ค๋‹ˆ๋‹ค.

ํ˜„์žฌ ๋น„๋ฐ€๋ฒˆํ˜ธ ํ‹€๋ ธ์„ ๊ฒฝ์šฐ firebase error ๋ฉ”์„ธ์ง€

 

// ํ˜„์žฌ ๋น„๋ฐ€๋ฒˆํ˜ธ error log
const [currentPasswordLog, setCurrentPasswordLog] = React.useState(false);
  
// ๋น„๋ฐ€๋ฒˆํ˜ธ ํผ ์ œ์ถœ ํ•จ์ˆ˜
async function handleSubmit(event) {

...

    // 02. ๋ฐœ๊ธ‰๋ฐ›์€ credential๋กœ ์žฌ๋กœ๊ทธ์ธ
    // => ์˜ˆ์™ธ์ฒ˜๋ฆฌ ) ๋งŒ์•ฝ ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ ํ˜„์žฌ ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ํ‹€๋ ธ๋‹ค๋ฉด? ์—๋Ÿฌ ๋ฉ”์„ธ์ง€
    await reauthenticateWithCredential(user, credential)
      .then(() => {
      // ๋กœ๊ทธ์ธ ์„ฑ๊ณต
      })
      .catch((error) => {
            handleAuthError(error.code); // auth/wrong-password => "๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ์ž˜๋ชป๋˜์—ˆ์Šต๋‹ˆ๋‹ค."
            switch (error.code) {
              case "auth/wrong-password": { // auth/wrong-password => ํ˜„์žฌ ๋น„๋ฐ€๋ฒˆํ˜ธ input error
                return setCurrentPasswordLog(true);
              }
            }
      });
}

 

 

03. ์ƒˆ ๋น„๋ฐ€๋ฒˆํ˜ธ, ์ƒˆ ๋น„๋ฐ€๋ฒˆํ˜ธ ํ™•์ธ ์ž…๋ ฅ ์ œ์–ด (์ž…๋ ฅ๊ฐ’ ์ผ์น˜ ์—ฌ๋ถ€)

์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ ์ƒˆ ๋น„๋ฐ€๋ฒˆํ˜ธ์™€ ์ƒˆ ๋น„๋ฐ€๋ฒˆํ˜ธ ํ™•์ธ์ด ์ผ์น˜ํ•œ์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

์ƒˆ ๋น„๋ฐ€๋ฒˆํ˜ธ, ์ƒˆ ๋น„๋ฐ€๋ฒˆํ˜ธ ํ™•์ธ ์ž…๋ ฅ ์˜ค๋ฅ˜

// ์ƒˆ ๋น„๋ฐ€๋ฒˆํ˜ธ ํ™•์ธ error log
const [newPasswordConfirmLog, setNewPasswordConfirmLog] = React.useState(false);


// 03. ์ƒˆ ๋น„๋ฐ€๋ฒˆํ˜ธ, ์ƒˆ ๋น„๋ฐ€๋ฒˆํ˜ธ ํ™•์ธ ์ผ์น˜ํ•˜๋Š”์ง€ ๊ฒ€์‚ฌ
function validatePassword() {
    let isValid = true;
    if (
      newPassword !== "" &&
      newPasswordConfirm !== "" &&
      newPassword !== newPasswordConfirm
    ) {
      isValid = false;
      handleAuthError("invalid-password"); // invalid-password => "๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ์ผ์น˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."
    }

    // ์ผ์น˜ํ•˜์ง€ ์•Š์„ ๊ฒฝ์šฐ => ์ƒˆ ๋น„๋ฐ€๋ฒˆํ˜ธ ํ™•์ธ input error
    setNewPasswordConfirmLog(!isValid);

    return isValid;
}
  
  
  
// ๋น„๋ฐ€๋ฒˆํ˜ธ ํผ ์ œ์ถœ ํ•จ์ˆ˜
async function handleSubmit(event) {

...

    // 03. ์ƒˆ ๋น„๋ฐ€๋ฒˆํ˜ธ, ํ™•์ธ ๊ฒ€์‚ฌ
    if (!validatePassword()) return;

}

 

 

04. ์ƒˆ ๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณด์•ˆ ์ œ์–ด (๋ณด์•ˆ ์ •๋„ ๊ด€๋ฆฌ)

์ƒˆ ๋น„๋ฐ€๋ฒˆํ˜ธ ์—ญ์‹œ ๋ณด์•ˆ์„ ์œ„ํ•ด ์•ˆ์ „ํ•œ ๋น„๋ฐ€๋ฒˆํ˜ธ์—ฌ์•ผ๊ฒ ์ฃ ? ๐Ÿ˜

์ƒˆ ๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณด์•ˆ ์˜ค๋ฅ˜

import {
	...
  updatePassword
} from "../../service/firebase";

// ์ƒˆ ๋น„๋ฐ€๋ฒˆํ˜ธ error log
const [newPasswordLog, setNewPasswordLog] = React.useState(false);


// ๋น„๋ฐ€๋ฒˆํ˜ธ ํผ ์ œ์ถœ ํ•จ์ˆ˜
async function handleSubmit(event) {

...

    // 04. ๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณ€๊ฒฝ
    await updatePassword(user, newPassword)
      .then(() => {
      // ๋ณ€๊ฒฝ ์„ฑ๊ณต
      })
      .catch((error) => {
      // ๋ณ€๊ฒฝ ์‹คํŒจ
        handleAuthError(error.code);  // auth/weak-password => "์•ˆ์ „ํ•˜์ง€ ์•Š์€ ๋น„๋ฐ€๋ฒˆํ˜ธ์ž…๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์‚ฌ์šฉํ•ด ์ฃผ์„ธ์š”."
        switch (error.code) {
          case "auth/weak-password": { // auth/weak-password => ์ƒˆ ๋น„๋ฐ€๋ฒˆํ˜ธ input error
            return setNewPasswordLog(true);
          }
        }
      });
}

 

 

05. ๋ณ€๊ฒฝ ์™„๋ฃŒ

์„ฑ๊ณต์ ์œผ๋กœ ๋ณ€๊ฒฝ์ด ์™„๋ฃŒ๋˜์—ˆ๋‹ค๋ฉด, ์Šค๋‚ต๋ฐ”๊ฐ™์€ ์ปดํฌ๋„ŒํŠธ๋กœ ์ฒ˜๋ฆฌํ•ด์ฃผ๋ฉด ๊ตฟ~!

 

React Snackbar component - Material UI

Snackbars provide brief notifications. The component is also known as a toast.

mui.com

 

 

์•„ํ•˜ํ•ซ ๐Ÿ˜†๐Ÿ˜†