状態管理はReactアプリケーションの中核であり、Reactは単なるUIライブラリであるため、アプリの状態を処理するための何かが必要です。 状態管理は面倒になる可能性があり、状態に一貫性がないため、管理しにくいReactアプリケーションを簡単に作成できます。

この記事では、ReactNativeアプリケーションで状態管理ソリューションとしてMobXを使用する方法について学習します。

状態管理とは何ですか?

State は、アプリが処理しているデータにすぎません。 状態は、コンポーネントに必要なデータを保存し、コンポーネントのレンダリング方法に影響を与えます。 状態管理は、そのデータを管理するプロセスです。 特定のアプリでデータを監視および取得することは困難な場合があり、そこで状態管理ライブラリが役に立ちます。 ReduxやReactContext API を使用するなど、状態を管理する方法は複数ありますが、ここではMobXについて説明します。

MobXとは何ですか?

MobX は、任意のJavaScriptフレームワークで使用できる状態管理ライブラリです。 ReactとMobXは一緒に強力であり、完全なフレームワークとして機能します。 MobXは、ReactNativeがコンポーネントのレンダリングに使用するアプリケーションの状態を保存および更新するメカニズムを提供します。 MobXの背後にある哲学は次のとおりです。*「アプリケーションの状態から派生できるものはすべて、派生する必要があります。 自動的。”*

核心概念

派生はMobXのバックボーンを形成し、繰り返される状態を破棄できるようにします。 アイデアは次のとおりです。

最小限の状態(観察可能な状態)を見つけ、すべてを派生させ(派生状態)、状態をそれ以上の状態に変えないでください。

MobXのコアには、 Observables Actions 、およびReactionsという3つの重要な概念があります。 ストアにはこれら3つが含まれており、ReactNativeアプリケーションによって使用されます。

オブザーバブル

MobXのオブザーバブルは、アプリケーションのコア状態を保持する単なるコンテナーです。 アイデアは、オブザーバーが反応できる新しい変化をオブジェクトが放出できるようにすることです。 あなたはこれを達成することができます @observable デコレータ。
名前の付いた変数があると想像してみましょう count それは時間とともに変化します。 次の方法で簡単に観察できるようになります。

// import observable from mobx
import { observable } from "mobx";

//create a store with count observable
class Store {
  @observable
  count = 0;
}

//export Store
export default new Store();

計算されたオブザーバブル

MobXの原則である*「最小状態(観察可能な状態)を見つけ、すべてを派生させる(派生状態)」*を覚えておいてください。
すでに定義されているオブザーバブルから導出できる値は、計算された値です。 MobXは、より多くの状態の作成を阻止することにより、状態の不整合を回避します。 私たちを想像してみてください count 変数は、何かが遅延する分数を保持します。 追加できます computed オブザーバブルから派生する遅延メッセージ count.

import { observable, computed } from "mobx";

class Store {
  @observable
  count = 0;

  @computed
  get delayMessage = () => {
    return 'The train is delayed by' + this.count;
  };
}

export default new Store();

ここ、 @computed からその値を導出するゲッター関数として機能しています count. delayMessage の値として自動的に変更を送信します count 変更します。

行動

アクションは、単に状態を変更する関数です。 MobXは一方向のデータフローをサポートします。つまり、アクションが状態を変更すると、その状態を消費しているすべてのビューが自動的に更新されます。 追加しましょう action その更新 count 遅延が増加するにつれて変化します。

Store {
import { observable, computed, action } from "mobx";

class Store {
 @observable
  count = 0;

  @computed
  get delayMessage = () => {
    return 'The train is delayed by' + this.count;
  };

  @action
  updateDelay = delay => {
    this.count = delay;
  };
}

export default new Store();

すべての状態の変更は、アクションによってのみ実行する必要があることに注意してください。

反応

オブザーバーは、オブザーバブルの変更をサブスクライブし、それらを使用するコンポーネントを再レンダリングします。 反応は、これらの状態変化の単なる副作用です。 これは計算された値と非常に似ていますが、違いは値を計算して返す代わりに、リアクションが単に副次的な操作を実行することです。 簡単に言うと、リアクションは次のとおりです。

状態の変化に反応して発生するはずの副作用(コンポーネントの再レンダリング)

MobXは、 autorun whenおよびreactionの3つの主要なタイプの反応関数を提供します。

1. 自動実行

autorun 状態が変化するたびに実行される関数です。

autorun(() => {
  console.log('delay is', this.count);
} );

関数は、の値が count 変更します。 重要なのは、変更を監視する必要があることを明示的に述べていないことです。 count 変数。 私たちが使用したという事実 count 自動実行の内部では、それが依存関係の1つになり、依存関係が変更されるたびに関数をトリガーするのに十分です。

2. いつ

when 特定の条件が満たされるたびに副作用を引き起こします。 2つのパラメータを取ります。 最初のパラメーターは、trueを返すまで再評価される関数であり、2番目のパラメーターは、最初の関数がtrueを返すと実行される別の関数です。 簡単な例は次のとおりです。

class MyResource {
  constructor() {
    when(
      // once...
      () => this.count > 60,
      // ... then
      () => console.log("Guest is too late, maybe he's not coming");
    );
  }
}

ここ、 when 遅延が1時間(60分)を超えているかどうかを確認し、彼が来ていない可能性があることを印刷します。

3. 反応

reaction のバリエーションです autorun これにより、関数で使用されるデータ(依存関係)をより細かく制御できます。 2つの関数の引数とオプションの3番目の引数を受け入れます。

  1. 最初の引数(データ関数)はデータの変更を監視し、2番目の引数であるエフェクト関数の入力として使用されるデータを返します。
  2. 2番目の関数は、最初の関数が受け取ったデータを最初の引数として受け入れ、副作用を実行しますが、データ関数が新しい値を返す場合に限ります。 また、実行中に反応を処理するために使用できる2番目の引数を受け取ります。

次の例は、1回だけ呼び出される反応を示しています。

const reactionDemo = reaction(
  () => this.count,
  (count, reaction) => {
    console.log("reaction demo: invoked. delay is " + count);
    reaction.dispose();
  }
);

this.count = 1;
// prints:
// reaction demo: invoked. delay is = 1

this.count = 2;
// prints:
// (There are no logging, because of reaction disposed. But, count continue reaction)

console.log(this.count);
// prints:
// 2

MobXの動作

3つの簡単なステップでReactNativeアプリを作成することで、MobXの動作を理解します。

  1. 状態を定義し、それを観察可能にする
  2. 状態の変化を監視するビューを作成する
  3. アクションを使用して状態を変更する

私たちが構築しているもの

ここでは、画像を取得するシンプルなアプリを作成しています Unsplash そしてそれらをユーザーに表示します。 ユーザーは画像をクリックしてお気に入りに追加することもできます。

アプリケーションはUnsplashAPIを使用してランダムな画像をフェッチします。 ここでAPIキーを生成できます

プロジェクトをまだ作成していない場合は、以下の手順に従ってください。

  1. ReactNativeアプリケーションを作成する
$ react-native init UnsplashDemo

または、Expoを使用します。

$ expo init UnsplashDemo
  1. MobXを追加
$ npm install mobx mobx-react
  1. プロジェクトを実行する
$ react-native run-<your-os>

または、Expoを使用します。

$ expo start

ステップ1。 状態を定義し、それを観察可能にする

いくつかの画像を検索して結果を保存します。 次に、任意の画像をクリックしてお気に入りに追加できるようにします。 コメントは自明です:

// importing observables and decorate
import { decorate, observable, action } from "mobx";

class Store {
  // observable to save search query
  text = '';

  // action to update text
  updateText = (text) => {
    this.text = text;
  }

  // observable to save image response from api
  data = null;

  // action to call API and search images
  searchImages = () => {
    fetch(`https://api.unsplash.com/search/photos?client_id=${API_KEY}&page=1&query=${this.text}&orientation=landscape`)
      .then(response => response.json())
      .then(data => this.setData(data));
  };

  // observables can be modifies by an action only
  setData = (data) => {
    this.data = data;
  };
}

// another way to decorate variables with observable
decorate(Store, {
  text: observable,
  updateText: action,
  data: observable,
  searchImage: action,
  setData: action,
});

// export class
export default new Store();

ステップ2。 状態の変化を監視するビューの作成

コンポーネントを作成する ImageList.js 画像のリストがレンダリングされます。 また、スイッチを切り替えるだけで、お気に入りに追加された画像が表示されます。

  1. ImageListコンポーネントのボイラープレート:
import React from "react";
import { View, TextInput, Button, FlatList } from 'react-native';

// imports inject and observer from 'mobx-react':
import { inject, observer } from "mobx-react";

// components receive Store values as props which we will inject while exporting
function ImageList(props) {
  // destructure variables from store to use 
  const { text, updateText, data, searchImages } = props.store;
  return (
    <>
      <TextInput // TextInput to get search query from user
        style={styles.input} 
        value={text}
        onChangeText={updateText}
      />
      <Button // Button to call API
          title="Search"
          style={styles.button}
          onPress={searchImages}
        />
      />
      <FlatList      
        data={data.results} // response from API
        keyExtractor={(item) => item.id}
        renderItem={({ item }) => (
          <ImageView // reusable component to render image
            source={{ uri: item.urls.small }} // passing the url
            onPress={() => {}} // action to add item to favorite
          />
        )}
      />
    </>
  );
}

// inject Store as props to ImageList and make it observe changes in Store
export default inject("store")(observer(ImageList));

からの入力を取得しています TextInput を押してUnsplash検索APIを呼び出す Button. 応答はに保存されています data 観察可能であり、私たちはそれを FlatList 画像のリストをレンダリングするコンポーネント。 簡単ですよね? それでは、お気に入りに画像を追加することに移りましょう。

Unsplash API応答の詳細については、unsplash.com/developersにアクセスしてください。

ステップ3。 アクションを使用した状態の変更

ご存知のように、アクションは状態の変更を担当します。これまでのところ、 updateText 変異した text 観察可能で setData 変異した data 観察可能。 次に、画像を追加します favorites、これは、状態を格納するための1つのオブザーバブルと、この状態を変更するための1つのアクションが必要であることを意味します。 それらを追加しましょう。

import { decorate, observable, action } from "mobx";

class Store {
  text = '';
  updateText = (text) => {...};

  data = null;
  searchImages = () => {...};

  setData = (data) => {...};

  // array to save favourite images
  favorites = [];

  // action to add images to favorites
  addToFavorite = (image) => {
    this.favorites.push(image);
    this.data = null;
    this.text = '';
  };
}

decorate(Store, {
  text: observable,
  updateText: action,
  data: observable,
  searchImage: action,
  setData: action,
  //adding decorators
  favorites: observable,
  addToFavorite: action,
});

export default new Store();

次に、これらの追加されたオブザーバブルとアクションのビューを更新します。 以前に検索した画像をクリアして、追加したお気に入りの画像を表示したいのですが、これは次の方法で簡単に実行できます。

// previous destructuring
const { favorite, addToFavorite} = this.props.store
return (
  <>
  {/* TextInput and Button added earlier */}
  {/* If data is available then show search results otherwise show the favorite images */}
  {data ?
    <FlatList // To render list of images
      style={styles.container}
      data={data.results}
      keyExtractor={(item) => item.id}
      renderItem={({ item }) => (
        <ImageView
          source={{ uri: item.urls.small }}
          onPress={() => addToFavorite(item.urls.small)} // action to add url to favorite
        />
      )}
    /> :
    <FlatList
      style={styles.container}
      data={favorites}
      keyExtractor={(item, index) => index.toString()}
      renderItem={({ item }) => (
        <ImageView
          source={{ uri: item }} // render favorite images
        />
      )}
    />
  }
  </>
);

使用しました observers, observablesactions これまでのところ。 追加しましょう computed お気に入りに追加された画像の数を表示します。 computed オブザーバブルから派生状態を取得するゲッター関数のように機能します。 次のように追加できます。

import { decorate, observable, action, computed } from "mobx";

class Store {
  // previously added value
  get getFavoriteCount() {
    return this.favorites.length;
  }
}

decorate(Store, {
  // previously added values
  getFavoriteCount: computed,
});

export default new Store();

ビューにもすばやく追加しましょう。

const { getFavoriteCount } = this.props.store;

return (
  // TextInput, Button
  <Text style={styles.count}>
    Images added: {getFavoriteCount}
  </Text>
  // FlatList
);

今、私たちがしなければならない最後のことは提供することです storeProvider ルートコンポーネントに。 ルートファイルは次のようになります。

import React from 'react';
import ImageList from './src/container/ImageList';

// imports Provider and store
import { Provider } from 'mobx-react';
import store from './src/store';

const App = () => {
  return (
    <Provider store={store}>
      <ImageList />
    </Provider>
  );
};

export default App;

それでおしまい。 私たちのアプリのGIFが実際に動作しているのを見てみましょう:


私たちはについて学びました observables, actions, observers、 と computed MobXのプロパティを使用し、単純なReactNativeアプリを作成してそれらを正常に使用しました。 MobXの学習を楽しんでいただければ幸いです。このチュートリアルは、React Native+MobXの使用を開始するのに役立ちました。 ハッピーコーディング! 👨‍💻