묻고 답해요
169만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결배달앱 클론코딩 [with React Native]
IOS 실기기 연결시 .env 환경변수
아이폰 실기기 연결하여 테스트 중인데, .env값 수정하였는데 계속 이전 값을 들고옵니다.(ex. API_URL에 설정해놓은 localhost값을 피씨 아이피로 변경 -> 재빌드해도 계속 이전 localhost를 들고옴)재빌드, 메트로 서버 종료, 앱삭제 등 여러가지 시도 하였는데 계속 이전 값을 유지하는데 보통 환경변수 파일 바꾸면 어떻게 하시는지 궁금합니다.이런 경우엔 빌드 폴더 클린 하는 방법말고 없을까여?
-
미해결배달앱 클론코딩 [with React Native]
TypeError: Cannot read property 'status' of undefined
안녕하세요 제로초님!회원가입을 하려면, 계속 아래와 같은 에러가 터미널에 뜹니다.error: [TypeError: Cannot read property 'status' of undefined] ERROR undefined어디가 잘 못 된걸까요,,.env파일 확인 해서 제 IP주소 확인했습니다.signUp 부분을 확인해야하는건지,,import React, {useCallback, useRef, useState, useEffect} from 'react'; import { ActivityIndicator, Alert, Platform, Pressable, StyleSheet, Text, TextInput, View, } from 'react-native'; import {NativeStackScreenProps} from '@react-navigation/native-stack'; import DismissKeyboardView from '../components/DismissKeyboardView'; import axios, {AxiosError} from 'axios'; import Config from 'react-native-config'; // 혹시 이거 설정법 아시나요 import {RootStackParamList} from '../../AppInner'; type SignUpScreenProps = NativeStackScreenProps<RootStackParamList, 'SignUp'>; function SignUp({navigation}: SignUpScreenProps) { const [loading, setLoading] = useState(false); const [email, setEmail] = useState(''); const [name, setName] = useState(''); const [password, setPassword] = useState(''); const emailRef = useRef<TextInput | null>(null); const nameRef = useRef<TextInput | null>(null); const passwordRef = useRef<TextInput | null>(null); useEffect(() => { console.log('email: ', email); console.log('name: ', name); console.log('password: ', password); }, [email, name, password]); const onChangeEmail = useCallback((text: string) => { setEmail(text.trim()); }, []); const onChangeName = useCallback((text: string) => { setName(text.trim()); }, []); const onChangePassword = useCallback((text: string) => { setPassword(text.trim()); }, []); const onSubmit = useCallback(async () => { if (loading) { return; } if (!email || !email.trim()) { return Alert.alert('알림', '이메일을 입력해주세요.'); } if (!name || !name.trim()) { return Alert.alert('알림', '이름을 입력해주세요.'); } if (!password || !password.trim()) { return Alert.alert('알림', '비밀번호를 입력해주세요.'); } if ( !/^(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/.test( email, ) ) { return Alert.alert('알림', '올바른 이메일 주소가 아닙니다.'); } if (!/^(?=.*[A-Za-z])(?=.*[0-9])(?=.*[$@^!%*#?&]).{8,50}$/.test(password)) { return Alert.alert( '알림', '비밀번호는 영문,숫자,특수문자($@^!%*#?&)를 모두 포함하여 8자 이상 입력해야합니다.', ); } console.log(email, name, password); try { //:TODO log 삭제 console.log('LOGIN REQUEST'); console.log(Config.API_URL); setLoading(true); console.log(email); console.log(name); console.log(password); const response = await axios.post(`${Config.API_URL}/user`, { email, name, password, }); console.log('response: ', response.data); Alert.alert('알림', '회원가입 되었습니다.'); navigation.navigate('SignIn'); } catch (error) { console.log('error: ', error); const errorResponse = (error as AxiosError).response; console.error(errorResponse); if (errorResponse) { Alert.alert('알림'); } } finally { setLoading(false); } }, [loading, navigation, email, name, password]); const canGoNext = email && name && password; return ( <DismissKeyboardView> <View style={styles.inputWrapper}> <Text style={styles.label}>이메일</Text> <TextInput style={styles.textInput} onChangeText={onChangeEmail} placeholder="이메일을 입력해주세요" placeholderTextColor="#666" textContentType="emailAddress" value={email} returnKeyType="next" clearButtonMode="while-editing" ref={emailRef} onSubmitEditing={() => nameRef.current?.focus()} blurOnSubmit={false} /> </View> <View style={styles.inputWrapper}> <Text style={styles.label}>이름</Text> <TextInput style={styles.textInput} placeholder="이름을 입력해주세요." placeholderTextColor="#666" onChangeText={onChangeName} value={name} textContentType="name" returnKeyType="next" clearButtonMode="while-editing" ref={nameRef} onSubmitEditing={() => passwordRef.current?.focus()} blurOnSubmit={false} /> </View> <View style={styles.inputWrapper}> <Text style={styles.label}>비밀번호</Text> <TextInput style={styles.textInput} placeholder="비밀번호를 입력해주세요(영문,숫자,특수문자)" placeholderTextColor="#666" onChangeText={onChangePassword} value={password} keyboardType={Platform.OS === 'android' ? 'default' : 'ascii-capable'} textContentType="password" secureTextEntry returnKeyType="send" clearButtonMode="while-editing" ref={passwordRef} onSubmitEditing={onSubmit} /> </View> <View style={styles.buttonZone}> <Pressable style={ canGoNext ? StyleSheet.compose(styles.loginButton, styles.loginButtonActive) : styles.loginButton } disabled={!canGoNext || loading} onPress={onSubmit}> {loading ? ( <ActivityIndicator color="white" /> ) : ( <Text style={styles.loginButtonText}>회원가입</Text> )} </Pressable> </View> </DismissKeyboardView> ); } const styles = StyleSheet.create({ textInput: { padding: 5, borderBottomWidth: StyleSheet.hairlineWidth, }, inputWrapper: { padding: 20, }, label: { fontWeight: 'bold', fontSize: 16, marginBottom: 20, }, buttonZone: { alignItems: 'center', }, loginButton: { backgroundColor: 'gray', paddingHorizontal: 20, paddingVertical: 10, borderRadius: 5, marginBottom: 10, }, loginButtonActive: { backgroundColor: 'blue', }, loginButtonText: { color: 'white', fontSize: 16, }, }); export default SignUp; 아니면 AppInner부분인건지 모르겟습니다.import SignIn from './src/pages/SignIn'; import SignUp from './src/pages/SignUp'; import Orders from './src/pages/Orders'; import Delivery from './src/pages/Delivery'; import Settings from './src/pages/Settings'; import * as React from 'react'; import {createBottomTabNavigator} from '@react-navigation/bottom-tabs'; import {createNativeStackNavigator} from '@react-navigation/native-stack'; import {useSelector} from 'react-redux'; import {RootState} from './src/store/reducer'; import useSocket from './src/hooks/useSocket'; import {useEffect} from 'react'; import EncryptedStorage from 'react-native-encrypted-storage'; import axios, {AxiosError} from 'axios'; import {Alert} from 'react-native'; import userSlice from './src/slices/user'; import {useAppDispatch} from './src/store'; import Config from 'react-native-config'; import orderSlice from './src/slices/order'; export type LoggedInParamList = { Orders: undefined; Settings: undefined; Delivery: undefined; Complete: {orderId: string}; }; export type RootStackParamList = { SignIn: undefined; SignUp: undefined; }; const Tab = createBottomTabNavigator(); const Stack = createNativeStackNavigator<RootStackParamList>(); function AppInner() { const dispatch = useAppDispatch(); const isLoggedIn = useSelector((state: RootState) => !!state.user.email); console.log('isLoggedIn', isLoggedIn); const [socket, disconnect] = useSocket(); // 앱 실행 시 토큰 있으면 로그인하는 코드 useEffect(() => { const getTokenAndRefresh = async () => { try { const token = await EncryptedStorage.getItem('refreshToken'); if (!token) { return; } const response = await axios.post( `${Config.API_URL}/refreshToken`, {}, { headers: { authorization: `Bearer ${token}`, }, }, ); dispatch( userSlice.actions.setUser({ name: response.data.data.name, email: response.data.data.email, accessToken: response.data.data.accessToken, }), ); } catch (error) { console.error(error); if ((error as AxiosError as any).response?.data.code === 'expired') { Alert.alert('알림', '다시 로그인 해주세요.'); } } }; getTokenAndRefresh(); }, [dispatch]); useEffect(() => { const callback = (data: any) => { console.log(data); dispatch(orderSlice.actions.addOrder(data)); }; if (socket && isLoggedIn) { socket.emit('acceptOrder', 'hello'); socket.on('order', callback); } return () => { if (socket) { socket.off('order', callback); } }; }, [dispatch, isLoggedIn, socket]); useEffect(() => { if (!isLoggedIn) { console.log('!isLoggedIn', !isLoggedIn); disconnect(); } }, [isLoggedIn, disconnect]); useEffect(() => { axios.interceptors.response.use( response => { return response; }, async error => { const { config, response: {status}, } = error; if (status === 419) { if (error.response.data.code === 'expired') { const originalRequest = config; const refreshToken = await EncryptedStorage.getItem('refreshToken'); // token refresh 요청 const {data} = await axios.post( `${Config.API_URL}/refreshToken`, // token refresh api {}, {headers: {authorization: `Bearer ${refreshToken}`}}, ); // 새로운 토큰 저장 dispatch(userSlice.actions.setAccessToken(data.data.accessToken)); originalRequest.headers.authorization = `Bearer ${data.data.accessToken}`; // 419로 요청 실패했던 요청 새로운 토큰으로 재요청 return axios(originalRequest); } } return Promise.reject(error); }, ); }, [dispatch]); return isLoggedIn ? ( <Tab.Navigator> <Tab.Screen name="Orders" component={Orders} options={{title: '오더 목록'}} /> <Tab.Screen name="Delivery" component={Delivery} options={{title: '내 오더'}} /> <Tab.Screen name="Settings" component={Settings} options={{title: '내 정보'}} /> </Tab.Navigator> ) : ( <Stack.Navigator> <Stack.Screen name="SignIn" component={SignIn} options={{title: '로그인'}} /> <Stack.Screen name="SignUp" component={SignUp} options={{title: '회원가입'}} /> </Stack.Navigator> ); } export default AppInner;
-
미해결비전공자를 위한 진짜 입문 올인원 개발 부트캠프
프로젝트를 마치며 배포 페이지에서 업로드 작동이 안됨
상품 업로드에 관한 이슈과정을 다 마치고, fly.io와 vercel.com을 통하여 배포한 페이지 중에서 상품 업로드가 제대로 이뤄지지 않습니다.github 주소 : https://github.com/arominddo/Inflearn_full_stack_boot_campvercel을 통해 배포된 web 어플리케이션 url :https://grab-market-client-ashen.vercel.app/ grab_market_web > src > upload > index.js에 코드 내용이 작성되어 있습니다. 배포된 페이지의 DB 초기화 문제프로젝트를 전부 마치면서, 다시 한번 fly.io에 최신 코드로 재배포를 해보고 실험을 해보았는데도, web에서 특정 상품을 업로드하거나(오류가 나지 않았을 당시), 상품 구매하기 기능을 통하여 soldout 값을 1로 바꿔줬음에도,약 5분이 지나면 DB가 배포 됐을 당시의 내용으로 계속 초기화가 됩니다.해결 방안이 궁금합니다.ex) A라는 물건 업로드 -> 5분 지남 -> 새로고침 해보면 A라는 물건이 리스트에서 삭제ex) B라는 물건 구매 하기 버튼 클릭 -> soldout 값 1로 변경 -> 약 5분 지남 -> 다시 soldout 값 0으로 복귀
-
미해결배달앱 클론코딩 [with React Native]
1. SafeAreaView 2. 상태관리
두가지 질문이 있습니다!NavigationContainer에 Safe view가 적용되있어최상단 App.tsx에는 작성안해도 되지만 내부에 중첩 라우터 컴포넌트의 경우 (Ing.tsx) 헤더가 없을 경우 적용되지 않던데이런 경우는 각 컴포넌트마다 SafeAreaView를 사용하는 수 밖에 없을까요? 강의에서는 상태관리를 리덕스 툴킷으로 하였는데 클라이언트 상태관리는 리덕스 툴킷, 서버 데이터 상태관리는 RTK나 리액트 쿼리등으로 따로 관리하시나요?
-
미해결배달앱 클론코딩 [with React Native]
키보드 관련 질문드립니다.
안녕하세요.안드로이드에서 react-native-keyboard-aware-scroll-view 라이브러리 사용해서 인스타그램 댓글창처럼 만들고있는데 FlatList로 댓글을 가져오고맨밑에 인풋창을 누르면 키보드가 상단으로 올라오면서 맨밑에 댓글이 가려지는 현상이있는데 이부분에 대해 해결방법이 있을까요?windowSoftInputMode는 adjustResize고 adjustPan모드로도 해봤는데 이건 맨위에 댓글 부분이 잘려나가더라구요.이것저것 해봤는데 안되서 여기다 질문 남깁니다.
-
미해결비전공자를 위한 진짜 입문 올인원 개발 부트캠프
setProducts(products); 의 작동방식을 모르겠습니다.
setProducts(products);가 products라는 state를 변경하는 거잖아요.그런데 products는 바로 위 line에서 const로 정의되었는데 setProducts(products); 의 의미가 const 정의된 products라는 변수로 state를 변경한다는 의미인가요? 만약 state가 products가 아닌 다른 것이었다면 어떻게 되는 건가요? 정확히 어떤 과정인지 이해되지 않습니다.
-
해결됨비전공자를 위한 진짜 입문 올인원 개발 부트캠프
useEffect의 위치 조건을 잘 모르겠습니다.
useEffect를 setProducts(products);앞에 쓰는 것은 왜 에러인가요? 재실행하고 싶은 구간에만 써주면 되는 것이 아닌가요?
-
미해결
react native 윈도우 실행 오류
이번에 처음으로 앱 개발 공부를 해보려고 react native를 열심히 실행해 봤습니다.중간에 계속 에러가 나고 막히는 부분이 있었지만 겨우 마지막에 npm run android부분까지 왔습니다. 그런데 실행을 할려고 하면 계속C:\Users\aladi\MyApp\NewApp>npx react-native run-android info Starting JS server... info 💡 Tip: Make sure that you have set up your development environment correctly, by running react-native doctor. To read more about doctor command visit: https://github.com/react-native-community/cli/blob/main/packages/cli-doctor/README.md#doctor FAILURE: Build completed with 2 failures. 1: Task failed with an exception. ----------- * Where: Build file 'C:\Users\aladi\MyApp\NewApp\android\app\build.gradle' line: 2 * What went wrong: A problem occurred evaluating project ':app'. > Could not find implementation class 'com.facebook.react.ReactPlugin' for plugin 'com.facebook.react' specified in jar:file:/C:/Users/aladi/.gradle/caches/jars-9/e787d8a8f912d81d210d8e27e6fa5ed3/react-native-gradle-plugin.jar!/META-INF/gradle-plugins/com.facebook.react.properties. * Try: > Run with --stacktrace option to get the stack trace. > Run with --info or --debug option to get more log output. > Run with --scan to get full insights. ============================================================================== 2: Task failed with an exception. ----------- * What went wrong: A problem occurred configuring project ':app'. > compileSdkVersion is not specified. Please add it to build.gradle * Try: > Run with --stacktrace option to get the stack trace. > Run with --info or --debug option to get more log output. > Run with --scan to get full insights. ============================================================================== * Get more help at https://help.gradle.org BUILD FAILED in 12s error Failed to install the app. Command failed with exit code 1: gradlew.bat tasks FAILURE: Build completed with 2 failures. 1: Task failed with an exception. ----------- * Where: Build file 'C:\Users\aladi\MyApp\NewApp\android\app\build.gradle' line: 2 * What went wrong: A problem occurred evaluating project ':app'. > Could not find implementation class 'com.facebook.react.ReactPlugin' for plugin 'com.facebook.react' specified in jar:file:/C:/Users/aladi/.gradle/caches/jars-9/e787d8a8f912d81d210d8e27e6fa5ed3/react-native-gradle-plugin.jar!/META-INF/gradle-plugins/com.facebook.react.properties. * Try: > Run with --stacktrace option to get the stack trace. > Run with --info or --debug option to get more log output. > Run with --scan to get full insights. ============================================================================== 2: Task failed with an exception. ----------- * What went wrong: A problem occurred configuring project ':app'. > compileSdkVersion is not specified. Please add it to build.gradle * Try: > Run with --stacktrace option to get the stack trace. > Run with --info or --debug option to get more log output. > Run with --scan to get full insights. ============================================================================== * Get more help at https://help.gradle.org BUILD FAILED in 12s > Task :gradle-plugin:compileKotlin UP-TO-DATE > Task :gradle-plugin:compileJava NO-SOURCE > Task :gradle-plugin:pluginDescriptors UP-TO-DATE > Task :gradle-plugin:processResources UP-TO-DATE > Task :gradle-plugin:classes UP-TO-DATE > Task :gradle-plugin:jar UP-TO-DATE > Task :gradle-plugin:inspectClassesForKotlinIC UP-TO-DATE 5 actionable tasks: 5 up-to-date. 이런 에러가 뜨더라구요정말 이쪽부분은 하나도 모르는 코린이라 아무리 구글링해보고 혼자 머리 굴려봐도해결이 되지 않습니다.. 에뮬레이터까지는 뜨는데 react native화면은 뜨지 않고 저렇게 에러 메세지만 나옵니다. 어떻게 해야될까요.. 제발 도와주세요ㅜ
-
미해결핸즈온 리액트 네이티브
firebase이용 관련 앱 종료
안녕하세요 rn-photo 강의를 듣고있는 학생입니다.8.2 ~8.3 강의에서 firebase를 등록하고 SignInScreen.js파일에서 const onSubmit = async () => { Keyboard.dismiss(); if (!form.disabled && !form.isLoding) { dispatch({ type: AuthFormTypes.TOGGLE_LOADING }); try { const user = await signIn(form); console.log(user); } catch (e) { const message = getAuthErrorMesseages(e.code); Alert.alert('로그인 실패', message); } dispatch({ type: AuthFormTypes.TOGGLE_LOADING }); } }; 위 코드 중 signIn함수를 사용할때 계속 앱이 종료되버립니다.원인을 알수없어서 질문 드립니다.아래는 저의 깃허브 주소입니다.https://github.com/yunhyeonji/Hands-on-ReactNative
-
해결됨비전공자를 위한 진짜 입문 올인원 개발 부트캠프
code EEXIST 에러가 계속 뜨는데 어떡하죠..
안녕하세요 create-react-app을 설치하고create-react-app .를 입력한 후에 계속 이 에러가 떠서 진행을 못하고 있습니다.ㅠEEXIST라는 에러코드인데요.. 일단 저는 sudo npm install -g create-react-app 코드를 이용해서 설치를 했고create-react-app -V라는 코드를 이용해서 create-react-app의 버전이 나옴을 확인해, 설치는 제대로 되었음을 확인했습니다. 그런데 create-react-app . 이 부분을 입력할 때마다 저 에러가 뜹니다.. 어떻게 해결하면 좋을까요?처음부터도 다시 깔아보고, uninstall install도 해보고 npx로도 해봤지만 잘 안됐습니다..
-
해결됨비전공자를 위한 진짜 입문 올인원 개발 부트캠프
상세 페이지 구성하다 안된 수강생 입니다.캡쳐 사진 올리니 꼭좀 해결해 주세요
아무리 구글링 유튜브 찾아 봐도 알수가 없네요mock-sever 주소 크롬 주소창에 넣으면 분명히 자료가 잘 나오는데 vs코드에서 실행 하면 위에 처럼 에러가 나옵니다. 선생님 해결좀 부탁드립니다.수업을 나갈수가 없네요.
-
해결됨비전공자를 위한 진짜 입문 올인원 개발 부트캠프
구매버튼 클릭 시 soldout 구현 부분(상품 블러 처리)
상품 상세 페이지에서 구매 버튼을 누르게 되면,해당 상품의 soldout값이 1로 바뀌게고 적용 완료.그 이후 자동으로 구매 버튼이 회색으로 다시 바뀌겠끔도 구현 완료 그 이후 뒷 페이지로 돌아갔을 때, 상품 목록에서 blur처리 되는 기능이 구현되지 않아 이 방법이 궁금합니다.뒤로가기 버튼을 눌렀을 때는 해당 페이지가 새로 불러와지는 로직이 아닌가요? // Main페이지 코드 import { StatusBar } from "expo-status-bar"; import { StyleSheet, Text, View, Image, ScrollView, Dimensions, TouchableOpacity, Alert } from "react-native"; import React, {useEffect, useState} from "react"; import axios from "axios"; import dayjs from "dayjs" import relativeTime from "dayjs/plugin/relativeTime" import "dayjs/locale/ko" import Carousel from "react-native-reanimated-carousel" import { API_URL } from "../config/constants"; import AvatarImage from "../assets/icons/avatar.png"; dayjs.extend(relativeTime); dayjs.locale("ko"); export default function MainScreen(props) { const [products, setProducts] = useState([]); const [banners, setBanners] = useState([]); const getProduct = () => { axios .get(`${API_URL}/products`) .then((result) => { console.log(result); setProducts(result.data.products) }) .catch((error) => { console.error(error); }); } useEffect(() => { getProduct(); axios .get(`${API_URL}/banners`) .then((result) => { setBanners(result.data.banners); }) .catch((error) => { console.error(error); }) }, []); return ( <View style={styles.container}> <ScrollView> <Carousel data={banners} width={Dimensions.get("window").width} height={200} autoPlay={true} sliderWidth={Dimensions.get("window").width} itemWidth={Dimensions.get("window").width} itemHeight={200} renderItem={(obj) => { return ( <TouchableOpacity onPress={() => { Alert.alert("배너 클릭"); }} > <Image style={styles.bannerImage} source={{ uri: `${API_URL}/${obj.item.imageUrl}`}} resizeMode="contain" /> </TouchableOpacity> ); }} /> <Text style={styles.Headline}>판매되는 상품들</Text> <View sytle={styles.productList}> {products.map((product, index) => { return ( <TouchableOpacity onPress={() => { props.navigation.navigate("Product", { id: product.id }) }}> <View style={styles.productCard}> {product.soldout === 1 && ( <View style={styles.productBlur} /> )} <View> <Image style={styles.productImage} source={{ uri: `${API_URL}/${product.imageUrl}`, }} resizeMode={"contain"} /> </View> <View style={styles.productContents}> <Text sytle={styles.productName}> {product.name} </Text> <Text sytle={styles.productPrice}> {product.price}원 </Text> <View style={styles.productFooter}> <View style={styles.productSeller}> <Image style={styles.productAvatar} source={AvatarImage} /> <Text style={styles.productSellerName} > {product.seller} </Text> </View> <Text style={styles.productDate}> {dayjs(product.createdAt).fromNow()} </Text> </View> </View> </View> </TouchableOpacity> ); })} </View> </ScrollView> </View> ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: "#fff", padding: 32, }, productCard: { width: 320, borderColor: "rgb(230,230,230)", borderWidth: 1, borderRadius: 16, backgroundColor: "white", marginBottom: 8, }, productImage: { width: "100%", height: 210, }, productContents: { padding: 8, }, productSeller: { flexDirection: "row", alignItems: "center", }, productAvatar: { width: 24, height: 24, }, productFooter: { flexDirection: "row", justifyContent: "space-between", alignItems: "center", marginTop: 12, }, productName: { fontSize: 16, }, productPrice: { fontSize: 18, fontWeight: "600", marginTop: 8, }, productSellerName: { fontSize: 16, }, productDate: { fontSize: 16, }, productList: { alignItems: "center", }, Headline: { fontSize: 24, fontWeight: "800", marginBottom: 24, }, productBlur: { position: "absolute", top: 0, bottom: 0, left: 0, right: 0, backgroundColor : "#ffffffa6", zIndex: 999 }, bannerImage: { width: "90%", height: 200, }, safeAreaView: { flex: 1, backgroundColor: "#fff" } }); // Product 화면 코드 import axios from "axios"; import React, { useEffect, useState } from "react" import {Image, ActivityIndicator, StyleSheet, View, Text, TouchableOpacity, Alert, ScrollView} from "react-native" import { API_URL } from "../config/constants"; import Avatar from "../assets/icons/avatar.png" import dayjs from "dayjs" export default function ProductScreen(props){ const {id} = props.route.params; const [product, setProduct] = useState(null); const getProduct = () => { axios.get(`${API_URL}/products/${id}`) .then((result) => { console.log("product result : ", result.data); setProduct(result.data.product); }) .catch((error) => { console.error(error); }) } useEffect(() => { getProduct(); }, []); const onPressButton = () => { if(product.soldout !== 1) { axios.post(`${API_URL}/purchase/${id}`) .then((result) => { Alert.alert("구매가 완료되었습니다."); getProduct(); }) .catch((error) => { Alert.alert(`에러가 발생했습니다. ${error.message}`); }) } } if(!product){ return <ActivityIndicator /> } return ( <View style={styles.container}> <ScrollView> <View> <Image style={styles.productImage} source={{uri: `${API_URL}/${product.imageUrl}`}} resizeMode="contain" /> </View> <View style={styles.productSection}> <View style={styles.productSeller}> <Image style={styles.avatarImage} source={Avatar} /> <Text>{product.seller}</Text> </View> <View style={styles.divider} /> <View> <Text style={styles.productName}>{product.name}</Text> <Text style={styles.productPrice}>{product.price} 원</Text> <Text style={styles.productDate}>{dayjs(product.createAt).format("YYYY년 MM월 DD일")}</Text> <Text style={styles.productDescription}>{product.description}</Text> </View> </View> </ScrollView> <TouchableOpacity onPress={onPressButton}> <View style={product.soldout ===1 ? styles.purchaseDisabled : styles.purchaseButton}> <Text style={styles.purchaseText}>{product.soldout === 1 ? "구매완료" : "구매하기"}</Text> </View> </TouchableOpacity> </View> ) } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: "#fff" }, productImage: { width: "100%", height: 300 }, productSeller: { flexDirection: "row", alignItems: "center" }, avatarImage: { width: 50, height: 50, }, productSection: { padding: 16 }, divider: { backgroundColor: "#e9ecef", height: 1, marginVertical: 16 }, productName: { fontSize: 20, fontWeight: "400" }, productPrice: { fontSize: 18, fontWeight: "700", marginTop: 8 }, productDate: { fontSize:14, marginTop: 4, color: "rgb(204,204,204)" }, productDescription: { marginTop : 16, fontSize: 17 }, purchaseButton: { position: "absolute", bottom: 0, left: 0, right: 0, height: 60, backgroundColor: "rgb(255,80,88)", alignItems : "center", justifyContent: "center" }, purchaseText : { color: "white", fontSize: 20, }, purchaseDisabled: { position: "absolute", bottom: 0, left: 0, right: 0, height: 60, backgroundColor: "gray", alignItems : "center", justifyContent: "center" } })
-
미해결비전공자를 위한 진짜 입문 올인원 개발 부트캠프
수업 진행중 이 그랩마켓 상세 페이지 만들던중 농구공 이미지
안녕하세요.그랩마켓 상세페이지 만들기 중에서 농구공 이미지 하고postman에서 만든 products/1 내용이 안나오기에 MOCK SEVER를 다시 생성해서 .GET에 복사 붙여 넣기를 했습니다.그랬더니 에러가 나면서 아무것도 안보이게 됐습니다.그래서 lean-all-with -java 페이지로 가서 INDEX.HTML로 에 있는 axios.get ( "https://831a8e94-7b7a-4354-9e1a-eb37becbc7ad.mock.pstmn.io/products"에 가서 보니 예전에 만들은 것들은 그대로 더군요. 그래서 이것도 지우고 새로 만든 mock주소를 넣었더니 이것도 에러가 납니디.원래 mock서버 새로 만들어서 붙여 놓으면 안되나요? 몇일동안 매달려도 안되네요.도와주세요.선생님
-
미해결틴더 파이어베이스 클론 | 리액트 네이티브
디스코드 올바르지 않은 초대장
디스코드 올바르지 않은 초대장이라고 뜹니다
-
미해결비전공자를 위한 진짜 입문 올인원 개발 부트캠프
windows에서 발생하는 경로 \ 관련 문의드립니다.
"상품 업로드 기능 구현-2" 강의 중 잘 따라가다가 후반부에서 경로 문제로 인해 문의드립니다.업로드 페이지에서 업로드는 잘 되나, 업로드 후 메인 페이지에서 등록된 이미지가 나오지 않아 확인해보니 "/" 대신에 콘솔에는 캡처1과 같이 "\\" 가 나오고 DB Browser에서는 캡처2와 같이 "\"가 나옵니다. : 캡처1 입니다. : 캡처2 입니다.원인을 찾아보니 windows에서 파일 경로를 다룰 때 "\\"로 하기 때문에 생기는 문제라고 하는데요...어떻게 해결하면 좋을지 모르겠습니다.해결방법을 알려주시면 감사하겠습니다.
-
해결됨비전공자를 위한 진짜 입문 올인원 개발 부트캠프
import { Switch, Route } from "react-router-dom"; 모듈을 찾을수 없다고 뜹니다.
선생님 수업 따라서 열심히 따라 왔는데 여기서 막히네요.해결 좀 부탁드립니다.제가 나이가 53인데 사다리차 운전 하면서 자영업 하는데 다른길좀 가보려고 공부하는 중이거든요. 다른 분들한테는 쉬운걸 텐데 저한테는 어렵네요.구글링 해보고 네이버 도 찾아봣는데 찾을수가 없네요.이걸 해결해야 앞으로 나갈수 있을것 같은데 도와주세요.감사합니다
-
미해결비전공자를 위한 진짜 입문 올인원 개발 부트캠프
main/index.js과 product/index.js에서 setProduct 관련 문의드립니다.
main/index.js 에서는setProducts(result.data.products); 로 써야하고product/index.js 에서는setProducts(result.data); 로 써야하는데두 파일에서 return문에서는 동등하게 {product.name} , {product.price} 등으로 사용됩니다. 둘의 차이를 알려주시면 감사하겠습니다.
-
미해결비전공자를 위한 진짜 입문 올인원 개발 부트캠프
import시 {} 유무의 차이는 무엇인가요?
import axios from 'axios'; 에서는 중괄호가 없고import {Link} from 'react-router-dom' 에서는 중괄호가 있는데 차이가 뭔지 잘 모르겠습니다.axios는 'axios' 안에 있는 함수를 import 하는 것이고 {Link} 는 'react-router-dom' 안에 많은 컴포넌트 중 Link만 import 하기 위함인가요?
-
해결됨비전공자를 위한 진짜 입문 올인원 개발 부트캠프
useState를 사용하는 이유가 무엇인가요?
빈 배열을 선언해서 빈 배열에 (axios 통신을 통해 전달받은) result.data를 대입해서 사용하는 것이 아니라 useState를 사용하는 이유는 무엇인가요?제가 이해한 것은 서버에 새로운 데이터가 업로드되면 그때마다 바로바로 업로드 된 데이터를 화면에 보여주기 위함인 것 같은데(예를 들어 상품이 3개로 보이다가 관리자가 상품을 한 개 추가하면 새로고침을 안해도 4개로 보임), 올바르게 이해한 것이 맞을까요?
-
미해결배달앱 클론코딩 [with React Native]
react-native-image-crop-picker --> openPicker 오류
안녕하세요ImagePicker.openCamera <- 정상 동작ImagePicker.openPicker <- Required permission missing위 내용입니다확인 부탁드립니다.