有很多理由考虑构建一个离线优先的React Native应用。你甚至在构建你的应用之前就需要考虑这样做,因为如果你等到你的应用因为缓慢或没有反应而受到批评,可能就太晚了。
但离线优先并不是一个一刀切的解决方案。有几种方法可以实现离线优先,根据你的应用程序的结构,一些方法可以在不改变应用程序的架构的情况下发挥作用,而另一些则不行。在这篇文章中,我们将介绍在React Native中实现离线优先的五种方法。
什么是 "离线优先"?
离线优先是指你构建你的React Native应用,使其能够在有或没有互联网连接的情况下工作。你可以通过各种方式做到这一点,但让我们看看为什么我们要利用离线优先的应用程序。
最明显的原因是,你的应用程序可能会在有间歇性或没有移动电话服务的地方被访问,这就是为什么我首先开始建立一个离线优先的应用程序。我的应用程序因为失去连接而收到负面评论。实施离线优先可以解决这个问题,但使用它还有另一个原因:在本地保存数据的速度更快。
无论你有什么类型的移动连接,都会有延迟,会影响用户体验。通过先在本地保存数据,然后在后台将这些数据同步到服务中,加载指标在用户界面上花费的时间更少,用户可以更快地进入下一个任务。
在你的移动应用中使用离线优先意味着用户无论在3G、4G、5G还是没有连接的情况下,都能得到同样的响应性UI。
实施离线优先的方法
在现有的应用程序中实施离线优先并不容易,但直到我开始深入研究,我才意识到有这么多的选择,甚至比我在这里列出的还要多,因为每个人创建React Native应用程序的方式略有不同。
这篇文章开始是为了研究在现有的React Native应用中实现离线优先。如果你要从头开始做一个应用,这些选项中的任何一个都可能对你有用。如果你正在使用一个现有的应用程序,你可能需要做一些改变。
使用react-native-offline和Redux实现本地优先的功能
我们将讨论的前两种方法都使用Redux来处理本地优先功能。如果你的应用程序的所有部分都使用Redux,并且它连接到远程服务以保存数据,这是有意义的。你不必写同步方法,也不必确保你的本地数据库与你的远程数据库是同一类型。
react-native-offline包是一把瑞士军刀,专门为React Native应用设计的工具。我们希望一个应用能够在离线状态下完成在线状态下的所有工作,并在找到连接时同步变化。
要开始使用 react-native-offline,将 react-native-offline 提供的网络减速器添加到你的根减速器中。
import { createStore, combineReducers } from 'redux';
import { reducer as network } from 'react-native-offline';
const rootReducer = combineReducers({
// ... your other reducers here ...
network,
});
const store = createStore(rootReducer);
export default store;
现在你有两个选择。你可以把ReduxNetworkProvider 作为你的 Redux 提供者的后裔,这样它就可以访问存储,就像这样。
import store from './reduxStore';
import React from 'react';
import { Provider } from 'react-redux';
import { ReduxNetworkProvider } from 'react-native-offline';
const Root = () => (
<Provider store={store}>
<ReduxNetworkProvider>
<App />
</ReduxNetworkProvider>
</Provider>
);
另一个选择是,如果你的应用程序使用Redux sagas,可以从你的根saga ,分叉出networkSaga 。这种方法无需用额外的功能来包装你的组件。
import { all } from 'redux-saga/effects';
import saga1 from './saga1';
import { networkSaga } from 'react-native-offline';
export default function* rootSaga(): Generator<*, *, *> {
yield all([
fork(saga1),
fork(networkSaga, { pingInterval: 30000 }),
]);
}
然后,通过使用react-native-offline提供的Redux中间件,你可以在进行API调用之前确定应用是否在线。如果是在线的,一切功能都是你所期望的。
如果应用处于离线状态,被派发的动作会被存储在一个队列中,一旦应用重新上线,它就可以被重新派发,如果你的手机只在应用运行时离线,这就足够了。
要想在应用启动后没有连接时拥有离线优先的功能,你需要在你的应用中添加redux-persist。这使得它能够将你的应用程序的状态快照存储到设备的内存中,并在应用程序启动时重新补充该状态。
使用 redux-offline 启用离线优先的功能
npmredux-offline包与 react-native-offline 类似,因为它使用 Redux 来处理在线与离线的功能,但做法略有不同。首先,你将redux-offline存储增强器添加到你的根减速器。
import { applyMiddleware, createStore, compose } from 'redux';
import { offline } from '@redux-offline/redux-offline';
import offlineConfig from '@redux-offline/redux-offline/lib/defaults';
const store = createStore(
reducer,
compose(
applyMiddleware(middleware),
offline(offlineConfig)
)
);
接下来,用离线元数据来装饰你的Redux动作。
const saveData = data => ({
type: 'SAVE_DATA',
payload: { data },
meta: {
offline: {
// the network action to execute:
effect: { url: '/api/save-data', method: 'POST', json: { data } },
// action to dispatch when effect succeeds:
commit: { type: 'SAVE_DATA_COMMIT', meta: { data } },
// action to dispatch if network action fails permanently:
rollback: { type: 'SAVE_DATA_ROLLBACK', meta: { data } }
}
}
});
如果一个API调用完成,提交动作将被调用。如果应用程序不在线,redux-offline将等待,直到连接恢复并重新尝试保存任何未提交的数据。
如果行动永久失败,那么将调用回滚行动,这将使应用程序的状态回滚到行动被调用前的状态。在这里,你可以指定当这种情况发生时要调用的动作。例如,通知用户他们的更改没有被保存,一旦他们有网络连接,他们将不得不重新尝试。
Redux-offline默认使用redux-persist,所以你不必担心像在react-native-offline中那样编写你的实现。但是redux-offline也使用不可靠的NetInfo API来检查连接。NetInfo API 假设如果你有一个公共 IP 地址,你就连接到了互联网上,这并不总是如此,因为应用程序可能在收到 IP 地址后失去连接。你可能想用一个方法来取代reduxOfflineConfig 中的detectNetwork 方法来ping你自己的后端,以检查连接情况。
在复杂的、离线优先的React Native应用中使用WatermelonDB
如果你的React Native应用很简单,而且你使用远程服务将数据存储在数据库中,并在整个应用中使用Redux,那么上面两个npm包中的任何一个都可以为你工作。
但对于那些数据密集型的应用,这些方法可能会拖慢你的应用。在没有必要的地方使用Redux,足以造成较慢的加载时间,而且这两个包都需要Redux来处理任何在线和离线的数据。
对于由SQL数据库支持的更复杂的应用程序,WatermelonDB是一个不错的选择。有了WatermelonDB,所有的数据都被保存在本地的SQLite数据库中,并使用一个单独的本地线程进行访问。Watermelon也很懒惰。它只在需要的时候加载数据,所以查询会很快解决。
WatermelonDB只是一个本地数据库,但它也提供了同步原语和同步适配器,你可以用来将本地数据同步到你的远程数据库。为了使用WatermelonDB来同步你的数据,你需要在你的后端创建两个API端点--一个用于推送变化,一个用于拉动变化。你还必须创建你自己的逻辑来决定何时同步这些数据。关于如何工作的更多信息,请查看如何使用WatermelonDB进行离线数据同步。
为数据密集型应用程序使用MongoDB Realm
如果你的数据密集型应用程序使用非关系型数据,那么WatermelonDB可能不是最佳解决方案。MongoDB Realm可能是一个更好的解决方案。Realm数据库是一个本地NoSQL数据库,你可以在你的React Native应用中使用。它可以与MongoDB Atlas集成。
如果你选择使用Realm,那么使用MongoDB Realm React Native SDK创建React Native应用就相对简单。Realm有内置的用户管理,允许用户创建和使用各种认证提供者在不同的设备上进行认证,包括电子邮件/密码、JWT、Facebook、谷歌和苹果。如果你选择将数据同步到托管在云端的MongoDB,该功能也被内置到SDK中。
SQLite和云存储
这是一个很好的选择,适合副业和业余应用。这也是一个简单的方法来制作React Native应用的原型。这是一个非常基本的概念:简单地使用SQLite在本地存储数据,然后使用Dropbox等云服务将数据库同步到云端。
对于SQLite这一块,你要使用react-native-sqlite-storagenpm包。关于这方面的更多细节,请查看这篇关于在React Native中使用SQLite的文章。
下一步是添加DropBox或其他云存储供应商。你将不得不去Dropbox开发者页面创建你的应用程序。然后你将需要创建一个授权DropBox的方法和一个同步数据库文件的方法。
结论
离线优先可以改变用户对你的React Native应用的反应方式,尤其是在网络连接可能不稳定的现场使用。但是没有简单的一刀切的解决方案。
我甚至没有在这篇文章中涵盖所有潜在的解决方案。如果你是从头开始,你可以使用这些选项中的任何一个。然而,对于一个现有的应用程序,除非你已经使用Redux来处理所有的状态,否则你很可能要做一些架构上的改变。编码愉快!
The postCreating an offline-first React Native appappeared first onLogRocket Blog.