React Native + Realm + Zustand ile basit kelime ezberleme uygulaması

Giriş
Merhabalar. İngilizce kelime eksiğim için geliştirdiğim basit bir uygulamayı paylaşmak ve Realm, Zustand kullanımı hakkında kısa bir örnek olması için bu post’u paylaşıyorum. Bu uygulamayı preply uygulamasında ders aldığım şu dönemlerde Fabian Afumbom A. isimli öğretmenimin dil öğrenirken kendi kullandığı ve bana da tavsiyesi üzerine yaptım. Neyse fazla uzatmadan konuya girelim.
Kullanılan Paketler
Paket Kurulumları (React-native v0.64.2)
Önce projemizi terminal açıp react-native ile oluşturuyoruz.
npx react-native init FabianEnglish
siz “FabianEnglish” kısmını istediğiniz bir proje ismi ile değiştirebilirsiniz.
Daha sonra proje dizinine ilerliyoruz
cd FabianEnglish
ve realm’i kuruyoruz
npm install realm
daha sonra podları yüklüyoruz
cd ios && pod install && cd ..
realm bu kadar.
Sıra geldi zustand’ı yüklemeye. Kök dizinde olduğunuzdan eminseniz aşağıdaki kodu tekrar terminale yapıştırın ve zustand kurulumunu tamamlayın.
npm install zustand
ya da yarn ile
yarn add zustand
sıra geldi react native vector icons kurmaya. Proje biraz daha güzel görünsün diye ikonlar her zaman lazım :). Hadi paketimizi ekleyelim.
npm install --save react-native-vector-icons
son olarak blur paketimizi ekleyelim
yarn add @react-native-community/blur
ya da
npm install --save @react-native-community/blur
ve son olarak ios için yeniden podları yükleyelim
cd ios && pod install && cd ..
paket kurulumu tamamlandı.
Projenin GitHub sayfası
https://github.com/HanzalaGun/FabianEnglish
Projeyi Kodlayalım
Öncelikle projeyi parçalara ayırmak için klasörlerimizi oluşturalım. Kök dizinde src adında bi klasör ve bu klasörün altında common, components, screen, state adında 4 adet klasör oluşturuyoruz. Daha sonra screen altında ListScreen.js adında bir dosya oluşturuyoruz.

bu dosyaya App.js içinde direkt gösterebiliriz. Aslında daha karmaşık yapılar için gerekli bir durum direkt App.js içine de ListScreen.js içine kodlayacaklarımızı kodlayabilirdik fakat ilerde projeyi geliştirmek istersek ve sayfalar artarsa karışıklık olmasın diye biz yine yapımızı hazır tutalım :). App.js şu şekilde gözükecek.
import React from 'react'
import ListScreen from './src/screens/ListScreen'
const App = () => {
return (
<ListScreen/>
)
}
export default App
artık ListScreen.js e geçebiliriz.Öncelikle arkaplanda bir fotoğraf ve bu fotoğrafın önüne bulanıklık vermek istedim. Bunun için istediğimiz bir arkaplan fotoğrafını common clasörü içine bg.jpg ismiyle koyuyoruz. bu isim önemli değil sadece resmi çekerken aynı isimde olduğuna dikkat edin. resmi çekmek için
const bg= require('../common/bg.jpg')
ile ListScreen.js içerisine aktarıyoruz.İkonlarımızı çekelim
import Icon from 'react-native-vector-icons/FontAwesome';
ve bu ikonu kullanmak için
Icon.loadFont()
sayfa içerisine yukarıdaki kod parçasını yazarak ikonları yüklememiz gerekiyor. Bu sırada blur arkaplan için ufak bi komponent hazırlayalım. components içerisine MyBlur.js adında bir dosya oluşturup “@react-native-community/blur” eklentimizi burada kullanıyoruz. MyBlur.js dosyamız şu şekilde
import React from 'react'
import { StyleSheet } from 'react-native'
import { BlurView } from "@react-native-community/blur";
const MyBlur = () => {
return (
<BlurView
style={styles.absolute}
blurType="dark"
/>
)
}
export default MyBlur
const styles = StyleSheet.create({
absolute: {
position: "absolute",
top: 0,
left: 0,
bottom: 0,
right: 0,
}
})
ListScreen.js sayfamıza geri dönelim. Bu sayfada header kısmında sol tarafta FabianEnglish yazacak. Sağ tarafta ise iki adet buton olacak bu butonların birisi “Ask Me” diğer ise “Learn” olacak Ask Me ile bize kaydettiğimiz kelimesinin çevirisini yapacağımız bi modal olacak doğru ise kelimenin scoru yükselecek. altında bir skip butonu olacak ve bu butona basarsak score azalacak. Header’ın altında bi search input olacak ki kelimeleri arayabilelim. Daha sonra sağ altta absolute olarak konumlandırdığımız bir buton olacak bu butona bastığımızda kelime kaydedebileceğimiz bölüm görünür hale gelecek. Son olarak da body kısmında kelimelerimiz listelenecek. Unutmadan bir adet de kendimize ait bir TextInput oluşturalım. O halde öncelikle components klasörüne
- Askme.js
- Learn.js
- SendComp.js(kelime kaydedeceğimiz komponent)
- ListComp.js(kelimelerin listeleneceği komponent )
- MyTextInput.js
sayfalarını oluşturuyoruz.
ListScreen’e geri dönmeden son olarak state yönetimimizi oluşturalım.
state klasörümüz içerisine state.js adında bir dosya oluşturdum. Evet asıl konulardan biri olan Zustand’ı kullanmaya başlayalım. Burada state ve aksiyonlarımızı oluşturuyoruz diyebiliriz. Ama redux’tan kullanımı çok daha kolay geldi bana :). Önce state.js içindeki kodları paylaşıp sonra açıklamaya çalışalım.
import create from 'zustand'
export const useStore = create(set => ({
wordState:false,
popupState:false,
askmeState:false,
learnState:false,
selectedWordState:{},
search:"",
setWordState:(data)=>set((state)=>({...state,wordState:data})),
setPopupState:(data)=>set((state)=>({...state,popupState:data})),
setAskmeState:(data)=>set((state)=>({...state,askmeState:data})),
setLearnState:(data)=>set((state)=>({...state,learnState:data})),
setSelectedWordState:(data)=>set((state)=>({...state,selectedWordState:data})),
setSearch:(data)=>set((state)=>({...state,search:data})),
}))
önce zustand içinden create fonksiyonunu çağırıp bu fonksiyonu useStore adında değişkene atayarak export edip create fonksiyonumuzu içine set parametresiyle array function oluşturuyoruz. ve içerisine değişken olarak wordState, learnState, search gibi değişkenlerimizi tanımlıyoruz. Ne olarak lazımsa o şekilde değer veriyoruz obje, string, int, boolean gibi gibi.. set ön ekiyle başlayan değişkenlerimiz ise aksiyonlarımız diyebiliriz yukarda tanımladığımız stateleri güncellemek için kullanacağız. Daha fazlası için zustand’ın dökümanlarına dalabilirsin :).
ama kısaca state okumak için
const loading = useStore(state => state.wordState)
state güncellemek için ise
const setLoading = useStore(state => state.setWordState)
şeklinde kullanıyoruz.
Evet artık ListScreen.js e dönüp burayı da şu hale getiriyoruz.
import React from 'react'
import { StyleSheet, Text, SafeAreaView, View, Pressable, ImageBackground } from 'react-native'
import Icon from 'react-native-vector-icons/FontAwesome';
import AskMe from '../components/AskMe';
import Learn from '../components/Learn';
import ListComp from '../components/ListComp'
import SendComp from '../components/SendComp'
import MyTextInput from '../components/MyTextInput'
import { useStore } from '../state/atom';
import MyBlur from '../components/MyBlur';
const bg= require('../common/bg.jpg')
Icon.loadFont()
const ListScreen = () => {
const setAskVisible = useStore(state => state.setAskmeState)
const setLearnVisible = useStore(state => state.setLearnState)
const setSearch = useStore(state => state.setSearch)
const search=(data)=>{
setSearch(data)
}
return (
<ImageBackground
source={bg}
resizeMode="stretch"
style={{backgroundColor:'white'}}
>
<MyBlur/>
<View style={styles.head1}>
<SafeAreaView>
<View style={styles.head}>
<Text style={styles.title}>Fabian English |</Text>
<Pressable style={styles.pressable}
onPress={()=>setAskVisible(true)}>
<Icon size={30} name="question" color="white" style={styles.pressableicon}></Icon>
<Text style={styles.headtext}>ask me</Text>
</Pressable>
<Pressable style={styles.pressable}
onPress={()=>setLearnVisible()}>
<Icon size={30} name="book" color="white" style={styles.pressableicon}></Icon>
<Text style={styles.headtext}>learn</Text>
</Pressable>
</View>
</SafeAreaView>
</View>
<AskMe/>
<Learn/>
<SafeAreaView style={styles.container}>
<View>
<MyTextInput placeholder="Search" onChange={(data)=>search(data)} padding={20}/>
</View>
<ListComp/>
</SafeAreaView>
<SendComp/>
</ImageBackground>
)
}
export default ListScreen
const styles = StyleSheet.create({
container:{
height:'100%',
},
head:{
flexDirection:'row',
justifyContent:'space-around',
marginBottom:10,
alignItems:'center',
paddingVertical:10,
},
head1:{
marginBottom:10,
backgroundColor:'#ffffff50',
shadowColor:'black',
shadowOpacity:0.,
shadowRadius:1,
shadowOffset:{width: -1, height: 3},
},
title:{
color:'white',
fontSize:20,
fontWeight:'700',
textShadowColor:'black',
textShadowRadius:3,
textShadowOffset:{width: -1, height: 1},
},
headtext:{
color:'white',
fontSize:14,
fontWeight:'600',
textShadowColor:'black',
textShadowRadius:6,
textShadowOffset:{width: -1, height: 1},
paddingLeft:3
},
pressable:{
flexDirection:'row',
alignItems:'center'
},
pressableicon:{
shadowColor:'black',
shadowOpacity:0.2,
shadowRadius:1,
shadowOffset:{width: -1, height: 3},
},
})
useStore ile zustand a nasıl veri gönderebileceğimizi görmüşsündür, bu kadar kolay 🙂
Sırayla diğer komponentleri de paylaşalım.
//MyTextInput.js
import React from 'react'
import { StyleSheet, View, TextInput, Dimensions } from 'react-native'
const MyTextInput = ({onChange,placeholder,value,autoFocus=false,padding=70}) => {
return (
<View style={[styles.container,{width:Dimensions.get('screen').width-padding}]}>
<TextInput style={{paddingVertical:5}} autoFocus={autoFocus} value={value} placeholder={placeholder} placeholderTextColor='white' onChangeText={(a)=>{onChange(a)}}></TextInput>
</View>
)
}
export default MyTextInput
const styles = StyleSheet.create({
container:{
backgroundColor:'#f2f2f270',
padding:5,
margin:3,
alignSelf:'center',
borderRadius:5,
}
})
burada araya girip diğer önemli konu olan Realm e bakalım.
import Realm from 'realm'
kullanmak için yukardaki şekilde import etmemiz gerekiyor. Ve bir şema kullanmamız gerekiyor. Bu şemayı farklı yerlerde kullanacağımız için bunu da hemen ayrı bir dosyada kaydedelim ki hem daha temiz bir görünüm olsun hem de değişiklik yapması kolay olsun. common klasörümüze Shema.js dosyası oluşturalım.
export const WordShema = {
name: 'Words',
properties: {
id:'int',
name: 'string',
description: 'string',
pronunciation: 'string',
translate: 'string',
date: 'date',
score: 'int'
}
};
bunda fazla anlatacak birşey yok ilk name şemamızın ismi properties içindekiler ise tabloda kaydettiklerimiz yani asıl verilerimiz.
- id => benzersiz id miz
- name => kelimemiz
- description => kelimeye açıklama eklemek istersek diye var
- pronunciation => kelimenin telaffuzu
- translate => çevirisi
- date => kelimenin üretilme tarihi için
- score => kelimenin puanını tutmamız için
gelelim kullanım kısmına
import { WordShema } from '../common/Shema';
diyerek şemamızı da import ediyoruz
öncelikle realmi kullanırken open fonksiyonunu kullanarak hangi şemayı açacağımızı söylüyoruz ve açtıktan sonra ne yapacağımızı fonksiyon döndürerek söylüyoruz.
Realm.open({schema:[WordShema]}).then(realm=>{
//her zaman işlemlerimizi burada yapıyoruz.
})
Örneğin tüm kelimeleri çekmek istersek
Realm.open({schema:[WordShema]}).then(realm=>{
let obj = realm.objects('Words');
})
bu şekilde obj değişkenine tüm kelimeleri aktarmış olduk. ‘Words’ şemada verdiğimiz ilk name değişkeninden geliyor.
Veritabanına yazı yazdırmak istersek ise
Realm.open({schema:[WordShema]}).then(realm=>{
realm.write(()=>{
const myData=realm.create('Words',{
id:'benzersiz id',
name:'kelime',
description:'açıklama',
pronunciation:'telafuz',
translate:'çeviri',
date:new Date(),
score:0
})
})
})
şeklinde yapabiliriz.
ya da Realm’de güncelleme işlemi için
Realm.open({schema:[WordShema]}).then(realm=>{
let obj = realm.objects('Words').filtered("id='"+data.id+"'")[0];
realm.write(() => {
obj.name='güncellenen kelime'
})
})
şeklinde kullanabiliriz. burada filtered fonksiyonu Words tablomuzun içinde filtreleme yapmamıza yarıyor.
Real kullanımını da temel olarak gördüğümüze göre kodlarımıza dönebiliriz. Komponentlere devam edelim ve hepsini artık arka arkaya paylaşsamda anlamayacağınız bir kısım kalmadı :). devamında bir açıklama yapmama gerek yok 🙂
//SendComp.js
import React, {useState, useEffect} from 'react'
import { StyleSheet, Text, View, TouchableOpacity, Dimensions, Alert, SafeAreaView } from 'react-native'
import MyTextInput from './MyTextInput'
import Realm from 'realm';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
import { useStore } from '../state/state';
import { WordShema } from '../common/Shema';
const width=Dimensions.get('screen').width;
Icon.loadFont()
const SendComp = ({isSend=true}) => {
const data = useStore(state => state.selectedWordState)
const [name, setName] = useState('')
const [description, setDescription] = useState('')
const [pronunciation, setPronunciation] = useState('')
const [translate, setTranslate] = useState('')
const [opened, setOpened] = useState(isSend?false:true)
const setLoading = useStore(state => state.setWordState)
const setModalVisible = useStore(state => state.setPopupState)
useEffect(() => {
if(!isSend&&data){
setName(data.name)
setDescription(data.description)
setPronunciation(data.pronunciation)
setTranslate(data.translate)
}
}, [data])
const sendData=()=>{
if(name.length>0&&translate.length>0){
Realm.open({schema:[WordShema]}).then(realm=>{
realm.write(()=>{
const myData=realm.create('Words',{
id:parseInt(new Date().getTime()+''+Math.floor(Math.random()*10000)),
name:name,
description:description,
pronunciation:pronunciation,
translate:translate,
date:new Date(),
score:0
})
})
}).then(()=>{
setLoading(true)
setName('')
setDescription('')
setPronunciation('')
setTranslate('')
setModalVisible(false)
})
}else{
Alert.alert('You must be fill Word and Translate')
}
}
const updateData = ()=>{
if(name.length>0&&translate.length>0){
Realm.open({schema:[WordShema]}).then(realm=>{
let obj = realm.objects('Words').filtered("id='"+data.id+"'")[0];
realm.write(() => {
obj.name=name
obj.description=description
obj.pronunciation=pronunciation
obj.translate=translate
})
}).then(()=>{
setLoading(true)
setModalVisible(false)
})
}else{
Alert.alert('You must be fill Word and Translate')
}
}
return (
<SafeAreaView style={[styles.container,isSend?{position:'absolute',
bottom:150,
left:10}:null]}>
{opened&&<View style={styles.inputs}>
<MyTextInput value={name} placeholder='Word' onChange={(data)=>{setName(data)}}></MyTextInput>
<MyTextInput value={translate} placeholder='Translate' onChange={(data)=>{setTranslate(data)}}></MyTextInput>
<MyTextInput value={pronunciation} placeholder='Pronunciation' onChange={(data)=>{setPronunciation(data)}}></MyTextInput>
<MyTextInput value={description} placeholder='Description' onChange={(data)=>{setDescription(data)}}></MyTextInput>
</View>}
<View>
{opened?
<View style={{flex:1}}>
<TouchableOpacity style={styles.buttonsend} onPress={()=>isSend?sendData():updateData()}>
<Icon name={isSend?"send":'update'} size={isSend?30:50} color="green" />
</TouchableOpacity>
{isSend&&<TouchableOpacity style={styles.buttonminus} onPress={()=>setOpened(false)}>
<Icon name="minus" size={30} color="red" />
</TouchableOpacity>}
</View>
:
<View style={{alignItems:'flex-end', width:width-35,}}>
<TouchableOpacity style={styles.buttonplus} onPress={()=>setOpened(true)}>
<Icon style={styles.plusicon} name="plus" size={30} color="white" />
</TouchableOpacity>
</View>
}
</View>
</SafeAreaView>
)
}
export default SendComp
const styles = StyleSheet.create({
container:{
flexDirection:'row',
paddingHorizontal:10,
},
buttonplus:{
backgroundColor:'#fff5',
padding:10,
borderRadius:50,
borderWidth:1,
borderColor:'white',
shadowColor:'black',
shadowOpacity:0.5,
shadowRadius:1,
shadowOffset:{width: -1, height: 3},
},
buttonminus:{
position:'absolute',
bottom:-10
},
buttonsend:{
justifyContent:'center',
flex:1,
},
plusicon:{
shadowColor:'black',
shadowOpacity:0.5,
shadowRadius:1,
shadowOffset:{width: -1, height: 3},
},
inputs:{
backgroundColor:'#111',
borderRadius:5
}
})
//Askme.js
import React, { useEffect, useState } from 'react'
import { StyleSheet, Dimensions, View,Modal, TouchableOpacity, Text } from 'react-native'
import Realm from 'realm'
import { useStore } from '../state/atom';
import { WordShema } from '../common/Shema';
import MyTextInput from './MyTextInput';
import MyBlur from './MyBlur';
const AskMe = () => {
const visible = useStore(state => state.askmeState)
const setVisible = useStore(state => state.setAskmeState)
const [data, setData] = useState([])
const [word, setWord] = useState('')
const [index, setIndex] = useState(0)
useEffect(() => {
Realm.open({schema:[WordShema]}).then(realm=>{
setData(realm.objects('Words').sorted('score',true))
})
}, [])
useEffect(() => {
if(data.length>0&&word.toLowerCase()==data[index].translate.toLowerCase()){
//realmda kelimenin scorunu yükselt
Realm.open({schema:[WordShema]}).then(realm=>{
let obj = realm.objects('Words').filtered("id='"+data[index].id+"'")[0];
realm.write(() => {
obj.score++
})
}).then(()=>{
setIndex(data.length!=index+1?index+1:0)
setWord('')
})
}
}, [word])
const skip =()=>{
//realmda kelimenin scorunu düşür
if(data.length>0){
Realm.open({schema:[WordShema]}).then(realm=>{
let obj = realm.objects('Words').filtered("id='"+data[index].id+"'")[0];
realm.write(() => {
obj.score--
})
console.log(obj)
}).then(()=>{
setIndex(data.length!=index+1?index+1:0)
setWord('')
})
}
}
return (
<Modal
animationType='slide'
transparent={true}
visible={visible}
>
<MyBlur/>
<TouchableOpacity style={styles.view} onPress={()=>setVisible(false)}>
<Text style={styles.title}>{data.length>0&&data[index].name}</Text>
<Text style={styles.text}>{data.length>0&&'( '+data[index].pronunciation+' )'}</Text>
<Text style={styles.text}>{data.length>0&&data[index].description}</Text>
<MyTextInput
value={word}
autoFocus placeholder="Write Translate"
onChange={(data)=>{setWord(data)}}
></MyTextInput>
<TouchableOpacity style={styles.skip} onPress={()=>skip()}>
<Text style={styles.skiptext}>{'skip >>'}</Text>
</TouchableOpacity>
<View style={{height:40}}/>
<Text style={styles.bottom}>if you skip this word, the word's score to less</Text>
<Text style={styles.bottom}>if you learned this word, you must delete this word</Text>
</TouchableOpacity>
</Modal>
)
}
export default AskMe
const styles = StyleSheet.create({
view:{
width:'100%',
height:'100%',
alignItems:'center',
justifyContent:'center',
alignSelf:'center',
borderRadius:10
},
skiptext:{
color:'white',
fontWeight:'900'
},
skip:{
padding:10,
marginTop:20,
backgroundColor:'#f005',
alignItems:'flex-end',
width:Dimensions.get('screen').width-70,
borderRadius:5
},
title:{
color:'white',
fontSize:25,
fontWeight:'900',
textShadowColor:'#f00',
textShadowRadius:5,
textShadowOffset:{width: 0, height: 0},
marginBottom:20
},
bottom:{
color:'white',
fontSize:12
},
text:{
color:'white'
}
})
//Learn.js
import React, { useEffect, useState } from 'react'
import { StyleSheet, Dimensions, View,Modal, TouchableOpacity, Text } from 'react-native'
import Realm from 'realm'
import { useStore } from '../state/atom';
import { WordShema } from '../common/Shema';
import MyBlur from './MyBlur';
const Learn = () => {
const visible = useStore(state => state.learnState)
const setVisible = useStore(state => state.setLearnState)
const [data, setData] = useState([])
const [index, setIndex] = useState(0)
useEffect(() => {
Realm.open({schema:[WordShema]}).then(realm=>{
setData(realm.objects('Words').sorted('score',true))
})
}, [])
const skip =()=>{
setIndex(data.length!=index+1?index+1:0)
}
return (
<Modal
animationType='slide'
transparent={true}
visible={visible}
>
<MyBlur/>
<TouchableOpacity style={styles.view} onPress={()=>setVisible(false)}>
<Text style={styles.title}>{data.length>0&&data[index].name}</Text>
<Text style={styles.text}>{data.length>0&&'( '+data[index].pronunciation+' )'}</Text>
<Text style={styles.text}>{data.length>0&&data[index].translate}</Text>
<Text style={styles.text}>{data.length>0&&data[index].description}</Text>
<TouchableOpacity style={styles.skip} onPress={()=>skip()}>
<Text style={styles.skiptext}>{'next >>'}</Text>
</TouchableOpacity>
<View style={{height:40}}/>
</TouchableOpacity>
</Modal>
)
}
export default Learn
const styles = StyleSheet.create({
view:{
width:'100%',
height:'100%',
alignItems:'center',
justifyContent:'center',
alignSelf:'center',
borderRadius:10
},
skiptext:{
color:'white',
fontWeight:'900'
},
skip:{
padding:10,
marginTop:20,
backgroundColor:'#f005',
alignItems:'center',
width:Dimensions.get('screen').width-70,
borderRadius:5
},
title:{
color:'white',
fontSize:25,
fontWeight:'900',
textShadowColor:'#f00',
textShadowRadius:5,
textShadowOffset:{width: 0, height: 0},
marginBottom:20
},
text:{
color:'white'
}
})
//ListComp.js
import React, {useState, useEffect} from 'react'
import { View, Dimensions, ScrollView } from 'react-native'
import Realm from 'realm';
import MyRow from './MyRow';
import { useStore } from '../state/state';
import { WordShema } from '../common/Shema';
const height=Dimensions.get('screen').height;
const ListComp = () => {
const [data, setData] = useState([])
const loading = useStore(state => state.wordState)
const search = useStore(state => state.search)
const setLoading = useStore(state => state.setWordState)
const setModalVisible = useStore(state => state.setPopupState)
useEffect(() => {
Realm.open({schema:[WordShema]}).then(realm=>{
setData(realm.objects('Words').sorted('date',true))
}).then(()=>{setLoading(false)
setModalVisible(false)})
}, [loading])
useEffect(() => {
Realm.open({schema:[WordShema]}).then(realm=>{
setData(realm.objects('Words').sorted('date',true))
}).then(()=>{
setModalVisible(false)
})
}, [])
useEffect(() => {
Realm.open({schema:[WordShema]}).then(realm=>{
setData(realm.objects('Words').filtered(
'translate CONTAINS[c] "'+search+'" OR name CONTAINS[c] "'+search+'"'
))
}).then(()=>{setLoading(false)
})
}, [search])
return (
<View key='1' style={{height:height-145}}>
<ScrollView overScrollMode="always">
{data.length>0&&
data.map((data,ind)=>{
return(
<MyRow key={ind} data={data} ind={ind} />
)
})
}
</ScrollView>
</View>
)
}
export default ListComp
Bu komponentler içerisinde kullandığımız diğer komponentleri de burada paylaşabilirim.
//MyModal.js
import React from 'react'
import { StyleSheet, Modal, TouchableOpacity } from 'react-native'
import { useStore } from '../state/atom';
import SendComp from './SendComp';
import MyBlur from './MyBlur';
const MyModal = () => {
const visible = useStore(state => state.popupState)
const setVisible = useStore(state => state.setPopupState)
const setSelectedData = useStore(state => state.setSelectedWordState)
return (
<Modal
animationType='slide'
transparent={true}
visible={visible}
>
<MyBlur/>
<TouchableOpacity style={styles.view} onPress={()=>{
setVisible(false)
setSelectedData({})}}>
<SendComp isSend={false} />
</TouchableOpacity>
</Modal>
)
}
export default MyModal
const styles = StyleSheet.create({
view:{
width:'100%',
height:'100%',
alignItems:'center',
justifyContent:'center',
alignSelf:'center',
borderRadius:10
}
})
//MyRow.js
import React, {useEffect} from 'react'
import { Dimensions, StyleSheet, Text, View, TouchableOpacity } from 'react-native'
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
import { WordShema } from '../common/Shema';
import { useStore } from '../state/atom';
import MyModal from './MyModal';
const width=Dimensions.get('screen').width;
const padding=20
Icon.loadFont()
const MyRow = ({data,ind}) => {
const setModalVisible = useStore(state => state.setPopupState)
const setLoading = useStore(state => state.setWordState)
const selectedData = useStore(state => state.selectedWordState)
const setSelectedData =useStore(state => state.setSelectedWordState)
const deleter = ()=>{
Realm.open({schema:[WordShema]}).then(realm=>{
realm.write(() => {
let obj = realm.objects('Words').filtered("id='"+data.id+"'");
realm.delete(obj)
setLoading(true)
})
})
}
useEffect(() => {
if(selectedData.name!=undefined){
setModalVisible(true)
}
}, [selectedData])
return (
<TouchableOpacity key={ind} style={styles.container} onPress={()=>setSelectedData(data)} >
<MyModal/>
<View style={styles.info} >
<View style={styles.data}>
<Text style={styles.text}>
{data.name}({data.pronunciation})
</Text>
<Text style={styles.text}>
{data.translate}
</Text>
</View>
<Text style={styles.description}>
{data.description}
</Text>
</View>
<TouchableOpacity onPress={()=>deleter()} style={styles.icon}>
<Icon name="delete" size={30} color="red" />
</TouchableOpacity>
</TouchableOpacity>
)
}
export default MyRow
const styles = StyleSheet.create({
container:{
padding:padding/2,
width:width-padding,
alignSelf:'center',
margin:4,
borderRadius:5,
backgroundColor:'#ffffff60',
flexDirection:'row',
shadowColor:'black',
shadowOpacity:0.2,
shadowRadius:1,
shadowOffset:{width: -1, height: 3},
},
info:{
flex:1,
justifyContent:'space-between'
},
data:{
flexDirection:'row',
justifyContent:'space-between'
},
text:{
textAlign:'center',
padding:2,
color:'white',
fontSize:20,
fontWeight:'900',
textShadowColor:'black',
textShadowRadius:5,
textShadowOffset:{width: 0, height: 0},
},
icon:{
alignItems:'center',
justifyContent:'center'
},
description:{
color:'white',
fontSize:14,
fontWeight:'900',
textShadowColor:'black',
textShadowRadius:5,
textShadowOffset:{width: 0, height: 0},
}
})
evet artık
npx react-native run-ios
ya da
npx react-native run-android
diyerek uygulamamızı ayağa kaldırabiliriz. Tebrik ederim 🙂
İlk blog yazım olduğu için hatalarım olduysa affola 🙂
React native ile mobil uygulama geliştirme üzerine daha fazla bu tip uygulama geliştirme yazıları eklemeye devam edeceğim takipte kalın 🙂 Sağlıkla kalın..