Skip to content

Instantly share code, notes, and snippets.

@jwheat
Created September 10, 2018 20:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jwheat/54c1a8c8132961755d2b9bc9185c01ad to your computer and use it in GitHub Desktop.
Save jwheat/54c1a8c8132961755d2b9bc9185c01ad to your computer and use it in GitHub Desktop.
React Native PouchDB replication problem
import React, { Component } from "react";
import { StyleSheet, Text, View, TouchableHighlight } from "react-native";
import Header from "../components/Header.js";
import HomeContent from "../components/HomeContent.js";
import Tabs from "../components/Tabs.js";
import config from "../client/config.js";
import SessionsList from "../screens/SessionsList";
import PouchDB from "pouchdb-react-native";
PouchDB.plugin(require("pouchdb-find"));
PouchDB.plugin(require("pouchdb-load"));
PouchDB.plugin(require("pouchdb-adapter-asyncstorage").default);
PouchDB.debug.enable("pouchdb:find");
export default class Home extends Component {
static navigationOptions = {
title: config.client.homeText
};
constructor(props) {
super(props);
this.state = {
localDB: [],
statearray: []
};
var db = new PouchDB("localDB", {
adapter: "asyncstorage",
auto_compaction: true
});
/* Check to see if we've loaded the dump file */
db.get("_local/initial_load_complete")
.catch(
function(err) {
if (err.status !== 404) {
throw err;
}
db.load(config.client.dumpFileURL)
.then(function() {
return db.put({ _id: "_local/initial_load_complete" });
})
.then(function(res) {
db.createIndex({
index: {
fields: ["type", "start_date", "start_time", "title"]
}
});
})
.then(
function() {
console.log("index created");
this.buildStateArray();
}.bind(this)
)
.catch(function(err) {
console.log(err);
});
}.bind(this)
)
.then(function(res) {
db.createIndex({
index: {
fields: ["type", "start_date", "start_time", "title"]
}
}).then(function(res) {
console.log("index created");
db.find({
selector: { type: { $eq: "sessions" } }
}).then(function(result) {
console.log("DEBUG: --- Dump docs from find");
console.log(result.docs);
});
});
})
.then(
function() {
this.buildStateArray();
}.bind(this)
)
.catch(function(err) {
console.log(err);
});
this.localDB = db;
this.remoteDB = new PouchDB(config.client.database);
}
buildStateArray = () => {
/* TODO: Make this a loop */
console.log("DEBUG: ================================");
console.log("DEBUG: BUILD STATE ARRAY");
this.setDocs(config.days[0][1], 1);
this.setDocs(config.days[1][1], 2);
this.setDocs(config.days[2][1], 3);
this.setDocs(config.days[3][1], 4);
console.log("DEBUG: STATE ARRAY BUILT");
console.log("DEBUG: ================================");
};
dumpDB = () => {
return this.localDB.allDocs({ include_docs: true }).then(function(res) {
console.log(res);
});
};
goReplicate = () => {
console.log("DEBUG: goReplicate");
this.localDB.replicate
.from(this.remoteDB, {
filter: function(doc) {
return doc.type === "sessions";
}
})
.on(
"complete",
function() {
console.log("DEBUG: sync completed");
this.refreshData();
}.bind(this)
)
.on("error", function(err) {
console.log("sync ERROR!");
});
};
setDocs = (which_day, state_variable) => {
console.log("DEBUG: ::> setDocs " + which_day + "-----");
/* TODO: remove this block after it is working */
// just for debug to verify all docs are in the database
this.localDB.allDocs({ include_docs: true }).then(function(res) {
console.log(res);
});
this.localDB
.find({
selector: {
$and: [
{ type: { $exists: true } },
{ type: { $eq: "sessions" } },
{ start_time: { $gt: true } },
{ start_date: { $exists: true } },
{ start_date: { $eq: which_day } }
]
}
})
.then(
function(result) {
console.log("DEBUG: Day " + state_variable + " sessions");
let obj = Object.assign({}, this.state.statearray);
if (state_variable === 1) {
obj.dayonedocs = result.docs;
}
if (state_variable === 2) {
obj.daytwodocs = result.docs;
}
if (state_variable === 3) {
obj.daythreedocs = result.docs;
}
if (state_variable === 4) {
obj.dayfourdocs = result.docs;
}
this.setState({
statearray: obj
});
}.bind(this)
)
.catch(function(error) {
console.log("Day " + state_variable + " - error");
console.error(error);
});
};
refreshData() {
this.localDB
.changes({
live: true,
include_docs: true
})
.on("change", this.handleChange.bind(this))
.on("complete", console.log.bind(console, "[Change:Complete]"))
.on("error", console.log.bind(console, "[Change:Error]"));
}
handleChange(change) {
console.log("DEBUG: [Change:Change]", change);
var doc = change.doc;
if (!doc) {
return;
}
//if (doc._deleted) {
// this.removeDoc(doc);
//} else {
this.addOrUpdateDocChanges(doc);
//}
}
addOrUpdateDocChanges(newDoc) {
/* TODO: Deal with this mess for the four days */
let dayOne = [...this.state.statearray["dayonedocs"]];
//let dayTwo = [...this.state.statearray["daytwodocs"]];
//let dayThree = [...this.state.statearray["daythreedocs"]];
//let dayFour = [...this.state.statearray["dayfourdocs"]];
console.log("DEBUG: addOrUpdateDocChanges");
var docs = dayOne;
/* TODO: build a function for this so it can be called for each day */
let index = docs.findIndex(el => el._id === newDoc._id);
console.log(docs);
if (index !== -1) {
console.log("DEBUG: Found it");
docs[index] = {
...docs[index],
title: newDoc.title,
start_date: newDoc.start_date,
start_time: newDoc.start_time,
end_date: newDoc.end_date,
end_time: newDoc.end_time,
instructors: newDoc.instructors,
track: newDoc.track,
room: newDoc.room,
floor: newDoc.floor,
level: newDoc.level,
session_canceled: newDoc.session_canceled
};
let obj = Object.assign({}, this.state.statearray);
obj.dayonedocs = docs;
this.setState({
statearray: obj
});
console.log("DEBUG: after update state");
console.log(this.state.statearray["dayonedocs"]);
} else {
// this item does not exist, contactinate to end of the list
this.setState({
docs: this.state.statearray["dayonedocs"].concat(newDoc)
});
// re-sort the list allowing the new document to pop into the proper place
this.sortState();
}
}
sortState() {
const sortedState = []
.concat(this.state.statearray["dayonedocs"])
.sort((a, b) => a.start_date > b.start_date)
.sort((a, b) => a.start_time > b.start_time);
//.sort((a, b) => a.title > b.title);
let obj = Object.assign({}, this.state.statearray);
obj.dayonedocs = sortedState;
this.setState({
statearray: obj
});
}
render() {
return (
<View style={styles.container}>
<Header displayLogo={true} style={styles.appHeader} />
<HomeContent text={config.client.clientEventName} textStyle="heading" />
<View>
<TouchableHighlight
onPress={() => {
this.goReplicate();
}}
style={styles.evaluateModalButton}
>
<Text style={styles.evaluateModalText}>RELOAD</Text>
</TouchableHighlight>
<TouchableHighlight
onPress={() => {
this.dumpDB();
}}
style={styles.evaluateModalButton}
>
<Text style={styles.evaluateModalText}>DUMP</Text>
</TouchableHighlight>
</View>
<View style={styles.tabContainer}>
<Tabs>
{/* First tab */}
<View
title={config.days[0][0]}
style={styles.content}
navigation={this.props.navigation}
>
<SessionsList
start_date={config.days[0][1]}
docs={this.state.statearray.dayonedocs}
/>
</View>
{/* Second tab */}
<View
title={config.days[1][0]}
style={styles.content}
navigation={this.props.navigation}
>
<SessionsList
start_date={config.days[1][1]}
docs={this.state.statearray.daytwodocs}
/>
</View>
{/* Third tab */}
<View
title={config.days[2][0]}
style={styles.content}
navigation={this.props.navigation}
>
<SessionsList
start_date={config.days[2][1]}
docs={this.state.statearray.daythreedocs}
/>
</View>
{/* Fourth tab */}
<View
title={config.days[3][0]}
style={styles.content}
navigation={this.props.navigation}
>
<SessionsList
start_date={config.days[3][1]}
docs={this.state.statearray.dayfourdocs}
/>
</View>
</Tabs>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
// App container
container: {
flex: 1
},
appHeader: {
//flex: 1,
height: 50
},
tabContainer: {
flex: 6, // Take up all screen
backgroundColor: config.colors.darkPrimary // Background color
},
// Tab content container
content: {
flex: 1, // Take up all available space
justifyContent: "center", // Center vertically
alignItems: "center", // Center horizontally
backgroundColor: config.colors.white // Darker background for content area
},
// Content header
header: {
margin: 10,
color: config.colors.primaryText,
fontFamily: "Avenir",
fontSize: 26
},
// Content text
text: {
marginHorizontal: 20, // Add horizontal margin
color: config.colors.primaryText, // Semi-transparent text
textAlign: "center", // Center
fontFamily: "Avenir",
fontSize: 18
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment