[프론트엔드 스쿨 6기] 🗓️ 8월24일

유동균·2023년 8월 24일
1

프론트엔드 스쿨 6기

목록 보기
43/44
post-thumbnail
post-custom-banner

useRef

class를 사용할 때는 React.createRef!!! 함수형에서는 React.useRef

React 컴포넌트 렌더링 프로세스에 영항을 주지 않으면서 다음 렌더링에도 값을 기억하기 위한 수단

animate()

웹 표준 animation

useLayoutEffect

useEffect 콜백보다 먼저 실행된다.

  • 리액트 렌더링 프로세스
    1. 렌더 트리거
    2. 컴포넌트 렌더링
    3. DOM 커밋
      -> useLayoutEffect() 콜백
  • 브라우저 렌더링 프로세스
    1. 브라우저 페인팅
      -> useEffect() 콜백

gsap

> pnpm add gsap


gsap X useRef



id가 중첩되는 컴포넌트를 생성하면 이벤트 발생시 동작하지 않는 에러가 발생한다. 즉, class, id, 요소를 하나만 선택하는 보장을 할 수 없다.

id, class 대신 useRef를 사용하자.
1. Refs 생성
2. JSX 요소 ref 속성(prop)에 Refs 연결
3. useLayoutEffect 훅 안에서 Refs 현재(current) 값으로 명령형 프로그래밍

React 컴포넌트는 순수해야한다. (렌더링 프로세스 순수해야 하기 때문)
Web Animation, GSAP, jQuery와 같은 API는 명령형 프로그래밍이다.
그러므로 컴포넌트 내부에 직접 사용할 수 없다.
명령형 프로그래밍을 작성힐 수 있는 구간은 두군데 이다.
1. Effect Hook (useLayoutEffect Hook 브라우저 페인팅 이전, 성능 이슈가 발생할 수 있기 때문에 이벤트 핸들링 할 때만 사용하자)
2. Event Handler(Listener)
React 요소(가상)가 실제 DOM에 렌덜이 된 후 요소를 참조하려면 ?
기존의 document.getElementById, document,querySelector 사용하는 것이 권장되지 않는다.
따라서 useRef Hook을 사용해 Refs 객체를 생성하여 활용
const anyRef = useRef();

과거 코드

gsap context()

gsap.context()는 React 개발자에게 범위 내에서 CSS 선택자를 사용하는 옵션과 애니메이션 정리(cleanup) 기능을 제공

사용하는 이유?

Framer Motion

React 전용! 선언형!

> pnpm add framer-motion

  • 3가지 상태
    초기 상태(initial)
    애니메이션 상태(animation)
    트랜지션 상태(transition)
import { motion } from 'framer-motion';
import { useState } from 'react';

function FramerMotion_Animation() {
  const [count, setCount] = useState(0);

  const handleCountUp = () => {
    setCount((c) => c + 10);
  };

  const [key1, setKey1] = useState(Math.random());
  const [key2, setKey2] = useState(Math.random());
  const [key3, setKey3] = useState(Math.random());

  const [keys, setKeys] = useState(
    Array(3)
      .fill(null)
      .map(() => Math.random())
  );

  const handleResetAnimation = () => {
    setKey1(Math.random());
    setKey2(Math.random());
    setKey3(Math.random());
    setKeys(keys.map(() => Math.random()));
  };

  return (
    <>
      <h2>컴포넌트 내부의 DOM 요소를 직접 참조하는 Refs</h2>
      <div className="flex gap-2">
        <button
          type="button"
          className="my-6 py-1.5 px-2.5 border border-slate-200 rounded-md shadow-lg"
          onClick={handleCountUp}
        >
          {count}
        </button>
        <button
          type="button"
          className="my-6 py-1.5 px-2.5 border border-slate-200 rounded-md shadow-lg"
          onClick={handleResetAnimation}
        >
          <svg
            className="w-4 h-4 text-gray-800 dark:text-white"
            aria-hidden="true"
            fill="none"
            viewBox="0 0 18 20"
          >
            <path
              stroke="currentColor"
              strokeLinecap="round"
              strokeLinejoin="round"
              strokeWidth={1}
              d="M16 1v5h-5M2 19v-5h5m10-4a8 8 0 0 1-14.947 3.97M1 10a8 8 0 0 1 14.947-3.97"
            />
          </svg>
        </button>
      </div>
      <div className="flex flex-col gap-[700px]">
        <Circle key={key1} />
        <Circle key={key2} />
        <Circle key={key3} />
        {keys.map((key) => (
          <Circle key={key} />
        ))}
      </div>
    </>
  );
}

function Circle() {
  return (
    <motion.figure
      role="none"
      className="grid place-content-center w-16 h-16 rounded-full bg-yellow-300"
      initial={{ y: -150, opacity: 0 }}
      whileInView={{
        y: 0,
        opacity: 1,
        scale: 6,
      }}
      viewport={{
        once: true,
      }}
      transition={{
        duration: 4,
        type: 'spring',
        stiffness: 400,
        damping: 5,
      }}
    >
      <motion.img
        // 초기 상태(initial)
        initial={{ scale: 0 }}
        // 애니메이션 상태(animate)
        animate={{ rotate: 180, scale: 1 }}
        // 트랜지션 상태(transition)
        transition={{
          type: 'spring',
          stiffness: 260, // 뻣뻣함 (팽팽함)
          damping: 20, // 마찰(제동)
        }}
        src="/react.png"
        alt="React"
        className="w-10 h-10"
      />
    </motion.figure>
  );
}

export default FramerMotion_Animation;

auth

로그인

PB는 사용자 브라우저 로컬 스토리지에 저장한다.

로그아웃

clear메서드를 사용해 데이터를 삭제한다.

탈퇴

context

인증 컨텍스트 생성


src/context/Auth.jsx


// 컨텍스트
// 1. Create Context (React.creactContext)
// 3. 컨텍스트 프로바이더를 앱을 감쌈
// 2. Context Provider를 사용해 값value을 공급provide

// 컴포넌트
// 1. useContext Hook을 사용해서 공급된 context value를 주입(injection)
// 2. JSX 또는 이벤트 핸들러 내부에서 값을 사용

/* ----------------------------------------------------------------------- */
import pb from '@/api/pocketbase';
import { createContext, useState, useEffect } from 'react';

// Context 생성
const Authcontext = createContext();

// 초기 인증 상태
const initialAuthState = {
  isSignin: false,
  user: null,
  token: '',
};

// Context.Provider 래퍼 컴포넌트 작성
function AuthProvider({ displayName = 'AuthProvider', children }) {
  // 인증상태 pb.authStore = { isValid, model, token } 객체로 묶어서 관리
  const [authState, setAuthState] = useState(initialAuthState);

  useEffect(() => {
    const unsub = pb.authStore.onChange((token, model) => {
      console.log(token);
      console.log(model);
      setAuthState((state) => ({
        ...state,
        isAuth: !!model,
        user: model,
        token,
      }));
    });

    return () => {
      unsub?.();
    };
  }, []);

  // 메서드: 할 수 있는 기능
  // 회원가입, 로그인, 로그아웃, 탈퇴
  // 서버는 대기 시간(비동기/ 요청/응답)
  const signUp = async (registerUser) => {
    return await pb.collection('users').create(registerUser);
  };
  const signIn = async (usernameOrEmail, password) => {
    return await pb
      .collection('users')
      .authWithPassword(usernameOrEmail, password);
  };
  const signOut = async () => {
    return await pb.collection('users').collectionIdOrName();
  };
  const secession = async (recordId) => {
    // localstorage에서 데이터를 지우기 때문에 asyc/await가 필요 없긴하다.
    return await pb.collection('users').delete(recordId);
  };

  const authValue = {
    ...authState,
    signUp,
    signIn,
    signOut,
    secession,
  };

  return (
    <Authcontext.Provider value={authValue} displayName={displayName}>
      {children}
    </Authcontext.Provider>
  );
}

export default AuthProvider;


하위 컴포넌트로 Auth 정보를 공급할 수 있다.


prop 검증

검증되지 않은 prop을 검사해보자

사용자 정의 prop-types

prop-types 라이브러리

> pnpm add prop-types

인증(Auth) 라우팅

인증(authentication)된 사용자만 이용 가능한 페이지

prop type검증

  • typescript

propTypes

toaster

pnpm add react-hot-toast


접근 막기

post-custom-banner

0개의 댓글