MobX与ReactNative,简化

来自菜鸟教程
跳转至:导航、​搜索

状态管理是任何 React 应用程序的核心,由于 React 只是一个 UI 库,我们需要一些东西来处理我们应用程序的状态。 状态管理可能会变得很麻烦,并且由于状态不一致,很容易创建无法管理的 React 应用程序。

在本文中,我们将了解如何在 React Native 应用程序中使用 MobX 作为我们的状态管理解决方案。

什么是状态管理?

State 只是您的应用正在处理的数据。 状态保存组件所需的数据,并影响组件的呈现方式。 状态管理是管理该数据的过程。 监控和检索特定应用程序中的数据可能很困难,这就是状态管理库的用武之地。 有多种管理状态的方法,例如使用 Redux 或 React Context API,但这里我们将介绍 MobX

什么是 MobX?

MobX 是一个状态管理库,可以与任何 JavaScript 框架一起使用。 React 和 MobX 功能强大,可以作为一个完整的框架运行。 MobX 提供了一种机制来存储和更新 React Native 用来渲染组件的应用程序状态。 MobX 背后的理念是:*“任何可以从应用程序状态衍生出来的东西,都应该衍生出来。 自动地。”*

核心理念

派生构成了 MobX 的主干,使我们能够丢弃重复的状态。 这个想法是:

找到最小状态(可观察状态),派生一切(派生状态),永远不要把状态变成更多状态。

MobX 的核心包含三个重要概念:ObservablesActionsReactions。 一个 Store 包含这三个,然后由 React Native 应用程序使用。

可观察的

MobX 的 Observables 只是保存我们应用程序核心状态的容器。 这个想法是让一个对象能够发出观察者可以做出反应的新变化。 您可以使用 @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();

计算的 Observables

记住 MobX 的原理,*“找到最小状态(可观察状态),导出一切(派生状态)”*.
可以从已经定义的可观察对象中导出的值是计算值。 MobX 通过不鼓励创建更多状态来避免状态不一致。 想象一下我们的 count 变量保存了某事被延迟的分钟数。 我们可以添加从可观察到的 count 派生的 computed 延迟消息。

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 作为一个 getter 函数工作,它的值来自 countdelayMessage 将随着 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 提供了三种主要的反应函数:autorunwhenreaction

1. 自动运行

autorun 只是一个在每次状态改变时运行的函数。

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

每次 count 的值发生变化时,该函数都会运行。 关键是我们没有明确声明它必须观察 count 变量的变化。 我们在 autorun 中使用了 count 的事实使它成为它的依赖项之一,这足以在依赖项发生变化时触发该函数。

2. 什么时候

只要满足特定条件,when 就会触发副作用。 它需要两个参数。 第一个参数是一个函数,它会被重新计算直到它返回 true,第二个参数是另一个函数,一旦第一个函数返回 true,它就会运行。 一个简单的例子可能是:

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

在这里,when 只是检查延迟是否超过一个小时(60 分钟),然后打印他可能不会来。

3. 反应

reactionautorun 的变体,它可以更好地控制函数中使用的数据(依赖性)。 它接受两个函数参数和第三个选项参数:

  1. 第一个参数(数据函数)监视数据的变化并返回用作第二个参数(效果函数)的输入的数据。
  2. 第二个函数接受第一个函数接收到的数据作为第一个参数并执行副作用,但仅当数据函数返回一个新值时。 它还接收第二个参数,可用于在执行期间处理反应。

以下示例显示了仅调用一次的反应。

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 在行动

我们将通过三个简单的步骤创建一个 React Native 应用程序来了解 MobX 的工作原理:

  1. 定义状态并使其可观察
  2. 创建一个观察状态变化的视图
  3. 使用动作修改状态

我们正在建设什么

在这里,我们正在构建一个简单的应用程序,它从 Unsplash 获取图像并将它们显示给用户。 用户还可以单击图像并将其添加到他们的收藏夹中。

该应用程序使用 Unsplash API 来获取随机图像。 您可以在此处 [1] 生成 API 密钥。


如果您尚未创建项目,请按照以下步骤操作:

  1. 创建一个 React Native 应用程序
$ react-native init UnsplashDemo

或者,使用世博会:

$ expo init UnsplashDemo
  1. 添加 MobX
$ npm install mobx mobx-react
  1. 运行项目
$ react-native run-<your-os>

或者,使用世博会:

$ 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 获取输入并通过按 Button 调用 Unsplash 搜索 API。 响应保存在 data 可观察对象中,我们在 FlatList 组件中使用它来呈现图像列表。 很简单,对吧? 现在让我们继续将图像添加到我们的收藏夹。

前往 unsplash.com/developers 了解有关 Unsplash API 响应的更多信息。


步骤 3。 使用操作修改状态

众所周知, 动作负责修改状态。 到目前为止,updateText 改变了 text 可观察对象,setData 改变了 [X151X ] 可观察的。 现在我们想将图像添加到我们的 favorites 中,这意味着我们需要一个 observable 来存储状态和一个动作来改变这个状态。 让我们添加它们。

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

到目前为止,我们已经使用了 observersobservablesactions。 让我们添加一个 computed 来显示添加到收藏夹的图像数量。 computed 像一个 getter 函数一样从 observable 中获取派生状态。 它可以添加为:

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

现在,我们要做的最后一件事是将 Provider 中的 store 提供给根组件。 我们的根文件将如下所示:

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 动图:



我们已经了解了 MobX 中的 observablesactionsobserverscomputed 属性,并通过构建一个简单的 React Native 应用程序成功地使用了它们。 我希望你在学习 MobX 时玩得开心,本教程有助于你开始使用 React Native + MobX。 快乐编码! 👨‍💻