reactjs 사이트를 네이티브 앱 반응으로 변환

React의 가장 좋은 특성 중 하나는 대부분의 비즈니스 로직이 동일하기 때문에 비교적 빠르게 반응 네이티브 앱으로 이식할 수 있는 기능입니다.
이제 반응 네이티브를 사용하여 지상 앱에서 앱을 빌드해야 합니다. 번들 크기가 새 사용자에게 적합하지 않을 수 있습니다. 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

좋은 웹페이지 즐겨찾기