23.08.19

useEffect를 사용하는 이유

useEffect를 사용하는 이유는 데이터를 가져오기 위해서가 아니라 리액트는 프라미스와 에러에 대응할 수 없기 때문이다.


useEffect 안에 직접 async 함수를 사용하는 것은 권장되지 않는 이유

비동기 함수와의 일관성: useEffect 는 일반적으로 부수 효과를 처리하기 위해 사용됩니다. 하지만 useEffect가 반환하는 값은 주로 정리(clean-up) 작업을 위한 함수이어야 합니다. async 함수는 항상 Promise 를 반환하기 때문에, 반환 값이 기대하는 일반적인 정리 함수 형태와는 다릅니다.

오류 처리의 어려움: useEffect 안에서 직접 async 함수를 사용하면 내부에서 발생한 오류를 캐치하거나 처리하기가 어려울 수 있습니다. try-catch 블록 안에서 await를 사용하여 오류를 처리할 수 없습니다. 이로 인해 예기치 않은 동작이 발생할 수 있습니다.

올바른 패턴은 useEffect 안에서 비동기 코드를 호출하는데 사용되는 별도의 함수를 선언하고, 그 함수 내에서 async/await 패턴을 사용하는 것입니다. 예를 들면 다음과 같습니다

useEffect(() => {
  const fetchData = async () => {
    try {
      // 비동기 작업 수행
    } catch (error) {
      // 오류 처리
    }
  };

  fetchData();
}, []);
import { useEffect, useState } from "react";
// 리액트는 자식 컴포넌트가 프로미스를 반환하거나
// 에러를 던질 때는 전혀 대응하지 못한다.
function App() {
  const [, set] = useState(0);
  const 비동기데이터가져오기 = async () => {
    const res = await fetch(
      "https://pokeapi.co/api/v2/pokemon?limit=5&offset=0"
    );
    const data = await res.json();
    set(data.results.length);
  };

  // fetch를 react 컴포넌트와 격리하기 위해
  // useEffect의 부수효과를 이용한다.
  useEffect(() => {
    // useEffect 안에서 async 함수를 선언하면
    // 프로미스를 반환하므로 에러가 발생한다
    비동기데이터가져오기();
  }, []);

  return <>{}</>;
}

export default App;

 function 메모이즈(함수) {
        // 0. 캐시라는 변수는 클로저가 된다
        const 캐시 = {};

        return function () {
          console.log("캐시 내부", 캐시);
          // 1.캐시 안에서 이전에 계산한 값을 꺼내 온다
          const= 캐시[];

          // 2. 이전에 계산한 값이 있으면 그 값을 반환한다
          if () {
            console.log("히트다 히트!");
            return;
          }

          // 3. 이전에 계산한 값이 없으면 새로 계산해서 캐시에 넣자
          캐시[] = 함수();

          // 4. 그리고 계산한 값을 반환!
          return 캐시[];
        };
      }

23.08.22

환경 변수 설정 & 동적 라우팅

.env.local

VITE_PB_URL = http://127.0.0.1:8090 # 환경변수 설정
VITE_PB_API = $VITE_PB_URL/api #API 엔드포인트를 저장
DB_PASSWORD = qweiuickx2@zkjw # 비트와의 약속 : 변수명에 'VITE'를 명시하지 않으면 값을 불러 올 수 없음!

.env.local에 있는 변수 불러오는 방법

src/routes

<Route path="product/edit/:productId" element={<ProductEdit />}/>
{/* :productId - url 파라미터에 따라 동적으로 라우팅 해주겠다는 뜻  */}
// productId는 동적 경로 매개변수                                 
// ProductEdit 컴포넌트에서 이 매개변수를 추출하려면 useParams 훅을 사용 
${import.meta.env.VITE_PB_API}/collections/products/records/${productId}
// http://127.0.0.1:8090/api/collections/products/records/상품ID

value vs defaultValue

defaultvalue - 폼 요소의 초기값을 설정하는 데 사용 / 리액트가 관리하지 않고 사용자에 의해서 값을 바꾸고 싶을 때 사용

 <div className="flex gap-3">
      <label htmlFor={titleId}>타이틀</label>
      <input
        type="text"
        name="title"
        id={titleId}
        // 리액트가 제공하지 않는 함수를 사용할 때는  defaultValue 사용해야 한다.
        defaultValue={formState.title} 
        onChange={handleDebounceChangeInput} // debounce 함수
      />
</div>

value - 폼요소의 현재 값을 나타냄 / 리액트가 관리할 때 사용


pocketbase SDK

PocketBase SDK
NPM을 사용해 PocketBase SDK 패키지를 설치합니다.

npm i pocketbase

src/api/pocketbase.js

import PocketBase from 'pocketbase';

const pb = new PocketBase(import.meta.env.VITE_PB_URL);

// PocketBase SDK {}
export default pb;

api 문서

useParams


<Route> 설정:
이 부분은 처음에 설정되며, 브라우저의 주소창에 특정 URL 경로가 입력되었을 때 
일치하는 라우트가 있으면 해당 라우트의 컴포넌트를 렌더링합니다. 
path 속성에 있는 경로 패턴을 가지고 매칭 여부를 결정합니다.

컴포넌트 내에서 const { productId } = useParams(); 실행:
이 부분은 ProductEdit 컴포넌트 내부에서 실행됩니다. 
해당 컴포넌트가 라우트에 의해 렌더링될 때, 컴포넌트 내부의 코드가 실행됩니다. 
따라서 useParams()를 호출하여 동적 매개변수 값을 추출하는 것은 ProductEdit 컴포넌트가 렌더링될 때 일어납니다.

따라서 순서는 <Route> 설정이 먼저 이루어진 다음, ProductEdit 컴포넌트가 렌더링되면서 내부에서 useParams()를 호출하여 동적 매개변수 값을 가져오게 됩니다.
  1. 사용자가 링크를 클릭하여 /product/edit/123과 같은 URL로 이동합니다.
  2. Route 컴포넌트가 /product/edit/:productId 경로와 일치하는지 확인합니다.
  3. 경로와 일치하므로 ProductEdit 컴포넌트가 렌더링됩니다.
  4. ProductEdit 컴포넌트 내에서 const { productId } = useParams(); 코드가 실행됩니다. 이때 productId는 123과 같은 값이 됩니다.
  5. 만약 item.id가 456인 링크를 클릭한 경우, to 속성이 /product/edit/456가 되며, ProductEdit 컴포넌트에서 productId는 456과 같은 값이 됩니다.

이렇게 함으로써 동적으로 변화하는 경로와 해당 경로의 매개변수 값을 활용하여 원하는 정보를 렌더링하거나 네비게이션을 처리할 수 있습니다.

23.08.23



lifting


상태와 달리, 참조 객체의 현재 값은 변경되어도 리액트가 다시 렌더링을 하지 않는다.
상태는 시간의 흐름에 따라 변하고, 상태가 변경되면 리액트는 필연적으로 반응(리액션: 렌더링)한다.
함수 내부의 변수나 포함된 함수는 다음 번 실행(리-렌더링) 시, 초기화된다. (가비지 컬렉터에 의해서)


컨텍ㄷ스트 == 영역

useContext





useReducer

23.08.24

23.08.24

Serialize(직렬화): 객체를 데이터스트림(연속적인 바이너리 형태나 텍스트 형태(예: JSON) )으로 만드는 것
즉, 객체에 저장된 데이터를 스트림에 쓰기위해 연속적인 데이터를 변환하는것. (JSON.stringify())
Deserialization(역직렬화): 반대로 스트림으로부터 데이터를 읽어 객체를 만드는 것 (JSON.parse())

useMemo / useCallback

useCallback 훅은 리액트 컴포넌트 내에서 함수를 최적화하여 생성하거나 업데이트할 때 사용됩니다. 함수 컴포넌트가 렌더링될 때마다 새로운 함수가 생성되는 경우, 불필요한 리렌더링이 발생할 수 있고, 성능 저하의 원인이 될 수 있습니다. 이러한 문제를 해결하고자 useCallback 훅을 사용하여 함수를 메모이제이션하고 최적화할 수 있습니다.

  // useCallback : 함수 값만 기억 vs. useMemo : JS 모든 값(함수 포함)을 기억
  // useMemo 훅: 모든 JS 값 유형 기억
  // const cachedUpdate = useMemo(() => 함수 값, [])

  // useCallback 훅: JS 함수 값만 기억

  const update = useCallback(
    (nextData) => {
      setData(key, nextData);
      setStorageData(nextData);
    },
    [key]
  );

  // const updateMemo = useMemo(
  //   () => (nextData) => {
  //     setData(key, nextData);
  //     setStorageData(nextData);
  //   },
  //   [key]
  // );

  const remove = useCallback(() => {
    deleteData(key);
    setStorageData();
  }, [key]);

  // const removeMemo = useMemo(
  //   () => () => { deleteData(key); },
  //   [key]
  // );

Route가 보호되는 상항에서 발생되는 에러 처리

토스트에서 문제 상황 발생
순수한 영역에서 상태를 바꾸려고 시도했기 때문에 에러가 발생한다
useEffect를 사용

const { isAuth } = useAuth();

  useEffect(() => {
    // if (!isAuth) {
      toast("로그인 된 사용자만 이용 가능한 페이지입니다.", {
        icon: "⚠️",
        ariaProps: {
          role: "alert",
          "aria-live": "polite",
        },
      });
    // }

    return () => {};
  }, [isAuth]);

  if (!isAuth) {
    return <Navigate to="/signin" />;
  }

  return children;
}

spa에서 검색 엔진 최적화를 도와주는 react-helmet-async

https://www.npmjs.com/package/react-helmet-async

profile
진주링딩동🎵

0개의 댓글