{{packageMeta.displayName}}의 로고

async

ver 3.2.6 ∙ 2024.11.05 업데이트됨

개요

Async, 비동기 JavaScript 작업을 처리하기 위한 간편하고 강력한 함수를 제공하는 유틸리티 모듈. 원래는 Node.js와 함께 사용하기 위해 설계되었으며, 브라우저에서도 직접 사용할 수 있음

관련 게시물

모두 보기

📝 메타의 스레드, 모놀리틱 아키텍처 사용

스레드를 5개월만에 런칭하기 위해 모놀리틱 아키텍처를 사용했고, 5일 만에 1억명의 사용자가 몰려드는 것을 수용할 수 있었음.


사용된 기술은 커스텀 버전의 Django와 PHP, 데이터 저장소로는 TAO/UDB/MySQL와 ZippyDB 그리고 피크 타임을 위한 서버리스 펑션 Async.


자, 말 할 거 많죠? ㅋㅋㅋ 한마디하고 싶은 분들 다 여기여기 붙으세요. 🤣🤣🤣

Next.js 15 출시: 4가지 주요 변화

Next.js15 가 정식 버전으로 출시되었습니다. 이번 릴리즈는 React19와 긴밀하게 통합하여 React19 RC 버전을 채택하고 React 컴파일러에 대한 지원도 추가되었습니다. 역시 Next.js와 리액트는 한몸이네요. 주요 변경사항은 아래와 같습니다.


  1. 코드베이스 업그레이드 자동화(@next/codemod) : TanStackQuery@V5와 같이 codemod를 통한 손쉬운 업그레이드를 지원합니다. 의존성 패키지 자동 업데이트 및 코드 자동 변환 기능을 제공한다고 하네요.


  2. SSR 렌더링 최적화(Async Request APIs): SSR 성능 개선을 위한 새로운 접근 방식 인데요. 데이터 의존성이 있는 컴포넌트를 async로 명시적으로 구분하여 데이터가 필요없는 컴포넌트는 사전 렌더링하여 전체 성능을 향상시켰습니다. 스트리밍SSR과 비슷한 최적화 개념인것 같습니다.


  3. API Route 캐싱 정책 변경: GET Handler의 기본 캐싱을 비활성화 했습니다. 이유는 PPR(Partial Prerendering) 호환성 문제, 기본값이 캐시되는 것이 항상 최선은 아니라는 피드백을 반영하였습니다.


  4. Turbopack 정식 버전으로 전환: Next.js의 개발 서버 번들러인 Turbopack이 정식 버전으로 릴리즈되었습니다. 아직도 기본 번들러는 Webpack이지만, Rust로 작성된 Turbopack에 많은 투자를 하고 있는만큼 머지않아 기본 번들러가 Turbopack으로 전환될 것 같네요.


이번 업데이트 역시 개발자 경험 개선(DX) 개선과 성능 향상에 중점을 두었습니다. 그리고 Turbopack이 안정화 되었고 매우 빠른 속도를 제공하는 만큼 개발 모드에서는 Turbopack을 사용하고 배포에서는 안정적으로 webpack을 사용해봐도 좋을것 같습니다.


https://nextjs.org/blog/next-15

Next.js 15

nextjs.org

Next.js 15

Vitest 짧막 팁 2가지

1. Vitest의 vi.mock 은 ESModule import를 넣을 수 있다.

장점: IDE에서 import 경로를 추적할 수 있어서 경로를 업데이트 할 때 같이 바꿔주기 때문에 실수를 줄여줍니다.

- jest.mock('axiost')
+ vi.mock(import('axios'))

2. Vitest의 vi.mock 은 두 번째 인자로 부분 모킹이 가능하다.

장점: 모듈에 타입 지원이 됩니다.

- jest.mock('ant-design', () => ({
-   ...jest.requireActual('ant-design'),
-   Typography: jest.fn().mockImplementation(({ children }) => <div>{children}</div>),
- }));

+ vi.mock(import('ant-design'), async (importOriginal) => ({
+   ...(await importOriginal()), // ((parameter) importOriginal: <typeof import("ant-design")>() => Promise<typeof import("ant-design")>)
+   Typography: vi.fn().mockImplementation(({ children }) => <div>{children}</div>),
+ }))

https://vitest.dev/api/vi.html#vi-mock

Vitest

Vitest

Vitest

서버 중심 라우팅: Next.js의 App Router 분석

App Router는 Next.js의 진화된 라우팅 시스템으로, 기존의 pages/ 디렉토리 기반 라우팅에서 벗어나 새로운 app/ 디렉토리를 통한 라우팅 방식을 도입합니다. 이 시스템은 Next.js의 철학에 따라 모든 기능이 라우터 중심으로 설계되었으며, 페이지 전환, 데이터 페칭, 캐싱, 데이터 변경 및 재검증, 스트리밍 등의 과정을 포괄적으로 관리합니다.


주요 특징:

  1. 서버 중심 라우팅: App Router는 React Server Components를 기반으로 구축되었으며, 이는 서버에서 데이터를 효율적으로 가져오는 데 중점을 두고 있습니다.

  2. SPA와 유사한 경험: 경로 변경 시 전체 페이지를 리렌더링하지 않고, URL만 업데이트하여 필요한 세그먼트만 렌더링함으로써 단일 페이지 애플리케이션(SPA)과 유사한 사용자 경험을 제공합니다.

  3. 코드 단순화 및 최적화: layout, loading, error.js 등 핸들링을 위한 다양한 파일들이 제공되어, 각 상황에 맞는 코드가 파일 내에 존재함으로써 코드의 복잡성을 줄여줍니다. Ex)코드레벨에서 if(error){} 등의 코드가 불필요

  4. 서버 컴포넌트 및 클라이언트 컴포넌트: app/ 디렉토리 내의 파일은 기본적으로 서버 컴포넌트로 작동하며, 이는 초기 페이지 로드 속도를 개선하고 캐시 가능성을 높입니다. 클라이언트 컴포넌트는 use client를 명시함으로써 사용할 수 있는데요 클라이언트 컴포넌트란 useState, useEffect 훅을 사용하거나 브라우저 API 의존성이 있거나 특정 이벤트 리스너(onClick, onChange)를 추가하는 경우가 이에 해당 합니다. 그리고 클라이언트 컴포넌트에서는 서버 컴포넌트를 import 할 수 없고 클라이언트 컴포넌트를 트리의 leaf 노드에 가깝게 설계하는것이 좋습니다.

  5. 데이터 페칭의 단순화: getServerSideProps, getStaticProps, getInitialProps와 같은 메서드를 더 이상 사용하지 않고, 리액트 서버 컴포넌트 기반 이기 때문에 async/await 문법을 사용하여 서버 데이터를 직접 가져올 수 있습니다. 이는 next/build 시 데이터 페칭을 수행하고 캐싱하는 방식으로, 기존의 useEffect를 사용한 데이터 페칭과 상태 변경 방식에서 벗어남으로써 성능을 개선합니다.


그렇지만 App Router는 아직은 초기 단계로, 일부 라이브러리(예: MSW, Emotion)와의 호환성 문제가 있을 수 있습니다. 또한 기존 Page 기반 라우팅 에서 지원되던, 라우터 이벤트 및, 내장 i18n 지원의 부재, 초기 버그 등 몇 가지 단점이 존재합니다.


그렇지만 이러한 측면을 고려하더라도, App Router는 지속적인 업데이트가 기대되는 만큼 통해 성능 향상에 중요한 역할을 할 것으로 보입니다. Vercel 에서는 App 라우팅 시스템의 사용을 권장하고 있기 때문에, 향후 더 안정적이고 성능이 우수한 웹 애플리케이션 개발을 위한 중요한 도구로 자리 잡을 것으로 보입니다.


https://nextjs.org/docs/app

App Router | Next.js

nextjs.org

App Router | Next.js

RSC의 이해: 클라이언트 컴포넌트에서 서버컴포넌트로

React가 클래스 컴포넌트에서 함수 컴포넌트를 개발하고 사용을 권장해서 현재는 대부분 함수 컴포넌트로 개발을 하고 있는데요.

Next.js 에서도 최근 앱 라우터를 출시해서 페이지 기반 라우터에서 앱 라우터의 사용을 권장하고 있습니다. 앱 라우터는 기본적으로 모든 컴포넌트가 서버 컴포넌트 입니다. 따라서 React개발 흐름이 '리액트 서버 컴포넌트' 라고 불리우는 'RSC'로 방향을 이어가고 있는데요. 따라서 React개발자는 이러한 변화에 맞추어 이 기술을 활용하고 적응해야 합니다. 그럼 이 RSC는 무엇일까요?


클라이언트 사이드 UI 라이브러리

리액트는 초기에 아주 간단한 클라이언트 사이드 UI라이브러리 였습니다. 큰 컴포넌트를 작은 컴포넌트 조각으로 나누는것을 제안했습니다. 자체 비공개 데이터인 State 와 데이터를 전달하는 방법인 Props로 컴포넌트 계층 구조를 나누고 데이터 흐름을 관리했습니다. 자바스크립트 함수를 통해서 말이죠.


그렇다면 기존 리액트 앱의 문제는 무엇이었을까요?

  1. JavaScript 파일 크기로 인한 초기 로딩 시간 지연: SSR을 통해 어느정도 문제를 해결할수는 있지만, 여전히 클라이언트에서 추가적인 JavaScrip를 실행해야 합니다.

  2. 네트워크 워터폴로 인한 클라이언트 컴포넌트 응답 지연

  3. 레이아웃 이동 문제: 네트워크 API응답 순서에 대한 보장이 없다보니, 지연 시간 등의 요인에 따라 컴포넌트 로딩 순서가 여러 요인에 따라 달라집니다.

이러한 문제를 해결하기 위해 React 컴포넌트를 서버로 옮기는 구상을 하게 됩니다.

컴포넌트가 서버에 있으면 데이터를 미리 가져오고 처리하여 클라이언트에 전달함으로써, 클라이언트는 렌더링에만 집중할 수 있게 됩니다.

따라서 초기 로드 시간을 단축하고 네트워크 효율성을 개선할수 있는 일종의 패러다임의 전환 이라고 볼수 있는데요.


RSC는 다음과 같은 특징이 있습니다.

  1. 비동기 호출을 처리해서 컴포넌트가 async 타입이다.

  2. 컴포넌트 자체에서 DB에 연결이 가능하다(Express 처럼)

  3. console.log를 찍으면 브라우저 콘솔이 아닌 서버 콘솔에 찍힌다.


또한 다음과 같은 주의사항이 있습니다.

  • 사용자 인터렉션을 추가할 수 없다(이벤트 핸들러)

  • LocalStorage 같은 브라우저 웹 API를 사용할 수 없다.

  • 클라이언트 상호 작용과 관련된 것은 클라이언트 컴포넌트를 사용해야 한다.


크롬의 Source탭에서는 클라이언트 컴포넌트 JavaScript 코드를 확인할 수 있습니다. RSC는 서버에서 실행되고 처리되어 Source탭에서는 확인할수 없고 서버의 코드를 직접 확인해야 합니다.

위 내용과 관련하여 더 자세한 내용을 알 고 싶으신 분은 아래 사이트를 방문해서 보시는것을 추천드립니다.


https://www.freecodecamp.org/korean/news/how-to-use-react-server-components/



React 서버 컴포넌트를 사용해야 하는 이유와 방법

freeCodeCamp.org

React 서버 컴포넌트를 사용해야 하는 이유와 방법

관련 개발자 Q&A

모두 보기

ReactNative ios build 에러 3일째 해결을 못했습니다.

시뮬레이션을 실행하려고 해도 스크립트 문제, iPhone 버전 범위 문제, 시뮬레이터 문제가 계속 발생합니다. 어떤 도움이라도 감사합니다. ReactNative를 처음 접했습니다. 저희 팀에서 저를 도울 수 있는 사람이 없습니다. #프로젝트 환경 mac M2 ruby -v ruby 2.6.10p210 (2022-04-12 revision 67958) [universal.arm64e-darwin23] node -v v20.10.0 pod --version 1.15.2 package.json { "name": "labts", "version": "0.0.1", "private": true, "scripts": { "android": "react-native run-android", "ios": "react-native run-ios", "lint": "eslint .", "start": "react-native start", "test": "jest" }, "dependencies": { "@react-native-community/async-storage": "^1.12.1", "@react-native-community/cli": "13.6.9", "@react-navigation/bottom-tabs": "^6.6.0", "@react-navigation/native": "^6.1.17", "@react-navigation/native-stack": "^6.10.0", "@tanstack/react-query": "^5.51.5", "@types/react-native-vector-icons": "^6.4.18", "axios": "^1.7.2", "date-fns": "^3.6.0", "immer": "^10.1.1", "react": "18.2.0", "react-native": "0.74.3", "react-native-calendars": "^1.1305.0", "react-native-date-picker": "^5.0.4", "react-native-dotenv": "^3.4.11", "react-native-get-random-values": "^1.11.0", "react-native-image-crop-picker": "^0.41.2", "react-native-image-zoom-viewer": "^3.0.1", "react-native-paper": "^5.12.3", "react-native-permissions": "^4.1.5", "react-native-safe-area-context": "^4.10.8", "react-native-screens": "^3.32.0", "react-native-splash-screen": "^3.3.0", "react-native-tab-view": "^3.5.2", "react-native-vector-icons": "^10.1.0", "react-native-vision-camera": "^4.5.1", "uuid": "^10.0.0", "yarn": "^1.22.22" }, "devDependencies": { "@babel/core": "^7.20.0", "@babel/preset-env": "^7.20.0", "@babel/runtime": "^7.20.0", "@react-native/babel-preset": "0.74.85", "@react-native/eslint-config": "0.74.85", "@react-native/metro-config": "0.74.85", "@react-native/typescript-config": "0.74.85", "@types/react": "^18.2.6", "@types/react-native-dotenv": "^0.2.2", "@types/react-test-renderer": "^18.0.0", "babel-jest": "^29.6.3", "babel-plugin-module-resolver": "^5.0.2", "eslint": "^8.19.0", "jest": "^29.6.3", "prettier": "2.8.8", "react-test-renderer": "18.2.0", "typescript": "5.0.4" }, "engines": { "node": ">=18" } } PodFile require Pod::Executable.execute_command('node', ['-p', 'require.resolve( "react-native/scripts/react_native_pods.rb", {paths: [process.argv[1]]}, )', __dir__]).strip platform :ios, '12.0' use_frameworks! #use_modular_headers! prepare_react_native_project! linkage = ENV['USE_FRAMEWORKS'] if linkage != nil Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green use_frameworks! :linkage => linkage.to_sym end target 'nexlabts' do config = use_native_modules! use_react_native!( :path => config[:reactNativePath], # An absolute path to your application root. :app_path => "#{Pod::Config.instance.installation_root}/.." ) target 'nexlabtsTests' do inherit! :complete # Pods for testing end post_install do |installer| # https://github.com/facebook/react-native/blob/main/packages/react-native/scripts/react_native_pods.rb#L197-L202 react_native_post_install( installer, config[:reactNativePath], :mac_catalyst_enabled => false, # :ccache_enabled => true ) end end 제가 아래 에러 3가지에 대해 제가 해본 방법들입니다. 1. node 재설치 node_module 폴더 삭제, package-rock.json 삭제 후 재설치 npm install --legacy-peer-deps yarn install 2. Xcode가 node 읽을 수 있도록 설정 sudo ln -s "$(which node)" /usr/local/bin/node 3. Podfile 내 platform 설정 수정 platform :ios, '12.0' or platform :ios, '14.0' 4. Pods 재설치 rm -rf ~/Library/Developer/Xcode/DerivedData or rm -rf ~/Library/Developer/Xcode/DerivedData/* rm -rf Pods rm Podfile.lock pod install --repo-update Xcode \> Product \> Clean Build Folder. cd ./ios pod cache clean -all pod install --repo-update cd ../ npx react-native run-ios --no-packager --simulator="iPhone 15" or npx react-native run-ios --simulator="iPhone 15" or yarn start > i(run ios) Err 1. cocoaPods 설치할 때 [!] CocoaPods could not find compatible versions for pod "React-RuntimeHermes": In Podfile: React-RuntimeHermes (from ../node_modules/react-native/ReactCommon/react/runtime) Specs satisfying the React-RuntimeHermes (from ../node_modules/react-native/ReactCommon/react/runtime) dependency were found, but they required a higher minimum deployment target. Err2. iOS 실행할때 run-ios --no-packager --simulator="iPhone 15" Build description signature: fc1341421f84b87c5245d346c2c17b66 Build description path: /Users/nowonjae/Library/Developer/Xcode/DerivedData/nexlabts-argvodqcybjfcybstpulfpghnzvm/Build/Intermediates.noindex/XCBuildData/fc1341421f84b87c5245d346c2c17b66.xcbuilddata /Users/nowonjae/Desktop/project/NeXLabRN/ios/nexlabts.xcodeproj:1:1: error: Unable to open base configuration reference file '/Users/nowonjae/Desktop/project/NeXLabRN/ios/Pods/Target Support Files/Pods-nexlabts/Pods-nexlabts.release.xcconfig'. (in target 'nexlabts' from project 'nexlabts') warning: Unable to read contents of XCFileList '/Target Support Files/Pods-nexlabts/Pods-nexlabts-resources-Release-output-files.xcfilelist' (in target 'nexlabts' from project 'nexlabts') warning: Unable to read contents of XCFileList '/Target Support Files/Pods-nexlabts/Pods-nexlabts-frameworks-Release-output-files.xcfilelist' (in target 'nexlabts' from project 'nexlabts') error: Unable to load contents of file list: '/Target Support Files/Pods-nexlabts/Pods-nexlabts-frameworks-Release-input-files.xcfilelist' (in target 'nexlabts' from project 'nexlabts') error: Unable to load contents of file list: '/Target Support Files/Pods-nexlabts/Pods-nexlabts-frameworks-Release-output-files.xcfilelist' (in target 'nexlabts' from project 'nexlabts') warning: Run script build phase 'Bundle React Native code and images' will be run during every build because it does not specify any outputs. To address this warning, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'nexlabts' from project 'nexlabts') warning: Run script build phase '[CP] Embed Pods Frameworks' will be run during every build because it does not specify any outputs. To address this warning, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'nexlabts' from project 'nexlabts') error: Unable to load contents of file list: '/Target Support Files/Pods-nexlabts/Pods-nexlabts-resources-Release-input-files.xcfilelist' (in target 'nexlabts' from project 'nexlabts') error: Unable to load contents of file list: '/Target Support Files/Pods-nexlabts/Pods-nexlabts-resources-Release-output-files.xcfilelist' (in target 'nexlabts' from project 'nexlabts') warning: Run script build phase '[CP] Copy Pods Resources' will be run during every build because it does not specify any outputs. To address this warning, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'nexlabts' from project 'nexlabts') --- xcodebuild: WARNING: Using the first of multiple matching destinations: { platform:iOS Simulator, id:B5AA2E84-4F83-4749-A986-A1FCE5E398A3, OS:17.5, name:iPhone 15 } { platform:iOS Simulator, id:B5AA2E84-4F83-4749-A986-A1FCE5E398A3, OS:17.5, name:iPhone 15 } ** BUILD FAILED ** ] Err3. Xcode 로 Build 할때 (Any iOS Simulator Device (arm64, x86_64)) Command PhaseScriptExecution failed with a nonzero exit code

위 에러 해결되었습니다. 크몽에 범코딩님께 에러 문의 및 코칭 요청드렸고 피드백으로 에러 발생 원인은 중복실행 문제로. 아이폰 직접 연결 빌딩시 해결될 것으로 판단된다고 피드백 주셔서, 진행해보니 정상적으로 잘 빌딩되었습니다. 관련해서 추가 참고한 블로그입니다. https://pocket-dev.tistory.com/35#google_vignette

Next.js SSR + react-query 조합에서의 serializing 에러

안녕하세요! Next.js SSR + react-query 조합을 사용하려고 하는데요, page 컴포넌트 내 getServerSideProps 함수에서 prefetching을 받아온 후에 serializing 에러가 발생합니다. (Next.js는 13버젼입니다.) 에러 내용은 다음과 같습니다. Error: Error serializing `.dehydratedState.queries[0].state.data.headers` returned from `getServerSideProps` in "/top". Reason: `object` ("[object AxiosHeaders]") cannot be serialized as JSON. Please only return JSON serializable data types. 해당 에러 내용으로 구글링을 해보니, 대부분 getServerSideProps 함수 반환 코드에서 return { props: { dehydratedState: JSON.parse(JSON.stringify(dehydrate(queryClient))), }, }; 와 같이 dehydrate(queryClient)값을 JSON화 -> Object화를 하라고 하는데요, 이와 같이 사용해도 또 다시 아래와 같은 에러가 납니다. TypeError: Converting circular structure to JSON --> starting at object with constructor 'ClientRequest' | property 'socket' -> object with constructor 'Socket' --- property '_httpMessage' closes the circle Backend API는 Express.js를 사용하고 있으며, res.status(200).json({ data: ~ })와 같은 방식으로 응답을 주고 있습니다. 어떻게 해결할 수 있을까요? 코드 첨부가 안되네요, 아래는 page 컴포넌트가 위치한 파일의 전체 코드입니다. import type { ReactElement } from 'react'; import { dehydrate, QueryClient, useQuery } from '@tanstack/react-query'; import { format } from 'date-fns'; import TopMusicContainer from '~containers/TopMusicContainer'; import Layout from '~layouts/Layout'; import type { NextPageWithLayout } from '~pages/_app'; import TopMusicService from '~services/topMusicService'; import * as MusicType from '~types/musicType'; export async function getServerSideProps() { const queryClient = new QueryClient(); await queryClient.prefetchQuery(['fetchTopMusic'], () => { const params: MusicType.ListRequestType = { filter: 'title', keyword: '', page: 1, limit: 25, time: format(new Date(), 'yyyyMMddHH'), }; return TopMusicService.list(params); }); return { props: { dehydratedState: JSON.parse(JSON.stringify(dehydrate(queryClient))), }, }; } const Top: NextPageWithLayout = (): JSX.Element => { const { data, isLoading } = useQuery({ queryKey: ['fetchTopMusic'], queryFn: () => { const params: MusicType.ListRequestType = { filter: 'title', keyword: '', page: 1, limit: 25, time: format(new Date(), 'yyyyMMddHH'), }; return TopMusicService.list(params); }, }); return ( <section> <TopMusicContainer /> </section> ); }; Top.getLayout = function getLayout(page: ReactElement) { return <Layout>{page}</Layout>; }; export default Top;

안녕하세요. Axios response를 그대로 사용하시면 함수 등 JSON으로 변환이 불가능한 것들이 포함되어 있어서 axios response에서 data만 추출해야 하는 것으로 알고 있는데요. 혹시 TopMusicService.list(params); 의 리턴 타입이 어떻게 되나요? 참고한 SO 포스트: - https://stackoverflow.com/questions/67204170/getserversideprops-functions-response-cannot-be-serialized-as-json-in-next-js

api의 첫번째 호출 이후부터 antd Button 렌더링 안되는 이슈가 있습니다.

```jsx import { Popover, Modal, Button, Image, Result } from "antd"; const [prevImg, setPrevImg] = useState(["any"]); const [loading, setLoading] = useState(false); const [removeImgFiles, setRemoveImgFiles] = useState([]); const combinePrevImages = (prevImages, newImages) => { const combinedImages = [...prevImages, ...newImages]; return combinedImages; }; useEffect(() => { const postSeg = async () => { try { const res = await axios.post( "apiurl", { filepath: filePath, clips: sortableList.map(list => `${list.seg.start}-${list.seg.end}`), frame: frameValue }, { proxy: false } ); return res.data; } catch (error) { console.error("Error posting segments:", error); return []; } finally { setLoading(false); } }; const postSegments = async () => { if (segments[0]?.start === 0 && segments[0]?.end === 0) return; if (sortableList && filePath) { setLoading(true); const res = await postSeg(); const combinedPrevImg = combinePrevImages(prevImg, res.results); setPrevImg(combinedPrevImg); console.log("Post Request Success"); } }; postSegments(); }, [filePath, segments, frameValue]); const handleModalOpen = useCallback(() => setModalOpen(true), []); const handleModalClose = useCallback(() => { setRemoveImgFiles([]); setModalOpen(false); }, []); const handleDeleteButtonClick = async () => { if (removeImgFiles.length > 0) { setPrevImg([...removeImgFiles]); setRemoveImgFiles([]); } else { const result = await showSwal({ title: "Are you sure delete?", showCancelButton: true, confirmButtonText: "Confirm", cancelButtonText: "Cancel", confirmButtonColor: "#3085d6", cancelButtonColor: "#d33" }); if (result.isConfirmed) { setRemoveImgFiles([...prevImg]); setPrevImg([]); } const success = await Promise.all(removeImgFiles.map(deleteFiles)); return success; } } const handleRemoveFinish = async () => { if (removeImgFiles) { for (const filePath of removeImgFiles) { try { await removeFile(filePath); } catch (e) { console.log("File Remove Error", e); } } } setRemoveImgFiles([]); handleModalClose(); }; return ( <motion.div initial={{ x: width }} animate={{ x: 0 }} exit={{ x: width }} transition={mySpring} > <div style={{ fontSize: 12, padding: "0 5px", color: "var(--gray12)", display: "flex", justifyContent: "space-between", alignItems: "center" }} > <FaAngleRight title={t("Close sidebar")} size={20} className="angle-right" role="button" onClick={toggleSegmentsList} /> {header} <FaExpandArrowsAlt title={t("Image Inspection")} size={18} className="expand-arrow-alt" style={{ cursor: "pointer" }} role="button" onClick={!loading ? handleModalOpen : handleModalClose} /> <Modal title={t("Image Inspection")} centered onCancel={handleModalClose} open={modalOpen} footer={[]} width="100%" > <div className="imagecontainer"> <Button danger className="toggle-remove" onClick={handleDeleteButtonClick}> {removeImgFiles.length > 0 ? "Add" : "Remove"} </Button> {prevImg?.length > 10 && prevImg.map(img => ( <Popover key={img}> {removeImgFiles?.includes(img) ? ( <span> <Result className="result" icon={<FaSmile />} subTitle="delete" /> </span> ) : <Image key={uuidv4()} src={img} preview={{ src: img }} alt={uuidv4()} /> )} </Popover> ))} </div> <Button block onClick={handleRemoveFinish}> Finish </Button> </Modal> </div> ) ``` api 호출을 통해 frameValue 개수(여기서는 12개씩) 만큼 이미지를 렌더링 하고 있는데 두번째 호출부터는 Button이 렌더링되지 않아서 어디가 잘못됐는지 알고싶습니다.. 필요한 부분이 imagecontainer 클래스네임인 div를 렌더링 해야합니다.

리액트 쿼리 에러 핸들링 이슈

react query를 활용한 에러 핸들링이 안돼서 질문 올립니다... //mainpage.tsx const { data, refetch, isFetching } = FetchData(url); const handleSearch = () => { refetch(); } <QueryErrorResetBoundary> {({ reset }) => ( <ErrorBoundary onReset={reset} FallbackComponent={FallbackUI}> {resultVisible ? ( <Result searchData={searchData} isFetching={isFetching} /> ) : ( <EmptyResult /> )} </ErrorBoundary> )} </QueryErrorResetBoundary> react-error-boundary 라이브러리를 이용해 ErrorBoundary 컴포넌트를 가져왔습니다. ErrorBoundary 하위 컴포넌트 내에서 에러가 발생하면 FallbackComponent의 FallbackUI 컴포넌트가 렌더링 되도록 했습니다. //FallbackUI 컴포넌트 //에러가 발생히면 이 컴포넌트가 렌더링되어야합니다. const FallbackUI = ({ error, resetErrorBoundary }) => { return ( <div> <span>{error.message}...</span> <button onclick={resetErrorBoundary} /> 돌아가기 버튼 </div> ); }; export default FallbackUI; FallbackUI 에서 QueryErrorResetBoundary 에서 제공하는 resetErrorBoundary를 받아와 에러 발생 후 '돌아가기 버튼'을 클릭하면 쿼리오류를 처리하고 리셋해주도록 구현했습니다. //url을 파라미터값으로 받아와 api호출하는 함수 //위에 있는 mainpage.tsx 에서 사용하는 함수입니다. const FetchData = (url: string) => { const { error, data, refetch, isFetching } = useQuery({ queryKey: ["repoData"], queryFn: async () => { const res = await axios.get(url); console.log(res.data); return res.data; }, refetchOnWindowFocus: false, enabled: false, }); return { error, data, refetch, isFetching }; }; 리액트 쿼리를 이용해 api를 호출하는 함수입니다. //main.tsx const queryClient = new QueryClient({ defaultOptions: { queries: { retry: 0, throwOnError: true, }, }, }); ReactDOM.createRoot(document.getElementById("root")!).render( <React.StrictMode> <QueryClientProvider client={queryClient}> <BrowserRouter> <GlobalStyles /> <Provider store={store}> <App /> </Provider> </BrowserRouter> </QueryClientProvider> </React.StrictMode> ); 마지막으로 전역으로 에러 관리를 하도록 세팅해놨습니다. 그리고 QueryClient에 throwOnError 속성이 있어야 에러를 ErrorBoundary로 전달할 수 있다해서 추가해줬습니다. 이렇게 세팅해놨는데 에러발생하면 그냥 하얀색 화면만 나오고 fallbackUI가 나오지 않습니다... 원인이 뭘까요...ㅠㅠㅠ 혹시 몰라서 콘솔 에러코드도 올립니다.. 추가로 궁금한 점 1. useQuery 에서 반환하는 객체중 error 객체는 어떤 존재인지 궁금합니다. 2. useQuery 속성과 QueryClient 속성 모두 throwOnError : true 를 가지고 있던데 어떤 차이점인지 궁금합니다. 답변주시면 정말 감사하겠습니다!!!

안녕하세요 모바일이라 자세하게 답변 못드리는점 양해 부탁드립니다. 구조가 맞는지는 모르겠으나 에러 바운더리는 리액트 쿼리를 실제로 사용하고 있는 컴포넌트를 참조하는 쪽에서 사용해주어야 합니다. 이 경우에는 mainpage 를 실제로 참조해서 쓰고있는 호출부에서 mainpage를 에러 바운더리로 감싸줘야 할 것 같네요. 1. 에러 객체는 서버 에러 리스폰스 객체입니다 2. 훅에서 사용하면 해당 훅에서만 throwOnError 값을 설정하는 것이고, QueryClient에서 사용하면 전역적으로 처리하는 것입니다.

vscode에서 언어를 설치 할 때 오류

대학생이 되어 vscode를 이용해 공부와 코딩으로 하려고 하는데 파이썬과 다른 프로그래밍 언어를 설치 할 때 오류가 뜨고 설치되지 않습니다. 어디다 마땅히 물어 볼 곳이 없어서 지푸라기 잡는 심정으로 질문 드립니다. ㅠㅠ 구글과 마이크로소프트 사이트에서도 검색했지만 나오지 않아서 질문합니다 🥺 혹시나 이유를 아시는분 또는 도움을 주실 수 있으신분은 답변 부탁드립니다 🥺 에러 로그 남깁니다. 2023-02-10 15:07:18.575 [error] Error: Untrusted,Untrusted,Untrusted at vscode-file://vscode-app/c:/Users/user/AppData/Local/Programs/Microsoft%20VS%20Code/resources/app/out/vs/code/electron-browser/sharedProcess/sharedProcessMain.js:88:89578 at Array.reduce (<anonymous>) at E (vscode-file://vscode-app/c:/Users/user/AppData/Local/Programs/Microsoft%20VS%20Code/resources/app/out/vs/code/electron-browser/sharedProcess/sharedProcessMain.js:88:89564) at ne.D (vscode-file://vscode-app/c:/Users/user/AppData/Local/Programs/Microsoft%20VS%20Code/resources/app/out/vs/code/electron-browser/sharedProcess/sharedProcessMain.js:88:80916) at async ne.z (vscode-file://vscode-app/c:/Users/user/AppData/Local/Programs/Microsoft%20VS%20Code/resources/app/out/vs/code/electron-browser/sharedProcess/sharedProcessMain.js:88:78417) at async ne.installFromGallery (vscode-file://vscode-app/c:/Users/user/AppData/Local/Programs/Microsoft%20VS%20Code/resources/app/out/vs/code/electron-browser/sharedProcess/sharedProcessMain.js:88:74855) 2023-02-10 15:07:18.599 [error] Untrusted,Untrusted,Untrusted: Error: Untrusted,Untrusted,Untrusted at vscode-file://vscode-app/c:/Users/user/AppData/Local/Programs/Microsoft%20VS%20Code/resources/app/out/vs/code/electron-browser/sharedProcess/sharedProcessMain.js:88:89578 at Array.reduce (<anonymous>) at E (vscode-file://vscode-app/c:/Users/user/AppData/Local/Programs/Microsoft%20VS%20Code/resources/app/out/vs/code/electron-browser/sharedProcess/sharedProcessMain.js:88:89564) at ne.D (vscode-file://vscode-app/c:/Users/user/AppData/Local/Programs/Microsoft%20VS%20Code/resources/app/out/vs/code/electron-browser/sharedProcess/sharedProcessMain.js:88:80916)

안녕하세요! 에러만 보면 권한 이슈 같은데 혹시 vscode 권한 설정을 확인해보시겠어요? - https://code.visualstudio.com/docs/editor/workspace-trust

공식 홈페이지

caolan.github.io

최신 버전 정보

3.2.6

최신 버전 출시일

2024.11.05

연관 라이브러리

라이브러리 로고Redux라이브러리 로고JQuery라이브러리 로고Lodash라이브러리 로고React라이브러리 로고Vue

의견 보내기