Mobx nedir :
Basitçe bir state yönetim yapısıdır. Örneğin elimizde a verisi var ve bunun değerini b+c oluşturuyor. Ve biz a verisini ekrana render ediyoruz.
Programın belirli biryeride b verisi değişikliğe uğradı diyelim. Eğer Mobx gibi bir state yönetimi kullanıyor ise a verisininde değeri değişecek demektir.
Ve ekranda aldığımız render b verisinin yeni içeriğine göre tekrar dizayn edilecek.
Kulum
npm install mobx mobx-react@5.4.3 --save
npm i metro-react-native-babel-preset @babel/preset-flow @babel/plugin-proposal-decorators --save-dev
proje kök dizininde .babelrc isminde bir dosya oluşturup aşağıdaki json veriyi içine yapıştırın.
{ "presets": [ "module:metro-react-native-babel-preset" ], "plugins": [ [ "@babel/plugin-proposal-decorators", { "legacy": true } ] ] }
Basit kullanımı şöyledir
// Store class'ımız import {observable} from 'mobx'; // Gerekli importları yaptık class CounterStore{ @observable count = 1; //observable decorator ile count isminde bir değişken tanımladık decrement = () => { Değer arttırma fonksiyonu yazdık this.count--; } increment = () => { this.count++; } } export default new CounterStore() //Ana sayfamız
import React, { Component } from 'react'; import { StyleSheet, Text, View, Button } from 'react-native'; import {observer} from 'mobx-react'; // mobx için gerekli importu yaptık import CounterStore from '../store/CounterStore'; // storumuzu sayfaya dahil ettik @observer // storumuzda tanımlı observable değişkenlerimizin değerlerini anlık olarak çekebilmek için class'ımızın başına bu dekoratoru ekledik export default class Counter extends Component { render() { return ( <View> <Text style={styles.text}>{CounterStore.count}</Text> <View style={styles.buttonContainer}> <Button title={"decrement"} onPress={() => CounterStore.decrement()} /> <Button title={"increment"} onPress={() => CounterStore.increment()} /> </View> </View> ); } } const styles = StyleSheet.create({ text: { fontSize: 38, textAlign: 'center' }, buttonContainer: { flexDirection: 'row' } });
Yukarıdaki kodları uygulayıp butona bastığımızda storeda değişen değerin anında ekrana yansıdığını görebilirsiniz.
@action, @computed dekoratörleri nedir ne işe yarar ?
Action dekoratörü kullanmazsak her satır kod değişikliğinde tek tek değişiklikler store tarafında işlenirken mobx bilgilendirilir.
Ve bu da bizim hızlı UI tasarlamamızı engelleyebilir. Bunun yerine store’da oluşturduğumuz fonksiyonlarımızın başına @action dekoratörü ekleyerek tüm işlem bittikten sonra mobx’i bilgilendirebiliriz. Örnek kullanımı aşağıdadır.
Computed dekoratörü ise verileri bir fonksiyon dan return etmek için kullanılır.
import {observable, action, configure } from 'mobx'; configure({ enforceActions:"observed" // Bunu yazma amacımız @action dekoratorunu kullanmayı zorunlu hale getirmel istediğimiz için }) class CounterStore{ @observable count = 1; @action decrement = () => { this.count--; } @action increment = () => { this.count++; } @computed get fullName(){ return `${this.firstname} ${this.surname}` } } export default new CounterStore()
Ana computed dekoratörü kullandıktan sonra ana sayfamızda bulunan
<Text style={styles.text}>{CounterStore.count}</Text> // Kod bloğunu
<Text style={styles.text}>{CounterStore.lastCount}</Text> //ile değiştirebiliriz
autorun nedir ?
autorun fonksiyonu uygulama ilk çalıştığında çalışıp içindeki kodları icra eder. Sonrasında store da herhangi bir zamanda bir state değişimi olduğunda tekrar çalışır.
Örnek kullanımı aşağıdaki gibidir
// sayfanın en başında import edilmlei import {autorun} from 'mobx' constructor(){ autorun(() => { alert(this.count) }) }
reaction nedir ?
Örnek olarak store içindeki değişkenlerin belli bir değere geldiğinde bir işlem yapmak istiyoruz. Ve bunu kontrol etmek için karmaşık yapılar kullanmak yerine reaction kullanabiliriz.
Örnek kullanımı aşağıdaki gibidir
// count değişkenimiz her 5 e eşit olduğunda alert alacağız // constructor içerisine tanımlamalıyız. reaction( () => this.count, count => { if (count === 5) { alert("Başardın") } } )
when nedir ?
When reaction ile benzer yapıdadır. Tek farkı yaptığımız tanımlama için sadece 1 kez çalışır. Yani aşağıdaki örnekte count ilk kez 5 olduğunda çalışır, ama ikinci kez 5 olduğunda çalışmaz.
//constructor içinde kullanmalıyız when( () => this.count === 5, () => alert("Başardın!") )
Storları Provider ve inject ile birlikte kullanmak.
Açıklamayı kod içinde bulabilirsiniz.
Counter stor dosyamız
import {observable, action, autorun, reaction, when} from 'mobx'; class CounterStore{ @observable count = 1; @action decrement = () => { this.count--; } @action increment = () => { this.count++; } } export default new CounterStore() //Class'ı dışarı aktardık
Store index dosyamız import CounterStore from './CounterStore';//Tüm storları import ettik export default{ CounterStore // Tüm storları dışarı aktardık }
import React, {Component} from 'react'; import {StyleSheet, Text, View} from 'react-native'; import {Provider} from 'mobx-react'; // Provider için gerekli importu yaptık import store from './src/store'; // Yukarıda src/store klasöründe index.js dosyasının içinde tüm storlarımızı çektik import Counter from './src/components/Counter'; export default class App extends Component { render() { return ( <Provider {...store}> //Burada {...store } diyerek tüm storlarımızı Provider'a tanımlamış olduk <View style={styles.container}> <Person /> </View> </Provider> ); } } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#F5FCFF', } });
Counter screen dosyamız
import React, { Component } from 'react'; import { StyleSheet, Text, View, Button } from 'react-native'; import {observer, inject} from 'mobx-react'; // Burada bizim provider'a eklediğimiz storları sayfamıza eklemeye yarayacak fonksiyonumuzu import ediyoruz => inject @inject('CounterStore') // Burada CounterStore u sayfamıza inject ettik @observer export default class Counter extends Component { render() { const { CounterStore, PersonStore} = this.props; // Ve counterStoru props dan çekip aynı isimli değişkene aktardık. return ( <View> <Text style={styles.text}>{CounterStore.count}</Text> <View style={styles.buttonContainer}> <Button title={"decrement"} onPress={() => CounterStore.decrement()} /> <Button title={"increment"} onPress={() => CounterStore.increment()} /> </View> <Text style={{ textAlign:'center'}}>{PersonStore.fullName}</Text> <Button title={"change the name"} onPress={() => PersonStore.changeName()} /> </View> ); } } const styles = StyleSheet.create({ text: { fontSize: 38, textAlign: 'center' }, buttonContainer: { flexDirection: 'row' } });
runInAction nedir ?
enforceActions:”observed” olarak ayarladığımızda bütün değişiklikleri @action dekoratörü olan fonksiyonlarda yapmaya zorluyorduk kodumuzu.
Mesela @action olan bir fonksiyonun içinde setTimeout çalıştıramayız hata alırız. Çünkü biz bütün değişikliklerin sadece ve sadece @action dekoratörü ile başlayan fonksiyonlarda yapılacağını belirttik.
Bunun önüne geçip örnek olarak setTimeout kullanmak istersek bunu runInAction ile kullanmalıyız.
Örneği aşağıdaki gibidir.
//runInAction yukarıda mobx den import edilmelidir @action changeName(){ setTimeout(() => { runInAction(() => { this.firstname = "Mehmet"; this.surname = "Seven"; }) }, 2000) }