8달 전 · 익명 님의 질문
expo에서 tabs로 동적라우팅 설계할때
지금 expo 사용해서 공부하는 중인데 tabs 컴포넌트 사용해서 바텀네비게이션 구현하고 tabs를 사용해서 동적라우팅 설정하려면 폴더구조를 어떻게 해야하나요? (tabs)폴더로 그룹화 해서 gym, board, search, profile 폴더 만들어준 후에 tabs에 4개 항목 유지하면서 /profile/:userid 경로로 동적라우팅 하고 싶은데 여기에 사진처럼 profile 폴더-> [userId]폴더-> index 파일 설정하면 디바이스의 tabs 항목에 /profile/ [userId]/index 가 같이 나옵니다... tabs에 4개 항목만 유지하면서 동적라우팅 하려면 폴더구조 어떻게 해야하나요 ㅠㅠ
개발자
#expo
#reactnative
답변 0
댓글 0
조회 50
9달 전 · 익명 님의 질문
NavigationContainer 중첩 오류
안녕하세요, RN(Expo)로 React Navigation을 적용하다 오류가 해결되지 않아서 질문드립니다. expo를 통해 다음과 같이 index.js에 React Navigation을 적용했습니다. import { store } from "@/redux/store"; import MainScreen from "./screens/MainScreen"; import { Provider } from "react-redux"; import { NavigationContainer } from "@react-navigation/native"; import { createNativeStackNavigator } from "@react-navigation/native-stack"; import LoginScreen from "./screens/LoginScreen"; export default function HomeScreen() { const Stack = createNativeStackNavigator(); return ( <Provider store={store}> <NavigationContainer> <Stack.Navigator> <Stack.Screen name="Main" component={MainScreen} /> <Stack.Screen name="Login" component={LoginScreen} />{" "} </Stack.Navigator> </NavigationContainer> </Provider> ); } 그러나 다음과 같은 오류가 뜨며 빈화면만 보이더라구요ㅠ Error: Looks like you have nested a 'NavigationContainer' inside another. Normally you need only one container at the root of the app, so this was probably an error. If this was intentional, pass 'independent={true}' explicitly. Note that this will make the child navigators disconnected from the parent and you won't be able to navigate between them. 찾아보니 NavigationContainer가 중첩되었다는 것 같은데, 저는 계속해서 그대로 강의를 따라가고 있었고, 따로 NavigationContainer를 적용한 파일이 존재하지 않습니다 ㅠ 다음 속성을 추가해도 오류가 해결되지 않습니다 ㅠ 아마 어디선가 부모에서 NavigationContainer가 적용된 것 같은데 찾을 수가 없네요 ㅠㅠ independent={true} 조금 더 찾아보니 expo-router랑 충돌이 난 거일 수도 있다는데 정확하게 모르겠네요 ㅠ
개발자
#react-native
#react-navigation
#expo
#navigationcontainer
답변 0
댓글 0
조회 109
10달 전 · 석정도 님의 질문
리액트 네이티브 릴리즈로 배포 시 build.gradle 설정대로 동작 안하는 이유가 뭔지 궁긍합니다.
안녕하세요. 현재 리액트 네이티브로 프로젝트를 진행하고 있습니다. 막바지 단계에 거의 도달해서 이제 배포 준비를 하려고 하는데요, 마지막으로 테스트를 하기 위해 stagingRelease 로 apk 를 만들어서 테스트를 하려고 하니, .env.staging 을 읽지를 못하고 있네요. 이상한건 stagingDebug 로 할 때에는 이런 문제가 없었습니다. 지금 환경변수는 루트 디렉토리에 env 폴더가 있고, 해당 폴더 내에는 3개의 환경변수 파일이 존재합니다. .env.development .env.staging .env.production 이렇게 3개 입니다. project.ext.envConfigFiles = [ productiondebug: "env/.env.production", productionrelease: "env/.env.production", developmentrelease: "env/.env.development", developmentdebug: "env/.env.development", stagingrelease: "env/.env.staging", stagingdebug: "env/.env.staging" ] 위의 코드는 제가 설정한 환경변수 매핑하는 부분입니다. 실제로 stagingrelease 로 빌드 시에 flavor 값이 stagingrelease 로 뜨는 걸 확인했습니다. node_modules 에서 react-native-config 폴더를 찾아서 dotenv.gradle 에서 찍으니까 확인이 가능하더라고요. 제가 궁금한 점은 왜 루트에서 .env 파일만을 읽어서 BuildConfig.java 에서 사용하려고 하는걸까요? .env.staging 을 참조하지 않는 이유가 궁금합니다. 아래는 dotenv.gradle 파일입니다. import java.util.regex.Matcher import java.util.regex.Pattern def getCurrentFlavor() { Gradle gradle = getGradle() def pattern = Pattern.compile("(?:.*:)*[a-z]+([A-Z][A-Za-z0-9]+)") def flavor = "" gradle.getStartParameter().getTaskNames().any { name -> Matcher matcher = pattern.matcher(name) if (matcher.find()) { flavor = matcher.group(1).toLowerCase() return true } } println "Current flavor: $flavor" return flavor } def loadDotEnv(flavor = getCurrentFlavor()) { def envFile = project.hasProperty("defaultEnvFile") ? project.defaultEnvFile : ".env" if (System.env['ENVFILE']) { envFile = System.env['ENVFILE'] } else if (System.getProperty('ENVFILE')) { envFile = System.getProperty('ENVFILE') } else if (project.hasProperty("envConfigFiles")) { project.ext.envConfigFiles.any { pair -> if (flavor.startsWith(pair.key.toLowerCase())) { envFile = pair.value return true } } } println "Reading env from: $envFile" def env = [:] File f = new File("$project.rootDir/../$envFile"); if (!f.exists()) { f = new File("$envFile"); } if (f.exists()) { println "Found env file: $f" f.eachLine { line -> def matcher = (line =~ /^\s*(?:export\s+|)([\w\d\.\-_]+)\s*=\s*['"]?(.*?)?['"]?\s*$/) if (matcher.getCount() == 1 && matcher[0].size() == 3) { env.put(matcher[0][1], matcher[0][2].replace('"', '\\"')) // 각 환경 변수 키-값 쌍 출력 println "Loaded env variable: ${matcher[0][1]} = ${matcher[0][2]}" } } } else { println("**************************") println("*** Missing .env file ****") println("**************************") } project.ext.set("env", env) } loadDotEnv() android { defaultConfig { project.env.each { k, v -> def escaped = v.replaceAll("%","\\\\u0025") buildConfigField "String", k, "\"$v\"" resValue "string", k, "\"$escaped\"" println "Set buildConfigField and resValue: $k = $v" } } } 안드로이드 스튜디오 터미널에서 ./gradlew assembleStagingRelease 명령어를 치게 될 경우, Current flavor: stagingrelease Reading env from: .env.staging ************************** *** Missing .env file **** ************************** 이런 로그가 뜨고 있습니다.
개발자
#react-native
#react-native-config
#다중환경변수
#release
답변 0
댓글 0
조회 66
10달 전 · L cyan 님의 질문
Expo SQLite WHERE 조건 한글 안됨
React Native Expo에서 앱을 개발중에 sql문이 오류가 뜹니다. 코드는 아래와 같습니다. async function SearchName() { console.log("load data"); try { const db = await SQLite.openDatabaseAsync("MountBedge.db"); const data = await db.getAllAsync(`SELECT * FROM HikingData WHERE Name = '가';`); setLoadedData(data); } catch (error) { console.error("Error testing database connection:", error); } } 문제가 되는 부분은 getAllAsync의 WHERE부분입니다. 한글로 검색한 부분을 영어로 변경하면 오류도 뜨지 않고 검색도 잘 됩니다. 한글로 검색 시 뜨는 오류는 아래와 같습니다. Error testing database connection: [Error: Calling the 'prepareAsync' function has failed → Caused by: Error code 1: near "'ㄱ'": syntax error] 혹시 해결할 방법을 아시는 분이 계시나요? 이게 expo에서는 해결이 가능한건지, 아니면 react native cli로 넘어가야 하는건지 모르겠습니다. 추가로 expo에서 sql문으로 데이터를 저장 시 db가 어디에 있는지 알 수 있는 방법이 있다면 알고싶습니다. 영어를 못해 영어로는 검색을 거의 안해봤지만 자료가 너무 없네요...
개발자
#react-navite-expo
#react-native
#expo
#sql
답변 0
댓글 0
조회 51
10달 전 · 성지수 님의 질문
micro repo 세팅하면서 격은 문제(같은 문제 격는 분들 댁글)
이번 프로젝트에서 하나의 레포지토리에서 client, server, admin, common 4가지 패키지를 만들었습니다. client, server, admin은 common을 의존하도록 모노레포로 만들었고, client는 admin을 의존할 수 있게 micro로 만들었습니다. 간단한 패키지 설명: - client: 메뉴 헤더 등 구현, 페이지는 admin을 remote 해서 사용, React로 구현 - admin: 페이지에 나오는 콘텐츠의 전반적인 부분이 컴포넌트로 되어있음, React로 구현 - server: Node.js로 되어있고 실제 Spring 서버에서 준 데이터를 포맷하는 형태 - common: 공통 컴포넌트, 라벨 등 문제1: 다른 프로젝트에서 expose 되어있는 Next.js 프로젝트(scss로 스타일 구현)를 client에서 사용할 때 의존성 관련 오류가 생깁니다. client의 package.json에서 peerDependencies로 next를 설정해줘야 하는지, 양쪽 패키지(다른 프로젝트와 client)에서 Next.js와 React를 share 설정을 해야 되는지 잘 모르겠습니다. 여러 방법으로 시도는 해봤지만 의존성 오류나 Next.js에서 훅을 사용 못하는 오류 때문에 해결하지 못하고 있습니다. 문제2: 빌드 최적화를 위해 트리쉐이킹이나 코드 스플리팅을 해야 합니다. 웹팩에서 아래와 같이 코드 스플리팅을 하면 청크 파일 이름이 겹치기 때문에 filename을 해시값으로 설정해야 합니다. 여기서 문제가 생기는데, micro의 client처럼 remote 하는 부분에서 remote.js, app.js 청크가 필요하기 때문에 이름이 해시값으로 바뀌면 해당 청크를 찾을 수 없습니다. 또한 ModuleFederationPlugin이 빌드 시 자동으로 코드 스플리팅을 해준다는 이야기도 있는데, 이 부분은 정확하지 않습니다. 저와 같은 문제를 격고 있거나 해결하신 분들 같이 나눴으면 합니다.
개발자
#micro
#react
#monorepo
#nextjs
#build
답변 0
댓글 0
조회 34
일 년 전 · 성지수 님의 질문 업데이트
마이크로 프론트 구현(Nextjs, React)
요구사항 마이크로 프론트엔드로 A라는 프로젝트에서 B라는 프로젝트의 컴포넌트를 사용하고 싶다 프로젝트 설명 ModuleFederationPlugin 사용해서 expose remote 설정 A 프로젝트 (remote) : react, styled-component 사용 B 프로젝트 (expose) : nextjs, scss 사용 첫번째 오류 styled 이 달라서 nextjs 에서 노드가 불러와지지 않는 것 해결 : <noscript id="**next_css__DO_NOT_USE**"></noscript> → 두번째 오류 발생 오류 내용 Cannot read properties of null (reading 'parentNode') TypeError: Cannot read properties of null (reading 'parentNode') at options.insert (webpack- 두번째 오류 Nextjs 에서 expose 할 때 Page 컴포넌트에 있는 useState를 사용 못한다고함 해결 : peerDependencies 로 nextjs 추가 → 오류동일 오류 내용 TypeError: Cannot read properties of null (reading 'useState') at useState (react.development.js:1623:21) at Page (index.js:8:40) react-dom.development.js:18704 The above error occurred in the <Page> component: 참고 : https://dev.to/omher/building-react-app-with-module-federation-and-nextjsreact-1pkh 두번째 오류를 해결해야 되는데 가능한 방법인지 모르겠습니다. 아시는 분은 댁글 남겨주세요~(코드상에 보안상 문제되는 부분은 a b 로 바꿨습니다.
개발자
#micro-frontend-architecture
#react
#next.js
#modulefederationplugin
답변 0
댓글 0
조회 288
일 년 전 · 삭제된 사용자 님의 댓글 업데이트
안녕하세요.. 정말 이것저것 다 해봤는데 안되네요 ㅠ
안녕하세요. 리액트와 리액트 쿼리를 이용해 프로젝트를 진행 중 입니다. 저는 일단. src/hooks/useProduct.jsx 라는 커스텀 훅 을 만들었습니다. 제 계획은 1. 맨 처음 최상단 Home.jsx 에서 useProduct 라는 커스텀 훅 호출 2. 자식컴포넌트에 data를 전달 3. Search.jsx에서 받은 filter값으로 커스텀 훅 안의 query 재실행 4. 바뀐 상태는 Home.jsx 가 다시 받고 자식 컴포넌트에게 전달. 1~3까지는 콘솔찍어가면서 잘 되는데 4.는 되지 않습니다. (쿼리 데이터가 바뀌어도 4이 재 실행이 안됨..) ㅠㅠㅠㅠㅠㅠㅠ 쿼리 옵션도 줘보고 전역 상태도 만들어보고 이것저것 다 해봤는데 ㅠㅠ 혹시 아시는분 계신가요..? 어떠한 답변도 정말 감사히 받겠습니다 간략 코드첨부) Home.jsx const Home = ()=>{ const { data, error, isLoading } = useProduct(); return ( <Search /> <List data={data?.product} /> ); }; export default Home; Search.jsx const Search = () => { ```일부코드생략``` const { updateQuery } = useProduct (); const handleSubmit = () => { const searchData = { productId }; updateQuery(productId); }; } return( ```일부코드생략``` <button onClick={handleSubmit}> 조회 </button> ) } export default Search; useProduct.jsx const useProduct = () => { const [queryData, setQueryData] = useState(); const { data, error, isLoading } = useQuery({ queryKey: ["product", queryData], queryFn: () => fetchProduct(queryData), }); const updateFilters = (queryData) => { setQueryData(() => (queryData); }; return { data, error, isLoading, updateQuery , }; export default useProduct ;
개발자
#react
#react-query
#react-query-v5
답변 3
댓글 6
조회 116
일 년 전 · 익명 님의 질문 업데이트
react-query,
안녕하세요. 리액트쿼리 최신v5를 사용하면서 어려움에 처해 글을 남기게 되었습니다. 제가 만든 코드는 아래와 같습니다. Home.jsx (맨처음 데이터를 받아서 List에 뿌려주는 역할) const { data, error, isLoading } = useFilteredApartmentData(); console.log('home data',data) <List data={data.speechCommands} /> Search.jsx (사용자 검색) const { updateFilters } = useFilteredApartmentData(); //커스텀훅 const handleSubmit = (filter) => { updateFilters(filter); }; useFilteredApartmentData .jsx (훅) const useFilteredApartmentData = () => { const [filters, setFilters] = useState({ skip: 0, take: 15 }); const { data, error, isLoading } = useQuery({ queryKey: ["apartments", filters], queryFn: () => fetchFilteredApartmentData(filters), placeholderData: keepPreviousData, enabled: !!filters, }); console.log("훅안에서 새로운데이터", data); const updateFilters = (newFilters) => { console.log(newFilters); setFilters((prevFilters) => ({ ...prevFilters, ...newFilters, })); }; return { data, error, isLoading, updateFilters, }; }; export default useFilteredApartmentData; 저의 계획은 search.jsx에서 사용자의 검색을 받으면 훅의 updateFilters 를 실행시키고 useState가 바뀌니 useQuery의 재 시작과 함께 새로운 데이터를 받아 List에서 새로운 데이터를 뿌리는 것이었습니다. 그런데 console.log("훅안에서 새로운데이터", data); 이 부분도 새로운 데이터로 잘 찍히는데 문제는 Home.jsx 에서 console.log('home data',data) 이부분은 안찍히네요 결과적으로, 리스트의 변동이 없습니다. 혹시 아시는분 답변주시면 정말 감사하겠습니다 ㅠㅠ
개발자
#react
#react-query
답변 0
댓글 0
조회 77
일 년 전 · 포크코딩 님의 새로운 댓글
리액트쿼리 데이터 리패칭 이렇게 하는거 아닌가요?
home.jsx const { data, error, isLoading } = useFilteredApartmentData(); <List data={data.result} /> 훅.jsx const useFilteredApartmentData = () => { const queryClient = useQueryClient(); const [filters, setFilters] = useState({ skip: 0, take: 15 }); const { data, error, isLoading } = useQuery({ queryKey: ["aaa", filters], queryFn: () => fetchFilteredApartmentData(filters), placeholderData: keepPreviousData, enabled: !!filters, }); const mutation = useMutation({ mutationFn: (filter) => { fetchFilteredApartmentData(filter); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["aaa", filters] }); }, }); const updateFilters = (newFilters) => { console.log(newFilters); setFilters(newFilters); mutation.mutate(newFilters); }; return { data, error, isLoading, updateFilters, }; }; export default useFilteredApartmentData; 여기서 처음에 데이터 패칭은 잘 이루어 지는데 fillter가 바뀌면 훅의 updateFilters 가 동작하여 새로운 데이터를 list에 다시 뿌리려고하는데 화면에 변화가 없습니다 ㅜㅜ 이렇게 하는거 아닌가요??
개발자
#react
#react-query
답변 1
댓글 2
조회 68
일 년 전 · 익명 님의 질문
UI 디자인 피그마에서 안드로이드앱 Export
안녕하세요. 대학교 3학년 학생입니다. 이번 프로젝트에서 제가 ui/ux 디자인을 맡았고 안드로이드 앱 디자인을 위해 피그마를 활용하려 합니다. 그런데 피그마에서 앱 디자인과 프로토타입 구성을 마친 후, 안드로이드 스튜디오로 코드를 변환할 때 xml로 수동으로 일일이 안드로이드 스튜디오로 붙여넣어야하나요? 아니면 plugin으로 피그마 디자인을 코드(java, xml) 로 바로 변환할 수 있나요? 보편적으로 피그마에서 디자인을 마친 후 어떻게 export하는지 모르겠습니다ㅜㅜ
디자이너
#피그마
#figma
#안드로이드
#안드로이드스튜디오
#uiux
답변 0
댓글 0
조회 624
일 년 전 · 김지엽 님의 새로운 답변
웹 개발자 RN , 플러터 질문드립니다
서버 개발자입니다. 취미 삼아 사이드프로젝트를 진행하면 항상 앱 프론트 쪽에서 문제가 발생해서( 기간, 퀄리티, 배포, 도망, 유기 등등) 앱 개발자들 다 내보내고 2명에서 플러터나 RN 고민 중에 있습니다. 저는 리액트 넥스트를 어느 정도 다룰 줄 알기 때문에 RN EXPO 생각 중입니다. 네이티브 앱 개발하시는 분들 중에 최근 RN EXPO를 사용하신분들 의견을 들어보면 react native cli 만큼 요즘 기능도 좋다. DX가 플러터 수준이다 배포가 너무 좋다라는 의견이라 저는 무조건 RN 생각 중이지만,, 다른 한명의 리액트 학습곡선 + 초보자가 개발하기 편한 여론이 flutter가 많아서 고민 중입니다. 취업 , 커리어 이런 고민은 하지 않고 그냥 개발, 관리 유지보수 적인 측면에서 어떤 것이 더 괜찮은 선택인지 하다보면 분명이 고도화, 서드파티, 디자인 등등에서 막힐텐데 주변에 이렇게 상세하게 상황 설명을 할 수도 없고 너무 단편적이고 편향적인 의견이 많고 어떤 플랫폼이 더 괜찮은지 아직 제대로 해보지 않아서 경험있는 분들에게 질문드립니다.
개발자
#flutter
#react-native
답변 2
댓글 0
조회 255
일 년 전 · 익명 님의 새로운 댓글
타입스크립트 타입지정
리액트 쿼리로 OptimisticUpdate 를 구현했는데 onError 에서 context 타입 지정을 어떻게 해야할지 모르겠습니다 ㅠㅠ context : 타입 하면 오류나고, data : 타입 = context 해도 오류나고 as 를 쓰면 해결되긴 하는데 더 좋은 방법 없을까요? ㅠㅠㅠ 'use client'; import { useState } from 'react'; import { toast } from 'react-toastify'; import { usePostLikeCount } from '@/hooks'; interface LikeContextType { previousLikeCount: number; previousIsLike: boolean; } export const useOptimisticLike = ( boardId: number, initialLikeCount: number, initialIsLike: boolean, refetch: () => void ) => { const [optimisticLikeCount, setOptimisticLikeCount] = useState(initialLikeCount); const [optimisticIsLike, setOptimisticIsLike] = useState(initialIsLike); const { mutate: postMutate } = usePostLikeCount(boardId, { onMutate: async (): Promise<LikeContextType> => { setOptimisticLikeCount((prev) => optimisticIsLike ? prev - 1 : prev + 1 ); setOptimisticIsLike((prev) => !prev); return { previousLikeCount: optimisticLikeCount, previousIsLike: optimisticIsLike, }; }, onError: (err, variables, context) => { const data: LikeContextType = context; if (data) { setOptimisticLikeCount(data.previousLikeCount); setOptimisticIsLike(data.previousIsLike); } toast.error('좋아요 업데이트에 실패했습니다.'); }, onSuccess: () => { refetch(); }, }); const uploadLike = () => { postMutate(); }; return { optimisticLikeCount, optimisticIsLike, uploadLike, }; };
개발자
#react-query
#typescript
답변 1
댓글 1
조회 60
일 년 전 · 백승훈 님의 새로운 답변
리액트 네이티브 안드로이드 앱 개발 백엔드 질문
현재 react native expo를 이용해 안드로이드 앱을 개발하려고 하는 학생입니다. 백엔드 공부를 하려하는데 아는 것이 없어 어떤 것을 사용하는지 조언을 얻고 싶습니다. 현재 제가 개발하려는 앱은 정보를 입력해 카드를 생성 후 블루투스나 스페이스 입장으로 공유할 예정입니다. 소셜로그인과 이메일 회원가입 또한 이루어질 예정입니다. 스프링부트, 디장고, 파이어베이스 등 추천해주시면 정말 감사하겠습니다!
개발자
#react-native
#expo
#android
#app
#backend
답변 2
댓글 0
조회 177
일 년 전 · 털먹는토끼 님의 댓글 업데이트
리액트 쿼리 에러 핸들링 이슈
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 를 가지고 있던데 어떤 차이점인지 궁금합니다. 답변주시면 정말 감사하겠습니다!!!
개발자
#react
#react-query
#error-handler
#error-boundary
답변 1
댓글 1
조회 215
일 년 전 · 백승훈 님의 답변 업데이트
Recoil Atom Effect 적용 기: 팀 내 설득 및 구현 조언
안녕하세요!! 현재 진행 중인 프로젝트에서 회원가입 시 필요한 정보를 입력하는 중 새로고침 시 session 및 localstorage를 이용하여 상태유지를 하려고하는데 recoil과 관련하여 atom effect를 사용하면 우아하게 처리할 수 있음을 알았습니다. 따라서, 각 atom에 effect를 하나하나 추가하는 방법을 생각했는데 동일한 logic을 행하는 코드의 양이 방대해지고 localstorage에 각 atom에 해당하는 key-value로 저장되므로 가독성 측면에서 좋지 않다고 판단하여 아래와 같은 과정을 생각했습니다. 각 atom을 하나로 묶어 객체로 관리하자. 객체로 관리하게 되면 불필요한 re-rendering이 촉발되므로 객체로 선언한 atom의 각 property에 접근 및 수정을 위한 selector를 정의하자. 객체에 내의 property에 1대1로 selector를 정의하면 객체로 묶기 전 atom의 갯수만큼 selector를 선언해주어야 하므로 selectorFamily를 사용하자. 이것저것 찾아보면서 1 → 2 → 3 단계로 생각을 정리했습니다. 아래는 현재 사용되는 atom입니다. <ATOM> // signup.store.ts 👇 회원가입에 대한 user state들 - SignUpProfileTypeAtom - SignUpProfileRentalTypeAtom - SignUpProfileRegionsAtom - SignUpProfileDepositPriceAtom - SignUpProfileTermAtom - SignUpProfileMonthlyPriceAtom - SignUpProfileSmokingAtom - SignUpProfilePetAtom - SignUpProfileAppealsAtom - SignUpProfileGenderAtom - SignUpProfileMatesNumberAtom - SignUpProfileMateAppealsAtom // 👇 위의 atom들을 한 번에 access 및 update - SignUpProfileSelector 하지만, 다른 팀원이 저렇게 atom을 구성한 상황 제 생각을 그대로 적용하고자하면 팀원의 코드를 마음대로 바꾸는 거 같아서 조심스럽습니다. 협업함에 있어 설득도 하나의 중요한 스킬임을 갈수록 깨닫게 됩니다.(다들 어떻게 설득하시나요?) 팀원이 기존의 코드는 안 바꿨으면 좋겠다 하면 각 atom에 effect를 추가하는 것이 맞겠죠???? 현재 현업에 계신 분들은 이러한 상황에서 어떻게 설득하며 어떻게 하는 것이 좋을까 자문을 구하고 싶어서 글 올려봅니다!!🥲🥲 짧지 않은 글이지만 읽어주셔서 감사하고 많은 의견 주시면 감사하겠습니다!!😄😄😄 ```typescript import { SignUpType } from '@/types/signUp.type'; // ? type 집 유형 0: 원룸/오피스텔, 1: 빌라/연립, 2: 아파트, 3: 단독주택 @number export const SignUpProfileTypeAtom = atom<SignUpType['type']>({ key: 'signUpProfileTypeAtom', default: undefined, }); // ? rental_type 집 대여 유형 0: 월세, 1: 전세, 2: 반 전세 @number export const SignUpProfileRentalTypeAtom = atom<SignUpType['rental_type']>({ key: 'signUpProfileRentalTypeAtom', default: undefined, }); // ? regions 유저가 찾는 지역 >도시 (region) + 구(district) 형태의 배열 @string[] export const SignUpProfileRegionsAtom = atom<SignUpType['regions']>({ key: 'signUpProfileRegionsAtom', default: [], }); // ? deposit_price 보증금 (전세 혹은 월세) 범위 [최소 금액, 최대 금액] (0만원~10000만원) @[number, number] export const SignUpProfileDepositPriceAtom = atom<SignUpType['deposit_price']>({ key: 'signUpProfileDepositPriceAtom', default: [0, 10000], }); // ? term 유저가 살 기간 [최소기간, 최대 기간] (0 ~ 24)범위 @[number, number] export const SignUpProfileTermAtom = atom<SignUpType['term']>({ key: 'signUpProfileTermAtom', default: [0, 24], }); // ? monthly_rental_price 월세 [최소 금액, 최대 금액] (0만원, 500만원) @[number, number] export const SignUpProfileMonthlyPriceAtom = atom<SignUpType['monthly_price']>({ key: 'signUpProfileMonthlyPriceAtom', default: [0, 500], }); // ? smoking 흡연 여부 @boolean export const SignUpProfileSmokingAtom = atom<SignUpType['smoking']>({ key: 'signUpProfileSmokingAtom', default: undefined, }); // ? pet 펫 여부 0: 상관없음, 1: 좋음, 2: 싫음 @number export const SignUpProfilePetAtom = atom<SignUpType['pet']>({ key: 'signUpProfilePetAtom', default: undefined, }); // ? appeals 유저의 어필할 매력(배열형태) @string[] export const SignUpProfileAppealsAtom = atom<SignUpType['appeals']>({ key: 'signUpProfileAppealsAtom', default: [], }); // ? gender 상대방의 성별 0: 상관없음, 1: 남성, 2: 여성 @number export const SignUpProfileGenderAtom = atom<SignUpType['gender']>({ key: 'signUpProfileGenderAtom', default: undefined, }); // ? mates_number 인원수 0: 상관없음, 1: 1명, 2: 2명, 3: 3명이상 @number export const SignUpProfileMatesNumberAtom = atom<SignUpType['mates_number']>({ key: 'signUpProfileMateNumberAtom', default: undefined, }); // ? mate_appeals 유저가 원하는 상대방의 매력 (배열형태) @string[] export const SignUpProfileMateAppealsAtom = atom<SignUpType['mate_appeals']>({ key: 'signUpProfileMateAppealsAtom', default: [], }); ```
개발자
#프론트
#협업
#recoil
답변 1
댓글 0
조회 92
일 년 전 · 익명 님의 질문
Expo vs bare ReactNative
리액트네이티브로 개발할 때 expo와 bare 중 어떤걸 사용하시나요?
투표
개발자
#react
#react-native
#reactnative
#expo
답변 0
댓글 0
조회 69
일 년 전 · Ed 님의 새로운 답변
사용자 등급에 따라 다른 화면을 보여주고 싶어요.
Next.js 14버전을 사용하고 있습니다. 홈페이지에 접속했을 때, 사용자의 로그인 상태 여부에 따라 각기 다른 컴포넌트를 보여주고 싶습니다. const Main = () => { const isLogin = useRecoilValue(loginStatus); const user = useRecoilValue(userAtom); return ( <> <AuthWrapper> {isLogin && user ? <Login/> : <Logout />} </AuthWrapper> </> ) }; export default Main; isLogin과 user는 로그인 여부와 회원 정보에 대한 전역 변수입니다. isLogin의 default값은 false이고, user의 경우 isLogin이 true일 때만 존재합니다. (로그인 상태일 때 해당 유저 정보를 api로 호출) 그리고 <AuthWrapper>를 통해 해당 전역 변수들을 업데이트 해줍니다. 제가 원하는 건 최초 페이지 접속 시에 AuthWrapper를 통해 state값을 초기화해주고, 이에 알맞게 컴포넌트가 렌더링 되는 것입니다. 하지만 isLogin의 default값이 false이기에 로그인 상태일 경우, 순간적으로 Logout컴포넌트가 출력되었다가 AuthWrapper에서 검증 후 state값이 변경되면 Login컴포넌트가 출력됩니다. 이 순간적인 깜빡임을 없애고 바로 동작할 수 있게 하는 방법이 있을까요? +) 추가로.. 서버 사이드에서 처리하기에는 AuthWrapper 내부에서 storage값을 사용하거나 useEffect등을 사용하기에 불가능했습니다.
개발자
#next.js
#react
답변 4
댓글 0
조회 106
일 년 전 · 허니 님의 새로운 답변
리액트 로그인질문..
react + 파이어베이스만 써오다가 react + express 조합을 오랜만에 사용중인데 긴가민가한점이있어서 질문드립니다 ㅠㅠ import axios from 'axios'; const instance = axios.create({ baseURL: process.env.REACT_APP_API_BASE_URL, timeout: 2500, headers: { 'Content-Type': 'application/json', withCredential: true, }, }); instance.interceptors.request.use( (config) => { const token = localStorage.getItem('token'); if (token) { config.headers['Authorization'] = token; } else { delete config.headers['Authorization']; } return config; }, (error) => { return Promise.reject(error); } ); export default instance; 이렇게 인터셉터를주어서, 요청할 때마다 토큰을 전달하고있습니다. 그리고 프라이빗 라우터 + 유저정보 인증 훅을 사용해서 로그인사용자만 접근가능하게 페이지를 설정해줬습니다. 근데 질문 1. 네트워크탭 Request Headers 에서 Authorization을 확인해보면 토큰정보가 그대로 노출되고있는데요 원래 이렇게되나요? 질문 2. Bearer + token 이렇게 보내는 경우는 포스트맨이나 이런걸로 테스트할때만 Bearer 을 붙여서 보내주면될까요? 질문 3. 검색 키워드가 생각이안나서 질문으로 올립니다. 아주 옛날에는 (4년전) App.tsx에서 if(localstorage.token){ setAuthToekn(token); } 이런식으로 하고, setAuthToken함수는 import axios from 'axios'; const setAuthToken = (token) => { if (token) { axios.defaults.headers.common['x-auth-token'] = token; } else { delete axios.defaults.headers.common['x-auth-token']; } }; export default setAuthToken; 이런식으로 되어있었는데요, 요즘은 제가 짠 코드처럼 axios.인터셉터 식으로 하는게 맞나요? 질문 4. 그럼 요즘도 회원가입/로그인시 로컬스토리지에 유저 정보 (닉네임 이름 이메일, 토큰정보)만 저장해두고 로그인하면, 로그인버튼이 회원 닉네임으로 변하게 해준다던가.. 이런식으로 분기처리를 하나요? ( 저는 이렇게하고있어서요.. 로딩처리를 줄수도있겠지만 깜빡거리는게 싫고, 또 로컬스토리지로안하면 로그인버튼으로 잠깐바꼇다가 회원닉네임이 표시되더라구요) 질문5. (질문4와 이어집니다.) 만약 질문4처럼하면 사용자가 사이트에 계속 로그인중인데, 이 토큰이 끝났는지 판단하려는 코드를 따로 작성해줘야할까요? 예를들면, App.tsx에 서버 api/auth같은거에 요청보내는 로직을 작성해서, 토큰만보내서 유효한 토큰인지 아닌지, 유효하지않은토큰이면 에러를 리턴시켜준다던가, 리프레쉬토큰을 발급시켜서 연장시켜준다던가 이런식으로하면될까요? 마지막으로 질문이 좀 많고 중구난방인데 죄송스럽고 조심스럽네요..
개발자
#react
#login
#register
#local-storage
#jwt
답변 1
댓글 0
조회 116
일 년 전 · 익명 님의 새로운 댓글
타입스크립트 'value' is possibly 'null' 에러 옵셔널체이닝으로 해결안되는 이슈
import DateRangePicker from "@wojtekmaj/react-daterange-picker"; import { useDispatch } from "react-redux"; import { dateFetch } from "components/feature/FetchSlice"; import styled from "styled-components"; type ValuePiece = Date | null; type Value = ValuePiece | [ValuePiece, ValuePiece]; export default function CustomCalendar() { const dispatch = useDispatch(); const [value, onChange] = useState<Value>([new Date(), new Date()]); return ( <CalendarBox> <Calendar>조회 기간</Calendar> <StlyedDateRangePicker onChange={onChange} value={value} onCalendarClose={() => { dispatch( dateFetch({ startDate: value[0]?.toISOString(), endDate: value[1]?.toISOString(), }) ); console.log(value); }} /> </CalendarBox> ); } <StlyedDateRangePicker>는 styled component로 만든 DateRangePicker 라이브러리 컴포넌트입니다. DateRangePicker 에서 날짜 2개를 선택하면 value라는 배열에 Date 객체 2개가 들어갑니다. 그리고 onCalendarClose 함수가 동작하면서 redux로 만들어놓은 startDate, endDate 객체에 각각 date를 toISOString() 처리한 값이 할당되는 로직입니다. 날짜를 선택하기 전에는 value={value}의 value 배열요소인 Date객체 값이 null 값이니까 type ValuePiece = Date | null; 타입지정을 해줬습니다. startDate: value[0]?.toISOString(), endDate: value[1]?.toISOString(), 근데 위 코드의 value[0], value[1] 에러가 나더라구요. 'value' is possibly 'null'.ts(18047) Element implicitly has an 'any' type because expression of type '0' can't be used to index type 'Date | [ValuePiece, ValuePiece]'. Property '0' does not exist on type 'Date | [ValuePiece, ValuePiece]'. null 값일 수도 있다길래 옵셔널체이닝을 줬는데 여전히 에러가 발생합니다.. 해결방법을 도무지 모르겠네요.. 도와주시면 진심으로 감사하겠습니다ㅠㅠㅠ
개발자
#react
#typescript
#optional-chaining
답변 3
댓글 3
조회 271
일 년 전 · 유길종 님의 답변 업데이트
비지니스로직 분리 질문드려요!
사이드 프로젝트를 완료했고 비지니스로직을 분리하고 싶습니다 hooks라는 폴더를 만들어 action과 api로 나눠 action에는 파이어베이스를 사용하기에 여러가지 행동적인 함수 ( 좋아요 기능, 글쓰기 기능, 조회수 등등) Api에는 탄스택쿼리를 사용하기에 해당되는 쿼리 로직들을 나눌려고 합니다. 훅을 사용하는것처럼 하나의 파일에 하나의 로직을 담아야하나요? 아니면 비슷한것끼리 파일에 넣고 export로 여러개를 두어야하나요? 제 스타일대로 하면 될꺼 같지만 현업에서는 어떤식으로 비지니스 로직을 분리하고 관리하는지 궁금해요 TMI. 로그인 페이지 하나 적용해봤는데 코드가 완전 깔끔하고 이컴포넌트에서 무엇을 하는지 딱 보여서 좋네요!!
개발자
#react
답변 1
댓글 1
조회 444
일 년 전 · 익명 님의 새로운 댓글
Next.js에서 page.js
안녕하세요. Next.js를 공부하던 중 궁금한점이 생겨 질문드립니다 ! 제가 app/page.js 파일에 사용자가 로그인했다면 메인화면 컴포넌트를 보여주고, 로그인하지 않았다면 로그인 컴포넌트를 보여주도록 작성해두었습니다. 그런데 궁금한 점이 로그인을 했는지 유무를 getserversession을 통해 세션을 확인해서 판단합니다. 그런데 이때 비동기처리를 위해 await를 붙여줘야하는데, 그렇다면 page.js의 Home() 자체에 async를 붙여주어야합니다. 그래서 해당 방법을 사용해 제가 생각한 로직은 구현했습니다. 그런데 궁금한 점이 page.js에서 export default async function Home() 이런식으로 작성해도 되나요? 제가 page.js의 역할을 정확히 이해하지 못한 느낌이 들어 질문드립니다. (챗 지피티에게 물어보니 13버전 이전의 내용만 알고 있는 듯합니다. 또한 컴포넌트 자체에 async를 붙이면 안된다고 답변이 옵니다 !)
개발자
#next.js
답변 1
댓글 1
추천해요 1
조회 493
일 년 전 · 익명 님의 질문
Next.js 14 서버액션을 사용한 폼 데이터 처리 중 질문입니다.
next.js 14의 서버액션을 사용해서 사용자로부터 form으로 데이터를 입력받아 DB에 저장하고 첨부파일을 서버에 업로드하는 모듈을 개발중입니다. 문제점은, 첨부파일을 input으로 입력받아 서버액션 함수로 formData로 넘겨주는데, 서버액션 함수에서 첨부파일의 파일명에 한글이 포함됐을 경우 파일명의 한글이 유니코드로 보이는 문자열로 찍히고 있습니다. // Form.jsx "use client"; // [other code] export default function Form() { const [formState, formAction] = useFormState(inquiryAction, { success: undefined, message: "", }); const { register, handleSubmit, reset, formState: { errors }, } = useForm(); const onSubmit = (data) => { const formData = new FormData(); const jsonData = JSON.stringify(data); formData.append("jsonData", jsonData); data.attachment[0] && formData.append("attachment", data.attachment[0]); formAction(formData); }; return ( <form action={handleSubmit(onSubmit)}> // [other code] <FileInput label="첨부파일" {...register("attachment")} error={errors} resetTrigger={resetTrigger} /> // [other code] </form> ); } // inquiryAction.js "use server"; import { connectDB } from "./connectDB"; export async function inquiryAction(prevState, formData) { const fields = JSON.parse(formData.get("jsonData")); const attachment = formData.get("attachment"); console.log(attachment); } Form 컴포넌트는 클라이언트 컴포넌트이고, react-hook-form과 next14의 서버액션을 사용하기 위해, form의 action에는 react-hook-form의 handleSubmit함수에 onSubmit 함수를 인자로 전달합니다. onSumbit 함수에서 서버액션 함수를 가져와 처리를 하고 있습니다. 그런데 여기서 서버함수쪽에서 첨부파일을 받을 때 한글 파일명이 다 깨지고 있네요... 기존에 api route와 fetch api를 사용했을 땐 문제가 없었는데.. 제가 놓치고 있는 부분이 있을까요?
개발자
#next.js
#server-action
답변 0
댓글 0
조회 535
일 년 전 · changwoo 님의 새로운 답변
vite에 관하여 질문드립니다.
프로덕션에 vite를 사용하여 개발환경을 구성하려고 공부 중인데, 궁금한 점이 생겼으나 정보가 파편화되어있어 정확한 이해가 어려워 질문 올립니다! 제가 vite 공식 가이드와 구글링하면서 이해한 바로는 “기존 브라우저 환경에서는 모듈화된 코드들을 브라우저가 읽을 수 없어 webpack과 같은 번들러를 이용해 하나의 파일로 합치는 과정을 거쳤고, 이것이 일반적인 번들러의 역할이었으나 브라우저가 ESM을 지원하면서 import, export를 별도의 도구 없이 브라우저 자체에서 해석할 수 있고 처리할 수 있게 되었으며 vite는 이 점을 활용하여 번들링 과정 없이 바로 실행하여 파일이 import되어 필요할 때 불러오는 방식을 사용한다. “ 라고 이해했는데 혹시 맞을까요? 추가로 vite의 공식 가이드에는 “프로덕션에서 번들 되지 않은 ESM을 가져오는 것은 중첩된 import로 인한 추가 네트워크 통신으로 인해 여전히 비효율적입니다” 라고 나와있는것을 보았을때, 위에 적힌 번들링없이 실행하는 것은 개발모드에만 사용되며, 프로덕션에는 여전히 webpack과같이 번들링을 진행하며 webpack대신 Rollup을 사용한다는 점만 다르다고 이해하였는데 이부분에서 틀린내용이 있을까요? 만약 그렇다면 vite가 강조하는 장점이 프로덕션에는 크게 작용하지않는다고 느껴져서요. 질문 자체가 잘못되었거나 ,틀린내용이 있다면 편하게 지적주시고 알려주시면 감사드리겠습니다!
개발자
#vite
답변 1
댓글 0
조회 354
일 년 전 · 남 재민 님의 새로운 답변
react native 코드 수정 후 expo에 반영이 안 됩니다
react native에서 코드를 수정하고 저장하면 즉시 expo에 반영이 됐었는데, 갑자기 안 되고 있습니다.. 해결 방법 아시는 분..?
개발자
#react-native
#react
#app
#expo
답변 1
댓글 0
조회 204
일 년 전 · 익명 님의 새로운 댓글
리액트 context api
* ContextProvider 정의* const LocationContext = createContext() export const LocationProvider = ({children})=> return ( <LocationContext.Provider value={contextValue}> {children} </LocationContext.Provider> ); }; --------------------------- asd.jsx <ContextProvider> <A/> </ContextProvider> ---------------------- qwe.jsx <ContextProvider> <B/> </ContextProvider> ---------------------------------- 이런식으로 작성했을때 A컴포넌트에서 컨택스트 내부 값을 변경하면 B컴포넌트가 재 랜더링 되나요? (되는줄 알았는데 안돼서요..ㅠ)
개발자
#react
#context
답변 1
댓글 1
조회 52
일 년 전 · 익명 님의 질문
nextjs에서 랜더링 시점 바꾸기
안녕하세요! nextjs 프로젝트 진행중에 궁금증이 생겼습니다. 현재 Sidebar 컴포넌트에서 카카오맵이 불러와져야 작업을 할 수 있는 상태입니다. 카카오 맵은 children 에서 랜더링되기 때문에 아래와 같이 코드작성시, Sidebar 랜더링 시점에 kakao is not defined 라는 오류가 뜹니다. 혹시 Sidebar를 좀 늦게 랜더링 할 수 있을까요? export default function RootLayout({ children, }: { children: React.ReactNode; }) { return ( <html lang="en"> <body className={inter.className}> <div id="login-modal" /> <section className="flex h-screen"> <nav className=" h-full bg-slate-100"> <Sidebar /> </nav> {children} </section> </body> <Script src={`//dapi.kakao.com/v2/maps/sdk.js?appkey=${APIKEY}&libraries=services,clusterer`} strategy="beforeInteractive" /> </html> ); }
개발자
#nextjs
#reactjs
답변 0
댓글 0
조회 60
일 년 전 · 익명 님의 새로운 댓글
리액트 타입스크립트 obj[key] 에러
타입스크립트 이제 막 적용해보는 초보입니다.. 코드 내 monitorMenu[type].container 에서 [type]에 에러가 뜨는데 타입 지정이 잘못 된 건지 찾아봐도 원인을 모르겠습니다ㅜㅜ 물어볼 곳이 없어 질문합니다,,! 도움 부탁드립니다...ㅠㅠ // code import React, { useEffect, useState } from 'react'; import { useNavigate, useParams } from 'react-router-dom'; import DashboardContainer from '../containers/DashboardContainer'; import IntegratedContainer from '../containers/IntegratedContainer'; interface IMonitorMenu { [key: string]: { container: string | JSX.Element; }; } const Monitor = () => { const user: any = []; const { type } = useParams<{ type?: string }>(); const navigate = useNavigate(); const [menu, setMenu] = useState('integrated'); const onClickMenu = (name: string) => { navigate(`/monitor/${name}`); }; const monitorMenu: IMonitorMenu = { integrated: { container: <IntegratedContainer /> }, dashboard: { container: <DashboardContainer /> }, }; return ( <div> ... <div>{monitorMenu[type].container}</div> </div> ); }; export default Monitor; // error ERROR in src/pages/Monitor.tsx:37:25 TS2538: Type 'undefined' cannot be used as an index type.
개발자
#react
#typescript
답변 1
댓글 1
조회 97
일 년 전 · 김언지 님의 새로운 댓글
리액트 네이티브 사용 시 expo
expo가 좋을까요 ? 아니면 Reactive Native로 하면 좋을까요??
개발자
#reactnative
답변 1
댓글 1
추천해요 1
조회 139
일 년 전 · 조용구 님의 답변 업데이트
타입스크립트에서 중첩객체에 대한 type of & key of 사용에 대해 질문 있습니다!
color와 같은 스타일 theme값을 객체로 만들어 놓고, type of key of를 통해 객체의 키값으로 만들고 있습니다! 해당 tpye을 만드는 목적은 컴포넌트에 color prop을 추가하려고 합니다! 단순한 객체는 아래 예시처럼 처리하면 객체의 키값을 가져와서 type으로 만들 수 있는걸로 알고 있습니다. export const colors = { Gray000: '#F5F5F5', Gray50: '#F2F2F2', Red100: '#FFECEF', Red200: '#F47F88', Blue: '#005E9E', }; export type colorType = keyof typeof colors; 하지만 아래 예시와 같은 중첩 객체문에서는 해당 키값을 어떻게 빼내야할지 고민입니다. export const colors = { page1: { Gray000: '#F5F5F5', Gray50: '#F2F2F2', } , page2: { Red000: '#F5F5F5', Red50: '#F2F2F2', } , page3: { Blue000: '#F5F5F5', Blue50: '#F2F2F2', } }; 아래 코드처럼 이런 식으로 따로 따로 처리해야하는걸까요? type page1Type = keyof typeof colors.page1; type page2Type = keyof typeof colors.page2; type page3Type = keyof typeof colors.page3; export type colorType = page1Type | page2Type | page3Type
개발자
#타입스크립트
#typescript
#react
#typeof
#keyof
답변 1
댓글 0
조회 368
일 년 전 · 권수경 님의 질문
[node.js] 세션을 이용한 로그인 구현 중 브라우저 쿠키의 maxAge 초기화 안 되는 문제 발생
Node.js(v18.17.0) + TypeScript로 개발을 진행하고 있습니다. express 로 서버를 구축했고, express-session , session-file-store 라이브러리를 사용해서 로그인 기능을 구현했습니다. 제가 원하는 것은 세션 만료 시간을 연장하는 기능을 만드는 것인데... 서버에서는 세션 쿠키 만료 시간이 재설정(초기화)가 되는데 브라우저에 저장된 쿠키 만료 시간은 그대로인 상태라 연장이 되지 않습니다. 처음 제 코드는 이렇습니다. ```ts export const extendSession = async (req: Request, res: Response) => { req.session.resetMaxAge(); res.json({ success: true, message: '세션 연장 성공', expiredTime: req.session.cookie.expires.getTime(), }); }; ``` 이런 식으로 resetMaxAge() 함수를 통해서 만료 시간을 연장할 수 있을거라 생각했습니다. (트라이캐치문은 생략하였습니다.) 콘솔에 값을 확인해봤을 때에도 연장이 잘 된 것으로 보이는데 브라우저에 저장된 쿠키의 만료 시간을 확인해보면 최초의 쿠키 값 그대로였습니다. 이를 해결하기 위해서 만료 시간을 따로 정해서 줘보기도 했습니다. `req.session.cookie.maxAge = 3600000;` 하지만 마찬가지로 세션 쿠키의 만료 시간은 바뀌지만 브라우저에 저장된 쿠키의 expires가 변하지 않았습니다. 따로 헤더를 줘보아도 새로운 쿠키가 생성될 뿐 해결책이 되지 않았습니다. `res.setHeader('Set-Cookie', 'Max-Age=3600000')` express-session 미들웨어가 자동으로 set-cookie 헤더를 설정해주어서 제가 여기에 어떻게 접근할 수 있을지 모르겠습니다. 브라우저의 쿠키가 초기화 적용을 받지 못하는 것이 문제인 것 같은데... 원인은 대충 알 것 같으면서 해결책을 모르겠습니다. session 설정은 이렇습니다! ```ts app.use( session({ secret: process.env.SESSION_SECRET_KEY, resave: false, saveUninitialized: false, cookie: { sameSite: 'lax', secure: false, httpOnly: true, maxAge: 1000 * 60 * 5, }, store: new FileStore({ reapInterval: 3000, }), }), ); ```
개발자
#node.js
#express
#express-session
#session
#cookie
답변 0
댓글 0
조회 190