React Native – Mobx kullanımı

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)
}