React 애플리케이션은 종종 원격 API에서 데이터를 검색해야 하는데, 이는 프레임워크 내에 use() 훅을 통합함으로써 React 개발팀이 예상했던 시나리오입니다. 이 간소화된 접근 방식은 개발자가 애플리케이션을 구축하는 동안 원활한 데이터 수집을 용이하게 합니다.

이 소개에서는 비동기 작업을 관리하고 애플리케이션 상태를 업데이트하는 데 필요한 반복적인 코딩을 최소화하기 위해 React의 새로운 “use” 훅을 사용하는 솔루션을 제시합니다. 이 접근 방식을 활용하면 개발자는 일반적으로 애플리케이션 내에서 프로미스를 정의하고 업데이트를 처리하는 데 사용되는 상용구 코드를 줄임으로써 개발 프로세스를 효과적으로 간소화할 수 있습니다. 이 글에서는 “사용” 훅의 기능에 대한 이해와 다양한 React 기반 프로젝트에서의 실제 구현에 대해 자세히 살펴봅니다.

기본 컴포넌트

주어진 텍스트는 지정되지 않은 “컴포넌트”에 대해 설명하는 구절입니다. 구체적인 예를 제공하기 위해 다음 사례를 살펴봅시다:

 import {useEffect, useState} from "react"

export function Data({ url }) {
  const [isLoading, setIsLoading] = useState(true)
  const [isError, setIsError] = useState(false)
  const [data, setData] = useState()

  useEffect(() => {
    setIsError(false)
    setIsLoading(true)
    setData(undefined)

    fetch(url)
      .then(res => res.json())
      .then(setData)
      .catch(() => setIsError(true))
      .finally(() => setIsLoading(false))
  })

  return isLoading ? (
    <h1>Loading...</h1>
  ) : isError ? (
    <h1>Error</h1>
  ) : (
    <pre>{JSON.stringify(data, null, 2)}</pre>
  )
}

React에서 이 컴포넌트를 렌더링하면 fetch() 메서드를 사용하여 API가 검색됩니다. 후속 요청이 성공하면 데이터는 컴포넌트의 상태에 동화되고, 요청이 실패하면 isError 변수가 true로 설정됩니다.

애플리케이션의 현재 상태에 따라 API에서 얻은 정보 또는 오류 메시지를 표시합니다. API 요청을 하는 동안 “로드 중…”이라는 메시지가 표시됩니다.

사용 훅() 구현

`use()` 훅의 효율성 향상 유틸리티를 활용하면 정교한 구현 기법을 통해 프로세스를 간소화하여 장황한 코딩의 부담을 줄일 수 있습니다. 이 접근 방식을 채택하면 광범위한 상용구 코드의 필요성을 효과적으로 없애고 애플리케이션의 전체 구조를 단순화할 수 있습니다.

`use()` 후크를 사용하면 제공된 컴포넌트를 간소하게 구현할 수 있으며, 단 두 줄의 코드로 줄일 수 있습니다. 하지만 이 특정 훅은 비교적 새로운 것이므로 React의 실험적인 반복 내에서만 사용할 수 있다는 점에 유의해야 합니다. 따라서 이 기능을 구현할 때는 반드시 해당 버전을 사용하고 있는지 확인해야 합니다.

 // package.json
"dependencies": {
  "react": "experimental",
  "react-dom": "experimental"
}

...

이제 간단한 사용 문으로 useState 및 useEffect 임포트를 대체하는 것으로 시작하여 후크를 활용할 수 있습니다.

 import {use} from "react"

Data 컴포넌트의 범위 내에서 유지되어야 하는 유일한 엔티티는 검찰 엔트리입니다. 그러나 검찰 탄원서를 사용자 후크의 범위 내에 포함하려면 해당 리셉터클 내에 검찰 탄원서를 캡슐화해야 합니다. 이 작업은 구조화된 형식의 정보 또는 비정상적인 정보를 검색한 다음 ‘데이터’라는 매개변수에 할당하는 결과를 가져옵니다.

 export function Data({ url }) {
  const data = use(fetch(url).then(res => res.json()))

  return <pre>{JSON.stringify(data, null, 2)}</pre>
}

실제로 `use()` 훅을 활용함으로써 이 기능의 구현이 매우 간소화되고 효율적이 되었습니다. 컴포넌트를 단 두 줄의 코드로 압축함으로써 `use()` 훅이 이러한 상황에서 제공하는 엄청난 가치를 예시했습니다.

이 글도 확인해 보세요:  판다와 폴라: 성능 대결

로딩 상태(서스펜스)

로딩 및 오류 상태 처리는 데이터 기반 애플리케이션의 상위 컴포넌트 내에서 `use()` 훅을 활용하는 데 필수적인 측면을 구성합니다. 이러한 기능의 구현은 해당 훅의 사용을 관리하는 포괄적인 엔티티 내에서 이루어지므로 데이터 수명 주기 관리 프로세스와 원활하게 통합할 수 있습니다.

로딩 메커니즘을 통합하려면 Suspense를 사용하여 데이터 구성 요소를 둘러싸십시오. Suspense 요소는 로딩 기간 동안 플레이스홀더 역할을 하며 사용 가능한 데이터가 없을 때 콘텐츠를 제공합니다. 애플리케이션이 로딩 상태일 때 표시할 내용을 지정하는 폴백 프로퍼티를 사용할 수 있습니다.

 export default function App () {
  const [url, setUrl] = useState(URL.USERS)

  return (
    <>
      <Suspense fallback={<div>Loading...</div>}>
        <Data url={url} />
      </Suspense>
    </>
  )
}

데이터 컴포넌트 내에서 `use()` 훅을 사용하면 보류 중인 프로미스의 해결을 기다리는 동안 애플리케이션이 “폴백 상태”라고 하는 대체 시각적 표현을 일시적으로 표시하여 렌더링을 효율적으로 관리하고 최적화할 수 있는 “서스펜스”라는 프로세스가 시작됩니다. 데이터 컴포넌트가 응답 데이터를 성공적으로 획득하면 초기 폴백 상태를 실제 콘텐츠로 대체하여 데이터 처리의 여러 단계 간에 원활한 전환을 통해 전반적인 사용자 경험을 향상시킵니다.

오류 경계로 오류 처리

오류를 감지하는 데 오류 경계를 효과적으로 활용하려면, 특히 서스펜스와 함께 사용할 때 그 기능을 포괄적으로 이해해야 합니다.

오류 경계에 대한 데모는 다음 코드에서 확인할 수 있습니다:

 import React from "react"

class ErrorBoundary extends React.Component {
  state = { hasError: false, error: null }

  static getDerivedStateFromError(error) {
    return {
      hasError: true,
      error
    }
  }

  render() {
    if (this.state.hasError) {
      return this.props.fallback
    }

    return this.props.children
  }
}

export default ErrorBoundary;

제공된 오류 경계 인스턴스는 현재 오류 상태와 특정 특성을 모니터링하는 상태 객체를 유지합니다. 이후 이 정보는 후속 상태를 도출하는 데 사용됩니다. 렌더() 메서드는 오류 발생 시 폴백 컴포넌트의 기본 디스플레이를 표시합니다. 반대로 오류가 없는 경우 이 메서드는 평소와 같이 요소 내의 콘텐츠를 렌더링합니다.

이 글도 확인해 보세요:  Rust의 제네릭 형식 알아보기

이 컴포넌트는 Suspense 컴포넌트와 유사하게 작동합니다. 애플리케이션 내에서 이 컴포넌트를 활용하려면 다음과 같이 ErrorBoundary 컴포넌트 내의 모든 요소를 둘러싸면 됩니다:

 export default function App () {
  const [url, setUrl] = useState(URL.USERS)

  return (
    <>
      <ErrorBoundary fallback={<div>Oops! There's an error.</div>}>
        <Suspense fallback={<div>Loading...</div>}>
          <Data url={url} />
        </Suspense>
      </ErrorBoundary>
    </>
  )
}

에러 바운더리 컴포넌트는 에러로 묶인 코드 블록 내에서 실수가 발생하면 getDerivedStateFromError() 메서드를 사용하여 이를 감지한 후 상태를 조정하여 “예기치 않은 딸꾹질이 발생했습니다.”라는 대체 메시지를 표시합니다.

사용() 훅 규칙

`사용()` 훅을 사용하면 로딩 및 오류 조건에 액세스하고 처리하는 프로세스를 단순화하면서 장황한 코딩 필요성을 최소화할 수 있는 방법을 제시합니다. 또한 이 함수는 또 다른 장점도 제공합니다.

해당 부울 변수가 참으로 평가될 때만 데이터 검색 작업을 시작하려는 의도로 `shouldFetch`라는 부울 값이 데이터 컴포넌트에 프로퍼티로 전달되는 시나리오를 가정해 보겠습니다.

기존의 React 훅은 if 문 안에 포함할 수 없지만, “use” 훅을 사용하면 루프나 조건문 안에 캡슐화할 때에도 원하는 곳 어디에서나 사용할 수 있어 유연성과 활용도가 높아집니다.

 export function Data({ url, shouldFetch }) {
  let data = "Default data"

  if (shouldFetch) {
    const data = use(fetch(url).then(res => res.json()))
  }

  return <pre>{JSON.stringify(data, null, 2)}</pre>
}

제공된 코드를 사용하면 React에서 초기 렌더링으로 “기본 데이터”를 표시할 수 있습니다. 그러나 부모 컴포넌트로부터 `shouldFetch` 프로퍼티가 전달되면 React는 네트워크 요청을 시작하고 수신된 응답을 활용하여 `data`의 값을 업데이트합니다.

`use()` 훅의 활용과 관련하여 주목할 만한 또 다른 측면은 프로미스에만 국한되지 않는 다용도성입니다.

 export function Data({ url, shouldFetch }) {
  let data = "Default data"

  if (shouldFetch) {
    const data = use(Context)
  }

  return <pre>{JSON.stringify(data, null, 2)}</pre>
}

 export function Data({ url, shouldFetch }) {
  let data = "Default data"

  if (shouldFetch) {
    const data = use(Context)
  }

  return <pre>{JSON.stringify(data, null, 2)}</pre>
}

if-문 및 루프와 같은 조건 구조 내에서 `useContext()` 훅을 활용하는 데는 몇 가지 제한이 있습니다. 그러나 이러한 구조 내에서 `use()` 훅을 if 문이나 루프로 감싸서 캡슐화할 수 있습니다.

React Hook 모범 사례

어디에나 있는 “사용” 훅과 같은 다양한 훅의 활용에 익숙해지는 것은 React 개발의 숙련도를 높이는 데 가장 중요한 요소입니다. 이러한 훅의 복잡성을 이해하고 구현을 위한 최적의 전략을 고안하는 것은 이 영역에서 개발자의 전문성을 향상시키는 데 크게 기여할 수 있습니다.

이 글도 확인해 보세요:  JES를 활용한 흥미로운 사운드 처리 기법 3가지

By 박준영

업계에서 7년간 경력을 쌓은 숙련된 iOS 개발자인 박준영님은 원활하고 매끄러운 사용자 경험을 만드는 데 전념하고 있습니다. 애플(Apple) 생태계에 능숙한 준영님은 획기적인 솔루션을 통해 지속적으로 기술 혁신의 한계를 뛰어넘고 있습니다. 소프트웨어 엔지니어링에 대한 탄탄한 지식과 세심한 접근 방식은 독자에게 실용적이면서도 세련된 콘텐츠를 제공하는 데 기여합니다.