使用PouchDB和CouchDB在React Native中构建离线应用程序

使用PouchDB和CouchDB在React Native中构建离线应用程序

以下是使用PouchDB 和 CouchDB 在 React Native 中构建离线第一个应用程序的示例。 在这个例子中我们将看到什么是离线优先方法? 为什么选择 PouchDB 和 CouchDB? 如何使用离线优先方法在 React Native 中开发任何应用程序?

什么是“线下优先”方法?

“离线优先”的概念非常简单,目标是您的应用程序始终能够完美运行,无论在线还是离线。 在这种方法中,数据将被下载到用户的设备,然后应用程序将访问数据,一旦修改数据,应用程序就会将其存储回设备数据库,然后发送到服务器。 因此,简单来说,不是将应用程序直接连接到服务器应用程序,而是将数据存储在离线数据库中并将数据同步到服务器。

“线下优先”的方法有问题吗?

理论上离线优先的概念非常好,但构建相同的应用程序是一个有点复杂的过程。

  1. 如何将数据从服务器同步到本地数据库?
  2. 将本地数据同步回服务器怎么样,谁能完美地做到这一点?
  3. 如果其他人更新了您在离线模式下更新的相同记录怎么办,谁来解决冲突?
  4. 如何反映实时变化(例如,您的Facebook帖子的点赞/评论计数)

还有很多其他问题可能会让您处于不同的状态,从而在没有适当解决方案的情况下忽略此方法。

如何实现“线下优先”?

如果我们谈论临时解决方案,那么我们可以使用任何本地数据库和服务器 API 创建相同的应用程序。 您只需管理记录的同步标志,这将帮助您识别该数据是否正在同步,并且每当您创建/更新/删除任何记录时,您都必须将该同步标志标记为 false,以便可以下次同步。 正如我提到的,这只是一个临时解决方案,因为您还必须管理同步触发器和网络状态。

我个人使用临时解决方案创建了此类应用程序,但在一段时间后,当您有大量事务时,您会感到性能问题,并且在发生冲突时会感到数据丢失。 为了解决临时解决方案的问题,我一直在寻找完美的解决方案,然后我找到了 PouchDB-CouchDB 来解决问题。

PouchDB 是为了帮助开发人员构建在离线模式下与在线模式下工作相同的应用程序。 Pouch db 标语说 The Database that Syncs!.同步的数据库!。 它使应用程序能够在离线状态下将数据存储在本地,然后与 CouchDB数据库 当应用程序重新上线时,兼容的服务器使用户的数据保持同步,无论他们下次登录在哪里。

什么是 PouchDB?

PouchDB 是一个用 JavaScript 编写的开源浏览器内数据库 API。 它是一个 JavaScript 实现CouchDB数据库。 它的目标是以近乎完美的保真度模拟 CouchDB API。 使用它,我们可以构建离线和在线工作的应用程序。 PouchDB内部使用WebSQL和IndexedDB来存储数据。 然后,会自动将数据同步到 Apache CouchDB,这又是一个 NoSQL 数据库。

什么是 CouchDB?

CouchDB 是由 Damien Katz 于 2005 年创建的 NoSQL 数据库,现在由 Apache 软件基金会维护。 如果您是一名 JavaScript 开发人员,您可能每天都会使用 CouchDB,因为它是驱动的核心技术 新项目管理

CouchDB 让您的数据在服务器集群、手机和 Web 浏览器之间无缝流动,从而实现引人注目的离线优先用户体验,同时保持高性能和强大的可靠性。

如今,有两家主要数据库公司的血统可以追溯到 CouchDB: 与 CouchDB 相比,它们都是独立的产品。 然而,这些数据库共享相同的 CouchDB 同步协议。 这意味着 PouchDB 可以与其中任何一个同步,并且您始终可以将一个数据库替换为另一个数据库。

为什么选择 CouchDB?

有如此多的 SQL 和 NoSQL 数据库(MongoDB、PostgreSQL、MySQL 等),您可能想知道为什么我们选择实现 CouchDB 而不是其他数据库。

对于这个问题,我们有两个很好的答案: HTTP协议同步

  1. HTTP协议:在使用数据库时,我们通常习惯于在数据库和客户端应用程序之间编写某种转换层。 然而,这意味着我们只是一遍又一遍地将数据库查询转换为 RESTful HTTP 调用。 对于我们编写的每个应用程序。
    CouchDB 鼓励我们从客户端应用程序直接与数据库对话,从而将这一点抛到了九霄云外。 它通过使用 HTTP 作为主要通信方式来实现这一点。 没有特殊的协议,没有特殊的驱动程序:只有 REST 和 HTTP。 您可以完全通过浏览器、curl 或 Postman 等 REST 客户端与 CouchDB 进行通信。
  2. 同步:CouchDB 的另一个独特功能是它是自下而上设计的,可以轻松实现不同数据库之间的同步。
    例如,如果您担心客户端应用程序的延迟,您可以简单地在欧洲设置一个 CouchDB,在北美设置另一个,在亚洲设置另一个。 在这些数据库之间启用连续双向复制后,您的客户可以简单地与距离较近的数据库进行通信。

CouchDB 的安装

我们将在下面看到 PouchDB 设置和应用程序开发,但在此之前让我们设置我们的 CouchDB。

首先从其下载 CouchDB 官方网站。 安装它并在浏览器中点击 URL。

http://127.0.0.1:5984/_utils/

这将打开一个名为 Futon 的界面。 这是 CouchDB 的内置接口。 如果系统要求您设置密码,请进行相应处理。 请记住您设置的用户名和密码,因为我们在将 PouchDB 与 CouchDB 连接时需要使用该用户名和密码进行身份验证。现在通过单击创建数据库 创建数据库 右上角的按钮,并给出数据库的名称。
存储在 CouchDB 中的数据称为 文件 和用途 _ID 作为每个文档的唯一标识符。 您可以在创建记录时提供自己的_id,也可以将其保留在 couchDB 上,以便为每个文档生成唯一的哈希值。

如果一切正常,那么您的 CouchDB 数据库就准备好了。 现在让我们使用 PouchDB 创建一个应用程序,它将数据同步到此 CouchDB。

PouchDB 和 CouchDB 示例说明

在此示例中,我们将使用 PouchDb 构建一个完整的离线第一个应用程序,该应用程序将与本地主机(端口:5984)上运行的 CouchDB 数据库同步。 在应用程序中我们将有一个 主屏幕 有以下选项

  • 注册用户:注册用户(创建/插入记录)
  • 查看所有用户:查看所有用户(获取所有记录)
  • 查看用户:按Id查看单个用户(获取单条记录,过滤)
  • 更新用户:更新用户(更新记录)
  • 删除用户:删除用户(删除记录)
  • 实时记录添加/删除:在单个屏幕中添加/删除功能以查看实时更新

我们将有一些自定义组件,例如 我的按钮, 我的文本, 我的文本输入 它将用来代替react-native Button、Text 和 TextInput。 我们将会有一个 配置文件 文件还具有与 CouchDB 连接相关的配置,您可以根据需要进行更改。

制作 React Native 应用程序

React Native 入门将帮助您更多地了解如何制作 React Native 项目。 我们将使用 React Native 命令行界面来制作我们的 React Native 应用程序。

如果您之前安装了全局的react-native-cli软件包,请将其删除,因为它可能会导致意外问题:

npm uninstall -g react-native-cli @react-native-community/cli

运行以下命令创建一个新的 React Native 项目

npx react-native init ProjectName

如果你想使用特定的 React Native 版本启动一个新项目,你可以使用 –version 参数:

npx react-native init ProjectName --version X.XX.X

注意如果上述命令失败,您可能使用的是旧版本 react-native 或者 react-native-cli 在您的电脑上全局安装。 尝试卸载 cli 并使用 npx 运行 cli。

这将在项目目录中创建一个带有名为 App.js 的索引文件的项目结构。

安装依赖项

要安装依赖项,请打开终端并跳入您的项目

cd ProjectName

1. 安装 pouchdb-react-native 使用依赖 PouchDB

npm install pouchdb-react-native --save

2. 安装 pouchdb-authentication 使用依赖 邮袋认证 用于身份验证

npm install pouchdb-authentication --save

3. 安装以下依赖项 react-navigation

npm install @react-navigation/native --save
npm install @react-navigation/stack --save
npm install react-native-reanimated react-native-gesture-handler react-native-screens react-native-safe-area-context @react-native-community/masked-view --save

4. 对于阵列操作安装 洛达什

npm install lodash --save

这些命令会将所有依赖项复制到您的 node_module 目录中。

CocoaPods 安装

请使用以下命令安装 CocoaPods

cd ios && pod install && cd ..

项目结构

请创建以下项目结构并复制下面给出的代码

使用 PouchDB 和 CouchDB 构建 React Native 应用程序的代码

打开项目目录,替换以下代码

应用程序.js

// Building Offline First App in React Native using PouchDB and CouchDB
// https://aboutreact.com/react-native-offline-app-using-pouchdb-couchdb/

import 'react-native-gesture-handler';

import React from 'react';
import {NavigationContainer} from '@react-navigation/native';
import {createStackNavigator} from '@react-navigation/stack';

import HomeScreen from './pages/HomeScreen';
import RegisterUser from './pages/RegisterUser';
import UpdateUser from './pages/UpdateUser';
import ViewUser from './pages/ViewUser';
import ViewAllUser from './pages/ViewAllUser';
import DeleteUser from './pages/DeleteUser';
import RealTimeAddUpdateUser from './pages/RealTimeAddUpdateUser';

const Stack = createStackNavigator();

const App = () => {
  return (
    <NavigationContainer>
      <Stack.Navigator initialRouteName="HomeScreen">
        <Stack.Screen
          name="HomeScreen"
          component={HomeScreen}
          options={{
            title: 'Home', //Set Header Title
            headerStyle: {
              backgroundColor: '#009999', //Set Header color
            },
            headerTintColor: '#fff', //Set Header text color
            headerTitleStyle: {
              fontWeight: 'bold', //Set Header text style
            },
          }}
        />
        <Stack.Screen
          name="View"
          component={ViewUser}
          options={{
            title: 'View User', //Set Header Title
            headerStyle: {
              backgroundColor: '#009999', //Set Header color
            },
            headerTintColor: '#fff', //Set Header text color
            headerTitleStyle: {
              fontWeight: 'bold', //Set Header text style
            },
          }}
        />
        <Stack.Screen
          name="ViewAll"
          component={ViewAllUser}
          options={{
            title: 'View Users', //Set Header Title
            headerStyle: {
              backgroundColor: '#009999', //Set Header color
            },
            headerTintColor: '#fff', //Set Header text color
            headerTitleStyle: {
              fontWeight: 'bold', //Set Header text style
            },
          }}
        />
        <Stack.Screen
          name="Update"
          component={UpdateUser}
          options={{
            title: 'Update User', //Set Header Title
            headerStyle: {
              backgroundColor: '#009999', //Set Header color
            },
            headerTintColor: '#fff', //Set Header text color
            headerTitleStyle: {
              fontWeight: 'bold', //Set Header text style
            },
          }}
        />
        <Stack.Screen
          name="Register"
          component={RegisterUser}
          options={{
            title: 'Register User', //Set Header Title
            headerStyle: {
              backgroundColor: '#009999', //Set Header color
            },
            headerTintColor: '#fff', //Set Header text color
            headerTitleStyle: {
              fontWeight: 'bold', //Set Header text style
            },
          }}
        />
        <Stack.Screen
          name="Delete"
          component={DeleteUser}
          options={{
            title: 'Delete User', //Set Header Title
            headerStyle: {
              backgroundColor: '#009999', //Set Header color
            },
            headerTintColor: '#fff', //Set Header text color
            headerTitleStyle: {
              fontWeight: 'bold', //Set Header text style
            },
          }}
        />
        <Stack.Screen
          name="RealTimeAddUpdate"
          component={RealTimeAddUpdateUser}
          options={{
            title: 'RealTime Add/Update User', //Set Header Title
            headerStyle: {
              backgroundColor: '#009999', //Set Header color
            },
            headerTintColor: '#fff', //Set Header text color
            headerTitleStyle: {
              fontWeight: 'bold', //Set Header text style
            },
          }}
        />
      </Stack.Navigator>
    </NavigationContainer>
  );
};

export default App;

页面/组件/Mybutton.js

// Building Offline First App in React Native using PouchDB and CouchDB
// https://aboutreact.com/react-native-offline-app-using-pouchdb-couchdb/
// Custom Button

import React from 'react';
import {TouchableOpacity, Text, StyleSheet} from 'react-native';

const Mybutton = (props) => {
  return (
    <TouchableOpacity
      style={styles.button}
      onPress={props.customClick}>
      <Text style={styles.text}>{props.title}</Text>
    </TouchableOpacity>
  );
};

const styles = StyleSheet.create({
  button: {
    alignItems: 'center',
    backgroundColor: '#009999',
    color: '#ffffff',
    padding: 10,
    marginTop: 16,
  },
  text: {
    color: 'white',
    fontWeight: 'bold',
  },
});

export default Mybutton;

页面/组件/Mytext.js

// Building Offline First App in React Native using PouchDB and CouchDB
// https://aboutreact.com/react-native-offline-app-using-pouchdb-couchdb/
// Custom Text

import React from 'react';
import {Text, StyleSheet} from 'react-native';

const Mytext = (props) => {
  return <Text style={styles.text}>{props.text}</Text>;
};

const styles = StyleSheet.create({
  text: {
    color: '#111825',
    fontSize: 18,
    marginTop: 16,
    marginLeft: 35,
    marginRight: 35,
    textAlign: 'center',
  },
});

export default Mytext;

页面/组件/Mytextinput.js

// Building Offline First App in React Native using PouchDB and CouchDB
// https://aboutreact.com/react-native-offline-app-using-pouchdb-couchdb/
// Custom TextInput

import React from 'react';
import {View, TextInput} from 'react-native';

const Mytextinput = (props) => {
  return (
    <View
      style={{
        marginTop: 10,
        borderColor: '#007FFF',
        borderWidth: 1,
      }}>
      <TextInput
        underlineColorAndroid="transparent"
        placeholder={props.placeholder}
        placeholderTextColor="#007FFF"
        keyboardType={props.keyboardType}
        onChangeText={props.onChangeText}
        returnKeyType={props.returnKeyType}
        numberOfLines={props.numberOfLines}
        multiline={props.multiline}
        onSubmitEditing={props.onSubmitEditing}
        style={props.style}
        blurOnSubmit={false}
        value={props.value}
      />
    </View>
  );
};

export default Mytextinput;

页面/config.js

  1. 如有任何变更 沙发数据库网址 请更新 remoteDB URL(以下代码中的 http://localhost:5984/)
  2. 更新 用户名(管理员)和 密码( admin ) 您在设置 CouchDB 时创建的
  3. 更新CouchDB URL中的数据库名称,下面的代码文档中是我存储记录的数据库,您可以将其替换为您自己的数据库
// Building Offline First App in React Native using PouchDB and CouchDB
// https://aboutreact.com/react-native-offline-app-using-pouchdb-couchdb/

import PouchDB from 'pouchdb-react-native';
import PouchAuth from 'pouchdb-authentication';

const localDB = new PouchDB('docs');
// Please update the CouchDB URL in case of any change
// Here "/docs" is the my database name
// You can change it with your own database name
const remoteDB = new PouchDB(
  'http://localhost:5984/docs',
  {skip_setup: true}
);
PouchDB.plugin(PouchAuth);

const syncStates = (
  'change',
  'paused',
  'active',
  'denied',
  'complete',
  'error',
);
// Please update the username and password of the couchDB
remoteDB.login('admin', 'admin').then(function () {
  const sync = localDB.sync(remoteDB, {
    live: true,
    retry: true,
  });
  syncStates.forEach((state) => {
    sync.on(state, setCurrentState.bind(this, state));
    function setCurrentState(state) {
      console.log('(Sync:' + state + ')');
    }
  });
});

export default localDB;

页面/RealTimeAddUpdateUser.js

// Building Offline First App in React Native using PouchDB and CouchDB
// https://aboutreact.com/react-native-offline-app-using-pouchdb-couchdb/

import React, {useState, useEffect} from 'react';
import {
  SafeAreaView,
  StyleSheet,
  View,
  Text,
  ScrollView,
  TextInput,
} from 'react-native';

import _ from 'lodash';
import Mybutton from './components/Mybutton';
import db from './config';

const RealTimeAddUpdateUser = () => {
  let (docs, setDocs) = useState(());
  let (inputDoc, setInputDoc) = useState('');

  useEffect(() => {
    db.allDocs({include_docs: true})
      .then((results) => {
        let temp = results.rows.map((row) => row.doc);
        setDocs(temp);
        addLiveUpdateListner();
      })
      .catch((err) => {
        alert('Error in fetching data: ', err);
        addLiveUpdateListner();
      });
  }, ());

  const addLiveUpdateListner = () => {
    db.changes({
      live: true,
      include_docs: true,
      ascending: true,
    })
      .on('change', (change) => {
        // console.log('(Change:Change)', change);
        let doc = change.doc;
        if (!doc) return;
        if (doc._deleted) {
          console.log('delete doc => ', doc);
          removeDoc(doc);
        } else {
          console.log('add doc => ', doc);
          addDoc(doc);
        }
      })
      .on(
        'complete',
        console.log.bind(console, '(Change:Complete)')
      )
      .on(
        'error',
        console.log.bind(console, '(Change:Error)')
      );
  };

  const addDoc = (newDoc) => {
    setDocs((docs) => {
      if (!_.find(docs, {_id: newDoc._id})) {
        return docs.concat(newDoc);
      } else {
        return docs.map((item) => (
          item._id === newDoc._id ? newDoc : item
        ));
      }
    });
  };

  const removeDoc = (oldDoc) => {
    setDocs((docs) => docs.filter(
      (doc) => doc._id !== oldDoc._id)
    );
  };

  const onDocSubmit = () => {
    db.post({name: inputDoc, contact: '', address: ''})
      .then((doc) => {
        console.log('doc', doc);
        if (!doc.ok) {
          alert('Insertion Failed');
          return;
        }
        setInputDoc('');
      })
      .catch((error) => alert('Error Inserting -> ' + error));
  };

  const onDocRemove = (oldDoc) => {
    db.remove(oldDoc)
      .then((doc) => {
        console.log('doc', doc);
        if (!doc.ok) {
          alert('Removal Failed');
          return;
        }
      })
      .catch((error) => alert('Error -> ' + error));
  };

  const renderDoc = (doc, index) => {
    return (
      <View
        style={{
          padding: 16,
          marginVertical: 10,
          backgroundColor: 'white',
          borderColor: '#E8E8E8',
          borderWidth: 1,
          borderBottomColor: '#D4D4D4',
          borderBottomWidth: 1,
          borderRadius: 2,
        }}
        key={index}>
        <Text>Id: {doc._id}</Text>
        <Text>Name: {doc.name}</Text>
        <Text>Contact: {doc.contact}</Text>
        <Text>Address: {doc.address}</Text>
        <Mybutton
          title="Remove"
          customClick={() => onDocRemove(doc)}
        />
      </View>
    );
  };

  return (
    <SafeAreaView style={{flex: 1}}>
      <View style={{flex: 1, padding: 16}}>
        <View style={{flexDirection: 'row'}}>
          <TextInput
            style={{
              flex: 1,
              borderColor: 'black',
              height: 40,
              borderWidth: 0.5,
              marginTop: 14,
              backgroundColor: 'white',
              padding: 10,
            }}
            placeholder="Enter Name"
            onChangeText={(inputDoc) => setInputDoc(inputDoc)}
            value={inputDoc}
          />
          <Mybutton
            title="Submit"
            customClick={onDocSubmit}
          />
        </View>
        <ScrollView>
          {docs.map((doc, index) => renderDoc(doc, index))}
        </ScrollView>
      </View>
    </SafeAreaView>
  );
};

const styles = StyleSheet.create({
  //containerForm
  containerForm: {
    paddingLeft: 10,
    paddingRight: 10,
    paddingBottom: 10,
    marginTop: 40,
    backgroundColor: '#EEEEEE',
  },

  //containerStatus
  containerStatus: {
    backgroundColor: 'red',
    height: 20,
    marginBottom: 20,
    borderRadius: 20,
  },

  //Status Text
  statusText: {
    color: 'white',
    flexDirection: 'row',
    textAlign: 'center',
  },

  //containerList
  containerList: {
    paddingLeft: 10,
    paddingRight: 10,
  },

  //Separator - Add form/List
  separator: {
    height: 0,
    backgroundColor: 'aliceblue',
  },
});

export default RealTimeAddUpdateUser;

页面/HomeScreen.js

// Building Offline First App in React Native using PouchDB and CouchDB
// https://aboutreact.com/react-native-offline-app-using-pouchdb-couchdb/

import { gt } from 'lodash';
import React from 'react';
import {View, Text, SafeAreaView} from 'react-native';
import Mybutton from './components/Mybutton';
import Mytext from './components/Mytext';
import db from './config';

const HomeScreen = ({navigation}) => {
  return (
    <SafeAreaView style={{flex: 1}}>
      <View
        style={{
          flex: 1,
          backgroundColor: 'white',
          padding: 16
        }}>
        <View style={{flex: 1}}>
          <Mytext
            text="Offline First App in React Native
                  using PouchDB and CouchDB"
          />
          <Mybutton
            title="Register User (Add Data)"
            customClick={() => navigation.navigate('Register')}
          />
          <Mybutton
            title="Update User (Update Data)"
            customClick={() => navigation.navigate('Update')}
          />
          <Mybutton
            title="View User (Get Single Record, filtered)"
            customClick={() => navigation.navigate('View')}
          />
          <Mybutton
            title="View All (Get All Records)"
            customClick={() => navigation.navigate('ViewAll')}
          />
          <Mybutton
            title="Delete (Delete Single Record)"
            customClick={() => navigation.navigate('Delete')}
          />
          <Mybutton
            title="RealTime Record Add/Remove"
            customClick={() =>
              navigation.navigate('RealTimeAddUpdate')
            }
          />
        </View>
        <Text
          style={{
            fontSize: 18,
            textAlign: 'center',
            color: 'grey'
          }}>
          Offline First App in React Native{' '}
          using PouchDB and CouchDB
        </Text>
        <Text
          style={{
            fontSize: 16,
            textAlign: 'center',
            color: 'grey'
          }}>
          www.aboutreact.com
        </Text>
      </View>
    </SafeAreaView>
  );
};

export default HomeScreen;

页面/RegisterUser.js

// Building Offline First App in React Native using PouchDB and CouchDB
// https://aboutreact.com/react-native-offline-app-using-pouchdb-couchdb/
// Screen to register the user

import React, {useEffect, useState} from 'react';
import {
  View,
  ScrollView,
  KeyboardAvoidingView,
  Alert,
  SafeAreaView,
  Text,
} from 'react-native';
import Mytextinput from './components/Mytextinput';
import Mybutton from './components/Mybutton';
import db from './config';

const RegisterUser = ({navigation}) => {
  let (userName, setUserName) = useState('');
  let (userContact, setUserContact) = useState('');
  let (userAddress, setUserAddress) = useState('');
  let nextId = 1;

  useEffect(() => {
    db.allDocs({include_docs: true}).then((results) => {
      console.log(results);
      nextId = results.total_rows + 1;
      console.log('nextId', nextId);
    });
  }, ());

  let register_user = () => {
    console.log(userName, userContact, userAddress);

    if (!userName) {
      alert('Please fill name');
      return;
    }
    if (!userContact) {
      alert('Please fill Contact Number');
      return;
    }
    if (!userAddress) {
      alert('Please fill Address');
      return;
    }

    db.post({
      name: userName,
      contact: userContact,
      address: userAddress,
    })
      .then((doc) => {
        console.log('doc', doc);
        if (!doc.ok) {
          alert('Registration Failed');
          return;
        }
        Alert.alert(
          'Success',
          'You are Registered Successfully',
          (
            {
              text: 'Ok',
              onPress: () => navigation.navigate('HomeScreen'),
            },
          ),
          {cancelable: false},
        );
      })
      .catch((error) => alert('Error Inserting -> ' + error));
  };

  return (
    <SafeAreaView style={{flex: 1}}>
      <View style={{flex: 1, backgroundColor: 'white', padding: 16}}>
        <View style={{flex: 1}}>
          <ScrollView keyboardShouldPersistTaps="handled">
            <KeyboardAvoidingView
              behavior="padding"
              style={{flex: 1, justifyContent: 'space-between'}}>
              <Mytextinput
                placeholder="Enter Name"
                onChangeText={
                  (userName) => setUserName(userName)
                }
                style={{padding: 10}}
              />
              <Mytextinput
                placeholder="Enter Contact No"
                onChangeText={
                  (userContact) => setUserContact(userContact)
                }
                maxLength={10}
                keyboardType="numeric"
                style={{padding: 10}}
              />
              <Mytextinput
                placeholder="Enter Address"
                onChangeText={
                  (userAddress) => setUserAddress(userAddress)
                }
                maxLength={225}
                numberOfLines={5}
                multiline={true}
                style={{textAlignVertical: 'top', padding: 10}}
              />
              <Mybutton title="Submit" customClick={register_user} />
            </KeyboardAvoidingView>
          </ScrollView>
        </View>
        <Text
          style={{
            fontSize: 18,
            textAlign: 'center',
            color: 'grey'
          }}>
          Offline First App in React Native{' '}
          using PouchDB and CouchDB
        </Text>
        <Text
          style={{
            fontSize: 16,
            textAlign: 'center',
            color: 'grey'
          }}>
          www.aboutreact.com
        </Text>
      </View>
    </SafeAreaView>
  );
};

export default RegisterUser;

页面/UpdateUser.js

// Building Offline First App in React Native using PouchDB and CouchDB
// https://aboutreact.com/react-native-offline-app-using-pouchdb-couchdb/
// Screen to update the user

import React, {useState} from 'react';
import {
  View,
  ScrollView,
  KeyboardAvoidingView,
  Alert,
  SafeAreaView,
  Text,
} from 'react-native';
import Mytextinput from './components/Mytextinput';
import Mybutton from './components/Mybutton';
import db from './config';

const UpdateUser = ({navigation}) => {
  let (inputUserId, setInputUserId) = useState('');
  let (userName, setUserName) = useState('');
  let (userContact, setUserContact) = useState('');
  let (userAddress, setUserAddress) = useState('');

  let updateAllStates = (name, contact, address) => {
    setUserName(name);
    setUserContact(contact);
    setUserAddress(address);
  };

  let searchUser = () => {
    console.log(inputUserId);
    db.get(inputUserId)
      .then((doc) => {
        console.log(doc);
        updateAllStates(doc.name, doc.contact, doc.address);
      })
      .catch((err) => {
        alert('No user found');
        updateAllStates('', '', '');
      });
  };
  let updateUser = () => {
    console.log(inputUserId, userName, userContact, userAddress);

    if (!inputUserId) {
      alert('Please fill User id');
      return;
    }
    if (!userName) {
      alert('Please fill name');
      return;
    }
    if (!userContact) {
      alert('Please fill Contact Number');
      return;
    }
    if (!userAddress) {
      alert('Please fill Address');
      return;
    }

    db.post({
      // You can also set current date for the complex unique id
      // _id: Date.now().toString(),
      name: userName,
      contact: userContact,
      address: userAddress,
    })
      .then((doc) => {
        console.log('doc', doc);
        if (!doc.ok) {
          alert('Registration Failed');
          return;
        }
        Alert.alert(
          'Success',
          'User updated successfully',
          (
            {
              text: 'Ok',
              onPress: () => navigation.navigate('HomeScreen'),
            },
          ),
          {cancelable: false},
        );
      })
      .catch((error) => alert('Updation Failed -> ' + error));
  };

  return (
    <SafeAreaView style={{flex: 1}}>
      <View style={{flex: 1, backgroundColor: 'white', padding: 16}}>
        <View style={{flex: 1}}>
          <ScrollView keyboardShouldPersistTaps="handled">
            <KeyboardAvoidingView
              behavior="padding"
              style={{flex: 1, justifyContent: 'space-between'}}>
              <Mytextinput
                placeholder="Enter User Id"
                style={{padding: 10}}
                onChangeText={
                  (inputUserId) => setInputUserId(inputUserId)
                }
              />
              <Mybutton
                title="Search User"
                customClick={searchUser}
              />
              <Mytextinput
                placeholder="Enter Name"
                value={userName}
                style={{padding: 10}}
                onChangeText={
                  (userName) => setUserName(userName)
                }
              />
              <Mytextinput
                placeholder="Enter Contact No"
                value={'' + userContact}
                onChangeText={
                  (userContact) => setUserContact(userContact)
                }
                maxLength={10}
                style={{padding: 10}}
                keyboardType="numeric"
              />
              <Mytextinput
                value={userAddress}
                placeholder="Enter Address"
                onChangeText={
                  (userAddress) => setUserAddress(userAddress)
                }
                maxLength={225}
                numberOfLines={5}
                multiline={true}
                style={{textAlignVertical: 'top', padding: 10}}
              />
              <Mybutton
                title="Update User"
                customClick={updateUser}
              />
            </KeyboardAvoidingView>
          </ScrollView>
        </View>
        <Text
          style={{
            fontSize: 18,
            textAlign: 'center',
            color: 'grey'
          }}>
          Offline First App in React Native{' '}
          using PouchDB and CouchDB
        </Text>
        <Text
          style={{
            fontSize: 16,
            textAlign: 'center',
            color: 'grey'
          }}>
          www.aboutreact.com
        </Text>
      </View>
    </SafeAreaView>
  );
};

export default UpdateUser;

页面/ViewAllUser.js

// Building Offline First App in React Native using PouchDB and CouchDB
// https://aboutreact.com/react-native-offline-app-using-pouchdb-couchdb/
// Screen to view all the user*/

import React, {useState, useEffect} from 'react';
import {FlatList, Text, View, SafeAreaView} from 'react-native';
import db from './config';

const ViewAllUser = () => {
  let (flatListItems, setFlatListItems) = useState(());

  useEffect(() => {
    db.allDocs({include_docs: true, descending: true})
      .then((results) => {
        let temp = results.rows.map((row) => row.doc);
        console.log('temp', temp);
        setFlatListItems(temp);
      })
      .catch((err) => alert('Unable to get data'));
  }, ());

  let listViewItemSeparator = () => {
    return <View style={{height: 20}} />;
  };

  let listItemView = (item) => {
    return (
      <View
        key={item._id}
        style={{
          backgroundColor: 'white',
          padding: 16,
        }}>
        <Text>Id: {item._id}</Text>
        <Text>Name: {item.name}</Text>
        <Text>Contact: {item.contact}</Text>
        <Text>Address: {item.address}</Text>
      </View>
    );
  };

  return (
    <SafeAreaView style={{flex: 1}}>
      <View style={{flex: 1, padding: 16}}>
        <FlatList
          data={flatListItems}
          ItemSeparatorComponent={listViewItemSeparator}
          keyExtractor={(item, index) => index.toString()}
          renderItem={({item}) => listItemView(item)}
        />
      </View>
    </SafeAreaView>
  );
};

export default ViewAllUser;

查看用户.js

// Building Offline First App in React Native using PouchDB and CouchDB
// https://aboutreact.com/react-native-offline-app-using-pouchdb-couchdb/
// Screen to view single user

import React, {useState} from 'react';
import {Text, View, SafeAreaView} from 'react-native';
import Mytextinput from './components/Mytextinput';
import Mybutton from './components/Mybutton';
import db from './config';

const ViewUser = () => {
  let (inputUserId, setInputUserId) = useState('');
  let (userData, setUserData) = useState({});

  let searchUser = () => {
    console.log(inputUserId);
    setUserData({});
    db.get(inputUserId)
      .then((doc) => {
        console.log(doc);
        setUserData(doc);
      })
      .catch((err) => {
        alert('No user found');
        updateAllStates('', '', '');
      });
  };

  return (
    <SafeAreaView style={{flex: 1}}>
      <View style={{flex: 1, backgroundColor: 'white', padding: 16}}>
        <View style={{flex: 1}}>
          <Mytextinput
            placeholder="Enter User Id"
            onChangeText={
              (inputUserId) => setInputUserId(inputUserId)
            }
            style={{padding: 10}}
          />
          <Mybutton title="Search User" customClick={searchUser} />
          <View style={{marginTop: 16}}>
            <Text>User Id: {userData._id}</Text>
            <Text>User Name: {userData.name}</Text>
            <Text>User Contact: {userData.contact}</Text>
            <Text>User Address: {userData.address}</Text>
          </View>
        </View>
        <Text
          style={{
            fontSize: 18,
            textAlign: 'center',
            color: 'grey'
          }}>
          Offline First App in React Native{' '}
          using PouchDB and CouchDB
        </Text>
        <Text
          style={{
            fontSize: 16,
            textAlign: 'center',
            color: 'grey'
          }}>
          www.aboutreact.com
        </Text>
      </View>
    </SafeAreaView>
  );
};

export default ViewUser;

页面/DeleteUser.js

// Building Offline First App in React Native using PouchDB and CouchDB
// https://aboutreact.com/react-native-offline-app-using-pouchdb-couchdb/
// Screen to delete the user

import React, {useState} from 'react';
import {Text, View, Alert, SafeAreaView} from 'react-native';
import Mytextinput from './components/Mytextinput';
import Mybutton from './components/Mybutton';
import db from './config';

const DeleteUser = ({navigation}) => {
  let (inputUserId, setInputUserId) = useState('');

  let deleteUser = () => {
    db.get(inputUserId)
      .then((doc) => {
        return db.remove(doc).then((doc) => {
          console.log('doc', doc);
          if (!doc.ok) {
            alert('Deletion Failed');
            return;
          }
          Alert.alert(
            'Success',
            'User Deleted successfully',
            (
              {
                text: 'Ok',
                onPress: () => navigation.navigate('HomeScreen'),
              },
            ),
            {cancelable: false},
          );
        });
      })
      .catch((err) => {
        alert('No user found with inserted id');
      });
  };

  return (
    <SafeAreaView style={{flex: 1}}>
      <View style={{flex: 1, backgroundColor: 'white', padding: 16}}>
        <View style={{flex: 1}}>
          <Mytextinput
            placeholder="Enter User Id"
            onChangeText={
              (inputUserId) => setInputUserId(inputUserId)
            }
            style={{padding: 10}}
          />
          <Mybutton title="Delete User" customClick={deleteUser} />
        </View>
        <Text
          style={{
            fontSize: 18,
            textAlign: 'center',
            color: 'grey'
          }}>
          Offline First App in React Native{' '}
          using PouchDB and CouchDB
        </Text>
        <Text
          style={{
            fontSize: 16,
            textAlign: 'center',
            color: 'grey'
          }}>
          www.aboutreact.com
        </Text>
      </View>
    </SafeAreaView>
  );
};

export default DeleteUser;

运行 React Native 应用程序

再次打开终端并使用跳转到您的项目。

cd ProjectName

1. 启动 Metro Bundler

首先,您需要启动 Metro,React Native 附带的 JavaScript 捆绑器。 要启动 Metro 捆绑程序,请运行以下命令

npx react-native start

一旦您启动 Metro Bundler,它将永远在您的终端上运行,直到您将其关闭。 让 Metro Bundler 在自己的终端中运行。 打开一个新终端并运行该应用程序。

2.启动React Native应用程序

在 Android 虚拟设备或真实调试设备上运行项目

npx react-native run-android

或在 iOS 模拟器上运行(仅限 macOS)

npx react-native run-ios

输出截图

以上是使用PouchDB和CouchDB在 React Native 中构建离线应用程序如果您有任何疑问或想分享有关该主题的内容,您可以在下面发表评论或在此处联系我们。 很快就会有更多帖子发布。 敬请关注!

推荐:ACF扩展插件Advanced Custom Fields Extended PRO


发表评论