React Clean Code - State(상태)

GunYong·2024년 5월 17일

React

목록 보기
2/17
post-thumbnail

2024 트랜드

  • React + Typescript 가 강세를 보인다
  • React 공식 홈페이지가 리뉴얼 되었다. https://react.dev/blog/2023/03/16/introducing-react-dev
  • 상태 관리의 강세는 TanStack Query
  • React Server Component --> Next.js << 라이징 스타 + Vercel
  • CRA는 최근 1년간 업데이트가 없다. 느리다는 인식이 강하게 박혔다. -> 대체로 Vite를 사용한다.

진행할 개발 환경

React 18 + Vite + VSC

상태

상태... 리엑트 하면서 상태 관리를 정말 많이하고 컴포넌트,전역,서버 등으로 확장되면서 관리하고 만들고 있었다.

과연 상태를 만들어야 하는 이유가 뭘까? 어떤 상황에서 어떠한 상태를 만들어서 사용하는게 적절할까? 라는 고민을 해본다.

  1. 초기값 설정

    상태 관리 훅에서 대표적으로 useState를 많이 사용한다. 이때 초기값 설정이 중요하다.

    초기값을 설정해주어야 하는 이유

    • 렌더링 이슈, 무한 루프, 타입 불일치등 의도치 않은 동작 에러가 발생해 런타임 오류가 발생한다.
    • 넣지 않으면 undefined 이다.
    • 상태를 CRUD 할때 초기값을 통해 방어 가능
    • null 처리 할떄도 불필요한 방어코드의 사용을 줄여준다.

업데이트 되지 않는 값

코딩을 하다보면 key와 value로 이루어진 정적인 데이터를 다루는 일이 많다. 필자도 코딩을 하면서 해당 정보들을 컴포넌트 내부에 포함시킬지 아니면 아예 외부로 빼낼지 고민했던 경험이 있는데 이번 기회로 확실하게 알게 되었다.

const DATA = {
  name: "gunyong",
  age: 25,
};

export default function App() {
  return (
    <div className="App">
      <h1>{DATA.name}</h1>
      <PropsController data={DATA}/>
    </div>
  );
}

랜더링할떄 사용하거나 props로 전달해주는 경우로 다양하게 쓰일 경우 정적인 데이터는 외부로 뺴주어서 관리해주는 것이 클린 코드를 작성하는데 도움이 된다.

플래그 값 설정

로그인 여부와 같이 수 많은 요소들의 조건을 만족할때 true or false를 나타내주는 경우 useState를 사용해서 상태로 만들지 않고 변수에 저장해주어서 플래그 값을 제어해주는 경우가 더 간단하다.

--> 플래그로 상태를 정의할 수 있다.

리렌더링 방지가 필요하다면 useState -> useRef

컴포넌트의 전체적인 수명과 동일하게 지속된 정보를 일관적으로 제공해야하는 경우

컴포넌트가 계속해서 렌더링이 되어도 컴포넌트가 언마운드되기 전까지는 값을 그대로 유지

자주 변경되는 값을 state에 담으면, 변경될때마다 재렌더링이 일어나서 성능에 안좋은 영향을 미친다. 하지만 useRef를 이용하면 값이 변경될때마다 렌더링이 일어나지 않는다. ➡️ 성능향상

const RefState = () => {
  const [isMount,setIsMount] = useState(false);
  
  useEffect(() => {
    if(!isMount) {
      setIsMount(true);
    }
  },[isMount])
}

// 상태 변경이 리렌더링을 유발할 필요가 없고 단순히 마운트 여부를 추적하는 목적일때
const RefState = () => {
  const isMount = useRef(false);
  
  useEffect(() => {
    isMount.current = true;
    
    return () => {
      isMount.current = false;
    }
  },[])
}

연관된 상태는 객체로 묶어보기

const [isLoading,setIsLoading] = useState(false);
const [isFinish,setIsFinish] = useState(false);
const [isError,setIsError] = useState(false);

const [fetchState,setFetchState] = useState({
  isLoading : false,
  isFinish : false,
  isError : false,
})

// 객체로 저장한 3개의 상태 중에 변경하고 싶은 상태가 생겼을때에는 이전 상태를 콜백으로 받기
setFetchState((prevState) => {
  ...prevState,
  isLoading : true,
})

1 : 1 로 상태를 관리하는 것이 아니라 N : 1로 관리 해주는 것이다.
프로젝트를 진행하면서 한 페이지에서 10개 이상의 상태를 관리해주어야 하는 상황이 있는데 이때 10개 이상의 useState를 사용해서 코드를 짠 경험이 있다. 짜면서도 이게 맞나? 싶었는데 해당 내용을 바탕으로 연관성 있는 상태는 객체로 묶어서 리펙토링 해봐야겠다.

추가로 CustomHook을 사용해서 함수 내에는 JSX만 존재하게 하여 코드를 깔끔하게 리펙토링 할 수 있다.

우선 연관성 있는 상태로 객체로 묶은 후에 CustomHook으로 데이터를 다루는 로직과 JSX을 분리하여 리펙토링 해봐야겠다.

상태를 업데이트 할때에는 이전 상태를 참조하자

const PrevState = () => {
  const [count,setCount] = useState(0);
  
  const updateState = () => {
    setCount(count + 1) // setCount(0 + 1)
    setCount(count + 1) // setCount(0 + 1)
  }
  
  const updatePrevState = () => {
    setCount((prev) => prev + 1) // setCount(0 => 1)
    setCount((prev) => prev + 1) // setCount(1 => 2)
  }
}

이전 상태를 꺼내 사용해야 Input을 핸들링하거나 상태를 조작할 때 예상치 못한 에러에 대응이 유연하다.

0개의 댓글