리액트 이모저모

김현준·2024년 3월 5일
0

리액트 이모저모

목록 보기
2/27

리액트 상태관리 가이드

  • 서버 캐싱을 전역 상태 라이브러리로 하면 안되는 이유
    전역 상태에서 서버 상태를 캐싱을 하게되면 서버 상태가 특정 시점에 캡쳐 되버린다. 서버 데이터를 캐싱한 클라이언트의 상태를 인터렉션에 따라 update해서 서버 데이터와 동기화 한다고 하여도 시간이 지남에 따라서 본질적으로는 다른 데이터가 되고 관리도 어렵다.

리액트 상태관리 종류 4가지와 useQuery

useQuery vs useSWR

  1. useQuery:
  • 주로 GraphQL을 사용하는 경우 Apollo Client와 함께 사용
  • GraphQL 쿼리를 실행하고 데이터를 가져오는 데 사용
  • Apollo Client는 캐시와 함께 통합되어 있어 쿼리 결과를 캐시하고 관리하는 것이 가능
  • 서버와의 상호 작용이 필요한 경우에 주로 사용
  1. useSWR:
  • 주로 RESTful API와 함께 사용
  • SWR은 "Stale-While-Revalidate"의 약자로, 데이터를 가져와서 캐시하고 동시에 데이터를 다시 가져오는 방식을 지원
  • RESTful 엔드포인트와 함께 간단하게 데이터를 가져오고 업데이트하는 데 사용
  • 간단한 상태 관리 및 데이터 가져오기에 유용

요약하면, useQuery는 GraphQL 및 Apollo Client와 함께 사용하여 복잡한 데이터 가져오기 및 관리에 사용되며, useSWR은 RESTful API와 간단한 데이터 가져오기 및 캐시 관리에 사용된다. 선택은 프로젝트의 요구 사항과 데이터 소스에 따라 달라진다.

정리된 자료
두 라이브러리 모두 장단점이 있다.
SWR은 React 요청 처리의 캐싱 문제를 해결하기 위한 최소한의 API를 제공하는 것이고 React Query는 동일한 문제에 대해 완전한 기능을 갖춘 솔루션을 제공한다. React는 클래스 기반 구성 요소의 복잡성을 줄이기 위해 기능적 구성 요소를 도입했기 때문에 이러한 단순성을 좋아하는 개발자는 SWR, 상세하고 강력한 API로 작업하고 데이터 캐싱을 위한 프레임워크와 같은 올인원 솔루션을 찾는 개발자는 React Query를 선택하면 된다. 둘 사이에 확실한 승자는 없다.

useSWR이 리덕스를 대체한다?
API를 호출할 때 useState 대신 useSWR을 사용해야 하는 이유

input 안에 value 써야하는 이유 + value 사용시 입력안되는 문제

왜 input에 value 값을 써줘야 할까?
input에 입력된 값을 쉽게 가져오려고 써준거다. 받아들이기!!!

왜 input 에 value 값을 쓰면 입력이 안되나?
해결방법 : onChange 이벤트를 써서 input 을 수정할 수 있는 상태로 만들어줘야한다.

콘솔로그 테스트 주의사항

  const handleCoin = (event) => {
    setOrgValue(event.target.value)
    console.log(orgValue); //orgValue를 알고 싶지만 이전에 선택한 값이 출력된다.
  };

이유는 React의 상태 업데이트가 비동기적으로 처리되기 때문.
setOrgValue 함수가 호출되면 상태가 업데이트되지만 이 업데이트는 즉시 반영되지 않는다.
따라서 console.log(orgValue);가 실행될 때 orgValue는 아직 업데이트되기 전의 이전 값을 가지고 있다.

React 상태 업데이트는 비동기적으로 처리되며, setState 함수는 업데이트가 완료된 후에 컴포넌트를 리렌더링 한다.
따라서 useEffect 내부에서 console.log(orgValue);를 호출하면 이전 값이 출력된다.

결론

  const handleCoin = (event) => {
    setOrgValue(event.target.value)
  };
console.log(orgValue); //이렇게 바깥으로 빼서 테스트해야 한다.

select태그의 option값 받아오기

선요약:
<option>의 value 값이 <select>의 value 값에 저장되는 것이 아니라, 선택된 옵션의 value 값이 <select>의 value 값으로 설정되는 것

     <select onChange={handleCoin} value={orgValue}>
        {
          coins.map((coin) => (
            <option key={coin.id} value={coin.quotes.USD.price}>
              {coin.name} ({coin.symbol}): ${coin.quotes.USD.price.toFixed(2)}
            </option>
          ))}
      </select>

위 코드에서 option의 value값고 select의 value값의 관계

  1. <select> 요소의 value 속성은 현재 선택된 옵션의 값을 나타낸다.
    이 값은 <option> 요소 중 하나의 value 속성 값과 일치해야 한다.
    사용자가 드롭다운 목록에서 새로운 옵션을 선택하면 이 value 값이 변경된다.

  2. <option> 요소의 value 속성은 해당 옵션의 값을 정의한다.
    사용자가 이 옵션을 선택할 때 선택된 값이 <select> 요소의 value로 설정된다.
    <option>의 value 속성 값과 <select>의 value 값이 일치하는 경우 해당 옵션이 선택된다.

list와 key

리액트에서 배열을 렌더링할 때 map 메서드를 사용하면 배열의 각 항목을 화면에 표시할 수 있다. 그러나 리액트는 각 항목이 유일하다는 것을 알기 위해 각 항목에 고유한 식별자가 필요하다. 이것이 바로 key prop가 필요한 이유다.

key prop는 리액트에게 각각의 배열 항목을 식별할 수 있는 고유한 식별자를 제공하는 역할을 한다. 이 식별자를 제공하지 않으면 리액트는 배열의 각 항목을 추적하지 못하고 변경 사항을 효율적으로 감지할 수 없다. 따라서 각 항목에 key를 지정하여 리액트에게 배열의 항목을 구분하도록 도와야 한다.

<ul>
{toDos.map((item) => (
  <li key={item.id}>{item.text}</li>
))}
</ul>

map은 key값이 필수라는 걸 꼭 기억하고 key 값은 고유한 것이면 무엇이든 된다!

선언적 라우팅 쓰는 이유

  • 중첩/동적라우팅 으로 똑똑하게 라우팅관리하기
  • 쿼리 스트링과 패스 매개변수 차이
    똑같은 데이터를 보낸다고 했을때
    name = 공수정
    age = 25
    //Query String
    user?name=공수정&age=25   // user중에 이름이 공수정이고, 나이가 25살으로 필터링된 결과 조회
    //Path Variable
    user/name/25			// 이름이 공수정이고, 나이가 25살인 user.
    없는 데이터에 대해
    만약 이름이 공수정이고, 나이가 25살인 유저가 없는 경우라면,
    Query String은 빈 결과값을 결과로 보내고, path Variable는 없는 페이지가 되니까 404 error를 발생시킬 것
    이상적인 사용
    Query String:
    검색 결과가 없으면 없다고 리턴하는 Query String은 해당 데이터를 통해 필터링을 할 때
    path Variable:
    검색 결과가 없으면 404 error 발생을 하는 path Variable는 해당 내용의 식별을 할 때

{...a}



두 개 모두

같은 porps(여기선 interface IToDo)를 바라보기에 {...ToDo} 가능

AND OR 연산자로 코드 짧게 쓰기


OR연산자는 첫 번째 값이 존재하면 좌측을 리턴하고, 아니면 우측을 리턴

AND연산자는 두 가지의 값이 모두 참이면 마지막 값을 리턴함
둘 중에 하나라도 false면 false를 리턴

OR은 기본값을 지정할 때 많이 쓰고, AND는 특수한 상황에서 조건문을 사용할 때 많이 씀
https://www.youtube.com/shorts/4X7WqELD-Ls

리액트 ts 팁


위의 카테고리 항목만 필요하면

이렇게 가져올 수 있다.

mutation이란

const name = 'jun'

name.toUpperCase()
'JUN'

name
jun

//보다시피 name자체는 변하지 않았다. 이것을 non-mutation이라 한다.

const x = [1, 2, 3]

x.splice(0, 1)
[1]

x
[2, 3]

//위처럼 x가 영원히 바뀐 것을 mutation

오브젝트 안의 배열 내용 불러오기

cosnt obj = {
  x: [1, 2, 3],
  z: [4, 5, 6]
}

obj[x]
-> [1, 2, 3]
//이런 식으로 불러온다,

Object.keys(obj).map((item) => obj[item])
//위처럼 Object.keys로 키값만 불러올 수 있다.

불변성유지를 위해 props 전달 주의점

<DragabbleCard
 //불변성 유지를 위해 통째로 말고 아래처럼 따로따로 보냄
  //todo={todo} (X) todoId={todo.id} todoText={todo.text} (O)
	key={toDo.id}
	index={index}
	toDoId={toDo.id}
	toDoText={toDo.text}
/>

리액트에서 todo={todo}와 같이 객체를 통째로 전달하는 것은 불변성 유지에 좋지 않은 방법인 이유

1. 렌더링 성능:

  • 리액트는 컴포넌트가 업데이트되었는지 여부를 판단하기 위해 얕은 비교(Shallow Comparison)를 수행
  • 객체를 통째로 전달하면 해당 객체의 내용이 변경되지 않아도 렌더링이 발생할 수 있다. 이는 성능 저하를 초래할 수 있다.

2. 불변성 유지:

  • 리액트에서는 불변성을 유지하는 것이 중요하다. 즉, 상태(state)를 변경할 때 기존 객체를 직접 수정하지 않고 새로운 객체를 생성해야 한다.
  • 객체를 통째로 전달하면 해당 객체의 내용을 직접 수정할 수 있기 때문에 불변성이 깨질 수 있다.

3. 성능 최적화를 위한 최소한의 업데이트:

  • 객체를 통째로 전달하면 해당 객체의 모든 속성이 변경되었을 때 렌더링이 발생
  • 반면에 속성을 개별적으로 전달하면 변경된 속성만 업데이트되어 최소한의 렌더링만 발생

비동기처리 메모리 누수, 비동기함수엔 useEffect()

const [bannerCount, setBannerCount] = useState(0);
  const dataLengh = movies.length;
  setInterval(
    () => setBannerCount((prev) => (dataLengh === 20 ? 0 : prev + 1)),
    2000
  );

이 코드가 실행되지 않는 이유를 알아보자.

setInterval 함수를 사용하여 상태를 업데이트하는 경우, 해당 setInterval은 컴포넌트가 마운트될 때 딱 한 번만 호출되는 것이 아니라, 계속해서 실행된다. 그러나 이런 방식으로 사용할 경우 컴포넌트가 언마운트되기 전까지 계속해서 setInterval이 실행되므로 메모리 누수와 같은 문제가 발생할 수 있다.

일반적으로 이런 경우에는 useEffect 훅을 활용하여 컴포넌트의 라이프사이클에 맞춰 setInterval을 설정하는 것이 좋다. 아래는 수정된 코드다:

import {useState,useEffect }from 'react';
const YourComponent =({ movies })=>{
  const [bannerCount,setBannerCount]=useState(0);
  const dataLength =movies.length;
  useEffect(()=>{
    const intervalId =setInterval(()=>{
      setBannerCount((prev)=> (dataLength ===20 ?0 :prev +1));
    },2000);
    // 컴포넌트가 언마운트될 때 clearInterval을 호출하여 메모리 누수 방지
    return ()=>clearInterval(intervalId);
  }, [dataLength]);// dataLength가 변경될 때마다 effect를 다시 실행
  // 나머지 컴포넌트 로직...
  return (
    // JSX 내용...
  );
};
export default YourComponent;

메모리 누수가 발생하는 이유와 useEffect를 사용해야 하는 이유는 React 컴포넌트의 생명주기와 관련이 있다.

메모리 누수가 발생하는 이유:

setInterval이 렌더링과 별개로 계속해서 실행 됨:

  • setInterval을 사용한 코드는 컴포넌트가 마운트되면서 실행되지만, 컴포넌트가 언마운트되어도 setInterval은 계속해서 실행된다.
  • setInterval이나 setTimeout과 같은 함수는 컴포넌트가 언마운트되더라도 계속해서 실행되는데, 이는 메모리 누수를 유발할 수 있다.

useEffect를 사용해야 하는 이유:
컴포넌트 생명주기 관리:

  • useEffect는 React 컴포넌트의 생명주기에 특별히 연결된 훅으로, 컴포넌트의 마운트, 언마운트, 업데이트 등의 시점에서 특정 동작을 수행할 수 있다.
  • useEffect를 사용하면 컴포넌트의 생명주기와 관련된 작업을 명확하게 처리할 수 있다.

언마운트 시 정리 작업 수행:

  • useEffect는 컴포넌트가 언마운트될 때 정리(clean-up) 작업을 수행하는 데에도 사용된다.
  • 예를 들어, setInterval과 같은 비동기 작업을 설정한 경우, 컴포넌트가 언마운트되기 전에 이러한 작업들을 정리(clean-up)해야 한다.

※비동기 작업: 코드의 실행 흐름을 차단하지 않고, 작업이 완료될 때까지 기다리지 않고 다른 작업을 계속 수행할 수 있는 프로그래밍 패턴. 시간초는 다른 작업을 신경쓰지 않으므로

 import {useEffect }from 'react';
  function YourComponent(){
    useEffect(()=>{
      // componentDidMount와 같은 동작
      // ...
  
      return ()=>{
        // componentWillUnmount와 같은 동작
        // 정리(clean-up) 작업을 수행
        // clearInterval, clearTimeout 등을 통해 비동기 작업 정리
  		//컴포넌트가 파괴될 때 특정 작업을 수행할 때도 유용!
      };
    }, []);// 빈 배열을 넣어 한 번만 실행되도록 설정
  
    return (
      // 컴포넌트 렌더링 로직
    );
  }

위의 코드에서 useEffect는 컴포넌트가 마운트될 때 한 번 실행되고, return 블록 내부에서 정리(clean-up) 작업이 정의되어 있다.
또한, 빈 배열 []을 두 번째 매개변수로 전달하여 useEffect가 컴포넌트가 마운트될 때만 실행되도록 설정했다.
이렇게 하면 useEffect 내부에서 설정한 비동기 작업은 컴포넌트가 언마운트되기 전에 정리(clean-up)다.

Link에서 절대경로, 상대경로

<Link to="followers"> : naver.com/user/1/followers

<Link to="/followers"> : /followers
profile
기록하자

0개의 댓글

관련 채용 정보