reactjs 사이트를 네이티브 앱 반응으로 변환
44991 단어 exporeactnativenodejreact
이제 반응 네이티브를 사용하여 지상 앱에서 앱을 빌드해야 합니다. 번들 크기가 새 사용자에게 적합하지 않을 수 있습니다. i. 애플리케이션이 성능에 의존하는 경우 kotlin/swift 기본 방식을 확실히 고려하세요.
기본 앱이 예산에 맞지 않는 경우 반응 사이트를 기본 앱으로 변환하는 것 외에는 권장하지 않습니다.
이제 이 실시간 채팅 반응 앱을 변환해 보겠습니다.
code repo
Built apk for android
기본적으로 반응하는 데 하루도 채 걸리지 않았고 kotlin에서 시도하면 훨씬 더 오래 걸릴 것입니다.
저는 엑스포docs를 사용했습니다.
create-expo-app -t expo-template-blank-typescript
cd my-app
엑스포 버전의 유일한 주요 변경 사항은 로컬 스토리지를 사용할 수 없다는 것이므로 사용했습니다@react-native-async-storage/async-storage.
App.tsx
import { StatusBar } from 'expo-status-bar';
import { StyleSheet, Text, View } from 'react-native';
import JoinRoom from './components/JoinRoom';
import { useState } from 'react';
import { getLocalStorageData } from './utils/storage';
import { useEffect } from 'react';
import UserContext from './utils/context';
import { User } from './utils/types';
import Chats from './components/Chats';
import Loading from './components/Loading';
import { useCountdownTimer } from 'use-countdown-timer';
// let the_user:any
// const getUser = async()=>{
// the_user = await getLocalStorageData()
// }
export default function App() {
const [user, setUser] = useState<User>({username:"",room:""});
const updateUser = (new_user:User) => {setUser(new_user)};
const [loading, setLoading] = useState(true);
const [timeup, setTimeUp] = useState(true);
useEffect(()=>{
const timeout = setTimeout(() => {
setTimeUp (false);
}, 2000);
getLocalStorageData()
.then((res)=>{
const local_user = res as User
updateUser(local_user)
if(!countdown){
setLoading(false)
}
})
return () => {
clearTimeout(timeout);
};
},[])
const user_exists = user && user?.username !==""
return (
<View style={styles.container}>
<View style={styles.status}>
<StatusBar style="auto" />
</View>
<View style={styles.chats}>
{loading && timeup ?<Loading />:
<UserContext.Provider value ={{user,updateUser}}>
{user_exists?<Chats/>:<JoinRoom/>}
</UserContext.Provider>}
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'flex-end',
height:'100%'
},
status: {
alignItems: 'center',
justifyContent: 'flex-end',
height:'5%',
width:'100%',
},
chats: {
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'flex-end',
height:'95%',
width:'100%',
},
});
또한 비동기 스토리지가 로컬 스토리지를 확인하는 데 몇 초가 걸리기 때문에 2초 동안 시간 제한을 추가합니다.
useChsts 후크는 완전히 동일합니다.
import { Room, User } from "./types"
import { useRef,useState,useEffect } from 'react';
import socketIOClient,{ Socket } from 'socket.io-client';
const NEW_MESSAGE_ADDAED = "new_message_added";
const ROOM_DATA = "room_data";
const devUrl="http://localhost:4000"
const lanUrl="http://192.168.43.238:4000"
const prodUrl="https://sockets-server-ke.herokuapp.com/"
const useChats=(user:User)=>{
const socketRef = useRef<Socket>();
const [messages, setMessages] = useState<any>([]);
const [room, setRoom] = useState<Room>({users:0,room:""});
useEffect(() => {
socketRef.current = socketIOClient(prodUrl, {
query: { room:user.room,user:user.username },
transports: ["websocket"],
withCredentials: true,
extraHeaders:{"my-custom-header": "abcd"}
})
socketRef.current?.on(NEW_MESSAGE_ADDAED, (msg:any) => {
// //console.log("new message added==== ",msg)
setMessages((prev: any) => [msg,...prev]);
});
socketRef.current?.on(ROOM_DATA, (msg:any) => {
//console.log("room data ==== ",msg)
setRoom(msg)});
return () => {socketRef.current?.disconnect()};
}, [])
const sendMessage = (message:any) => {
//console.log("sending message ..... === ",message)
socketRef.current?.emit("new_message", message)
};
return {room,messages,sendMessage}
}
export default useChats
JoinRoom.tsx
import { StyleSheet,View,Text} from 'react-native'
import React ,{useContext}from 'react'
import { useFormik } from 'formik';
import Button from './CustomButton';
import TextInput from './CustomInput';
import { storeLocalStorageData } from './../utils/storage';
import UserContext from './../utils/context';
import axios from 'axios';
import {LinearGradient} from 'expo-linear-gradient';
import * as yup from 'yup'
import { useState } from 'react';
interface JoinRoomProps{
}
const JoinRoom: React.FC<JoinRoomProps> = () => {
const devUrl="http://localhost:4000"
const lanUrl="http://192.168.43.238:4000"
const prodUrl="https://sockets-server-ke.herokuapp.com/"
const client = axios.create({ baseURL:prodUrl});
const user = useContext(UserContext);
const [error, setError] = useState({ name:"", message:"" });
const { handleChange, handleSubmit, values,errors,isSubmitting } = useFormik({
initialValues: { username:'',room:'general' },
onSubmit: values =>{
const roomname = values.room?values.room.toLowerCase():"general"
const username = values.username.toLowerCase()
const room_data = {username,room:roomname}
client.post('/users', {user:room_data})
.then( (response)=> {
const user_exist =response.data.data
console.log("user exists === ",user_exist,room_data)
if(user_exist){
console.log("error block")
setError({name:"username",message:"username exists"})
errors.username = "username exists"
}else{
console.log("no error block")
storeLocalStorageData(room_data)
user.updateUser(room_data)
}
})
.catch(function (error) {
});
}
})
console.log("errors",errors.username)
const validationColor = "white"
const textColor = "white"
return (
<View
style={styles.container}>
<LinearGradient colors={['#164e63', '#1b9999', '#851ea3']} style={styles.linearGradient}>
<View style={styles.formbox}>
<TextInput onChangeText={handleChange('username')} value={values.username}
validationColor={validationColor} textcolor={textColor}/>
{/* {errors.username &&<Text style={{ fontSize: 15, color: 'yellow' }}>{errors.username}</Text>} */}
{error.name==="username" &&<Text style={{ fontSize: 15, color: 'yellow' }}>{error.message}</Text>}
<View style={styles.inputbuffer}></View>
<TextInput onChangeText={handleChange('room')} value={values.room}
validationColor={validationColor} textcolor={textColor}
/>
{error.name === "room" &&<Text style={{ fontSize: 15, color: 'yellow' }}>{error.message}</Text>}
<View style={styles.button}>
<Button onPress={handleSubmit} label="JOIN" color={textColor} />
</View>
</View>
</LinearGradient>
</View>
)
}
export default JoinRoom
const styles = StyleSheet.create({
container:{
flex:1,
width:'100%',
height:"100%",
marginTop:15
},
inputbuffer:{
height:20,
flexDirection:'column',
justifyContent:'center',
alignItems:'center',
width:'100%'
},
linearGradient: {
flex: 1,
width:'100%',
height:"100%",
flexDirection:'column',
justifyContent:'center',
alignItems:'center',
},
formbox:{
flex:.5,
height:100,
backgroundColor:"#330033",
flexDirection:'column',
justifyContent:'center',
alignItems:'center',
width:'95%',
borderRadius:10,
elevation:7,
shadowColor:'#00ff33',
shadowOffset: {
width: 5,
height: 25,
},
shadowOpacity: .9,
shadowRadius: 50.05,
}
,
button:{
marginTop:20,
}
})
여기서 유일하게 큰 차이점은 선택 사항인 formik을 사용하고 있으며 일반 일반 양식을 계속 사용할 수 있으며 원하는 경우 웹사이트에서 formik을 사용할 수도 있다는 것입니다.
다른 하나는 몇 가지 tailwindcss 클래스에 의해 달성된 웹 사이트의 그라데이션 색상 효과를 모방하는 선형 그라데이션 구성 요소입니다.
react linear gradient
그리고 반응 네이티브에서 tailwindcss를 사용하는 방법이 있는 것 같습니다article link.
나는 그것을 시도하지만 당신이 나를 이기면 알려주세요.
code repo
Built apk for android
reactjs client repo
server repo
Reference
이 문제에 관하여(reactjs 사이트를 네이티브 앱 반응으로 변환), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/tigawanna/converting-your-reactjs-site-to-react-native-app-i5a텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)