Intermediate React and Firebase Tutorial - Build an Evernote Clone

Intermediate React and Firebase Tutorial - Build an Evernote Clone

Intermediate React and Firebase Tutorial - Build an Evernote Clone: In this intermediate React.js tutorial, we create a clone of the popular note-taking application Evernote. This app will allow us to create notes with a full text editor, and update live to a database using Firebase.

In this intermediate React.js tutorial, we create a clone of the popular note-taking application Evernote. This app will allow us to create notes with a full text editor, and update live to a database using Firebase.

Thanks for watching

If you liked this post, share it with all of your programming buddies!

Follow us on Facebook | Twitter

Further reading about React, Redux and Django

React - The Complete Guide (incl Hooks, React Router, Redux)

Modern React with Redux [2019 Update]

Best 50 React Interview Questions for Frontend Developers in 2019

Learn React - Full Course for Beginners - React Tutorial 2019

React (without Redux) - JWT Authentication Tutorial & Example

React vs Angular vs Vue.js by Example

MERN Stack Tutorial - Build a MERN App From Scratch ❤

State Management with React Hooks

💻 Code: https://github.com/Zackazt/evernote-clone

How to Use Algolia with Firebase Angular Apps

How to Use Algolia with Firebase Angular Apps

Algolia is a super powerful, scalable API service that allows developers to send different forms of data into their platform and quickly perform search, sort and complex filter queries on top of it.

What is Algolia?

Algolia is a super powerful, scalable API service that allows developers to send different forms of data into their platform and quickly perform search, sort and complex filter queries on top of it. The service is incredibly fast, by using replica indexes to pre-build common query conditions to send your data back as quick as possible.

Why use Algolia with Firebase?

Firebase has come a long way in terms of its accessibility with querying data structures, especially in Firestore. Even with these advancements, it has limitations and often time requires pre-sorted data, using Firebase’s syntax sugar with push ids (push ids contain a date hash in their generation) and sacrificing extra reads/writes and straight forward object structure. Firebase also officially recommends Algolia for performing full-text search operations in Firestore.

Getting Started

In this working example, we will be using Firebase Cloud Functions with triggers to help assist with syncing data changes from Firestore over to Algolia. We will also be using the Algolia Node.JS and JavaScript client module for interacting with their service.

Firebase Cloud Functions

In your functions directory you will need to install the following dependencies to leverage Algolia.

npm install --save algoliasearch @types/algoliasearch

For this example we will listen for whenever a new user document is created, updated or deleted in our custom Firestore collection “users”.

For each of the below examples you will need to replace appId and apiKey with your own access tokens generated through Algolia’s admin panel.

user.onCreate.ts

The userOnCreate trigger is dispatched every time a new document is created in the users collection. In the example below we initialize Algolia with our app’s id and unique API key and initialize the index we want to use in Algolia. Algolia recommends naming your index by the instance/environment you are working with (i.e. dev_, prod_, staging_, next_).

We are also replicating to indexes so that we can sort by the user’s name in either ascending or descending order. Algolia reserves objectID for correlating records in their world; we will use the new document’s path id.

import * as algoliasearch from 'algoliasearch';
import * as functions from 'firebase-functions';

export const userOnCreate = functions.firestore
.document('users/{id}')
.onCreate(async (change, context) => {
const user = change.data();
const client = algoliasearch('appId', 'apiKey');
const index = client.initIndex('dev_users');
await index.setSettings({
replicas: [
'dev_users_name_desc',
'dev_users_name_asc'
]
});
return index.addObject({
objectID: change.id,
...user
});
});

user.onUpdate.ts

The userOnUpdate trigger is very similar to the create trigger. The difference is that we do not need to re-specify the replica indexes since once we register them; they will automatically push data over to the replica indexes any time we write to the parent index (dev_users).

To reduce the operation cost, Algolia allows partial updates to only change specific properties on an index’s object.

import * as algoliasearch from 'algoliasearch';
import * as functions from 'firebase-functions';

export const userOnUpdate = functions.firestore
.document('users/{id}')
.onCreate(async (change, context) => {
const user = change.data();
const client = algoliasearch('appId', 'apiKey');
const index = client.initIndex('dev_users');
return index.partialUpdateObject({
objectID: change.id,
...user
});
});

user.onDelete.ts

The userOnDelete trigger is the simplest operation with an initialize and delete object call to remove the Algolia object by the objectID we defined earlier.

import * as algoliasearch from 'algoliasearch';
import * as functions from 'firebase-functions';

export const userOnDelete = functions.firestore
.document('users/{id}')
.onCreate(async (change, context) => {
const client = algoliasearch('appId', 'apiKey');
const index = client.initIndex('dev_users');
return index.deleteObject(change.id);
});

Export all of these constants to your root index.ts file. This will register them as new Firebase Cloud Functions when you build and deploy. At this point any time you change documents in Firestore (either directly through the Firebase Console or with your app) it will trigger these functions to push and sync data across to Algolia.

firebase deploy --only functions:userOnCreate,functions:userOnUpdate,functions:userOnDelete
Application Side
You can store Algolia’s search-only access token (this is different than the apiKey used in Cloud Functions) in your environments file to easily access/import it.

Create a simple service to easily interact with your Algolia indexes.

user.service.ts

import * as algoliasearch from 'algoliasearch';

@Injectable()
export class UserService {

client: algoliasearch.Client;

init(config: {
appId: string,
apiKey: string
}) {
this.client = algoliasearch('appId', 'apiKey');
}

fetchUsers(options: algoliasearch.QueryParameters) {
const userSearch = this.client.initIndex('dev_users');
return userSearch.search(options);
}

fetchUsersByNameAsc(options: algoliasearch.QueryParameters) {
const userSearch = this.client.initIndex('dev_users_name_asc');
return userSearch.search(options);
}

fetchUsersByNameDesc(options: algoliasearch.QueryParameters) {
const userSearch = this.client.initIndex('dev_users_name_desc');
return userSearch.search(options);
}

}

In your component, provide UserService and make the following method calls to test the response back from Algolia.

async ngOnInit() {
this.init({ appId: 'foo', apiKey: 'bar' });
const res = await this.fetchUsers({
page: 0,
length: 10,
query: 'Sean'
});
console.log('res', res);
}

This method call will attempt to load the first page of results, up to 10 records that has a searchable attribute that matches “Sean”.

Final Thoughts

Without getting too far into the weeds of Algolia’s client and explicitly focusing on syncing data over and quickly logging that information out; we can see that Algolia serves as a powerful interface to receive the exact data we need.

In our implementation on Hive, we use Algolia to handle paginated admin tables, infinite scroll experiences, pre-filtering collection records by specific conditions and sorting table data. You can also leverage Algolia as a read-only database, only storing/syncing documents that the client should have access to. This is powerful when using concepts such as soft deletes, where you stamp a document with a deletedAt timestamp in Firestore and remove the object from Algolia. By doing this, you can always recover the document back, but all querying logic from Algolia will treat the document as being deleted.

Thanks for reading. If you liked this post, share it with all of your programming buddies!

Further reading

☞ Learn and Understand AngularJS

☞ The Complete Angular Course: Beginner to Advanced

☞ Angular Crash Course for Busy Developers


Originally published on medium.com