<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: EchoEye</title>
    <description>The latest articles on DEV Community by EchoEye (@echoeyecodes).</description>
    <link>https://dev.to/echoeyecodes</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F183288%2F64369592-e6f4-43a3-b134-6b62abc57b66.jpg</url>
      <title>DEV Community: EchoEye</title>
      <link>https://dev.to/echoeyecodes</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/echoeyecodes"/>
    <language>en</language>
    <item>
      <title>Database table structure for different notification events</title>
      <dc:creator>EchoEye</dc:creator>
      <pubDate>Mon, 20 Dec 2021 14:41:52 +0000</pubDate>
      <link>https://dev.to/echoeyecodes/database-table-structure-for-different-notification-events-3lbc</link>
      <guid>https://dev.to/echoeyecodes/database-table-structure-for-different-notification-events-3lbc</guid>
      <description>&lt;p&gt;I set out to build one of my &lt;a href="https://picashot.co"&gt;favorite projects&lt;/a&gt; some time around June, and while I was able to complete it to some extent and successfully launched it, I did face some setbacks while trying to implement certain features in the application. One of the most difficult feature I had to implement was notifications. I spent quite some time trying to figure out how to model this form of data in the database. I am using a relational database (PostgreSQL). The main problem I faced with the notifications model was based on the requirements needed to store notifications in a way that still references certain rows and columns in multiple tables. Here's the explanation in details:&lt;/p&gt;

&lt;p&gt;a. In the database, here's a &lt;code&gt;User&lt;/code&gt; table that contains columns like &lt;em&gt;id(primary key) name, email, profileUrl&lt;/em&gt;, etc&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class User extends Model { }

User.init(
  {
    name: {
      type: DataTypes.STRING,
      allowNull: false,
    },
    bio: {
      type: DataTypes.STRING,
      allowNull: false,
      defaultValue: "Hey there!"
    },
    id: {
      type: DataTypes.UUID,
      allowNull: false,
      primaryKey: true,
      defaultValue: DataTypes.UUIDV4,
      unique: true,
    },
    username: {
      type: DataTypes.TEXT,
      allowNull: false,
      unique: true,
    },
    profile_url: {
      type: DataTypes.STRING,
      allowNull: false,
      defaultValue:
        "https://someimagesite.com/default_image.jpg",
    },
    email: {
      type: DataTypes.TEXT,
      allowNull: false,
      unique: true,
    }
  },
  {
    sequelize: instance,
    modelName: "users",
    tableName: "users",
    timestamps: true,
    createdAt: true,
    updatedAt: true,
  }
);


User.hasMany(Post, {
  foreignKey: "userId",
  foreignKeyConstraint: true,
  constraints: true,
  onUpdate: "CASCADE",
  onDelete: "CASCADE",
});


User.hasMany(Comment, {
  foreignKey: "userId",
  foreignKeyConstraint: true,
  constraints: true,
  onUpdate: "CASCADE",
  onDelete: "CASCADE",
});

Post.belongsTo(User)
Comment.belongsTo(User)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;b. Here's a &lt;code&gt;Post&lt;/code&gt; table that contains columns like &lt;em&gt;id(primary key), content, title, userId, timestamp&lt;/em&gt;. "userId" references a row in the &lt;code&gt;User&lt;/code&gt; table and it represents the author of the posts. It has a foreign key constraints set as "onUpdate: CASCASDE" &amp;amp; "onDelete: CASCADE" on the User table which ensures that when a user row is deleted/updated from the users table, any other references to the row in any table gets updated as well.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Post extends Model { }

Post.init(
  {
    content: {
      type: DataTypes.TEXT,
      allowNull: false,
    },
    id: {
      type: DataTypes.UUID,
      allowNull: false,
      primaryKey: true,
      defaultValue: UUIDV4,
      unique: true,
    },
    userId: {
      type: DataTypes.UUID,
      allowNull: false,
    },
  },
  {
    sequelize: instance,
    modelName: "posts",
    tableName: "posts",
    timestamps: true,
    createdAt: true,
    updatedAt: true,
  }
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, imagine we need to to display a notification to certain users in the following typical format(show picture of notification):&lt;br&gt;
&lt;em&gt;"&lt;a class="mentioned-user" href="https://dev.to/echoeyecodes"&gt;@echoeyecodes&lt;/a&gt; just made a post"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In the sample format above, we can see a couple of references to certain attributes of 2 tables in the database.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a. username of user (User table)&lt;/li&gt;
&lt;li&gt;b. post thumbnail (Post table)&lt;/li&gt;
&lt;li&gt;c. description (Post table)&lt;/li&gt;
&lt;li&gt;d. profile photo of user (User Table)&lt;/li&gt;
&lt;li&gt;e. timestamp (Post table)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To model this as a table in the database for notifications, we'll need the following columns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a. postId&lt;/li&gt;
&lt;li&gt;b. userId&lt;/li&gt;
&lt;li&gt;c. targetUserId (recipient of the notification)
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Notification extends Model {}

Notification.init(
  {
    id: {
      type: DataTypes.UUID,
      allowNull: false,
      primaryKey: true,
      defaultValue: UUIDV4
    },
    postId: {
      type: DataTypes.UUID,
      allowNull: false,
    },
    userId: {
      type: DataTypes.UUID,
      allowNull: false,
    },
    targetUserId: {
      type: DataTypes.UUID,
      allowNull: false,
    },
    isRead: {
        type: DataTypes.BOOLEAN,
        allowNull: false,
        defaultValue: false
    },
  },
  {
    sequelize: instance,
    modelName: "notifications",
    tableName: "notifications",
    timestamps: true,
    createdAt: true,
    updatedAt: true,
  }
);

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now to ensure our data here is consistent with the tables it references and avoid null data, we'll add foreign key constraints --&amp;gt; &lt;code&gt;onUpdate: CASCASDE&lt;/code&gt; &amp;amp; &lt;code&gt;onDelete: CASCADE&lt;/code&gt; to the &lt;code&gt;userId&lt;/code&gt;, and &lt;code&gt;postId&lt;/code&gt; columns to User and Post table&lt;/p&gt;

&lt;p&gt;With this model, we can query for notifications on posts created by a certain user with no issues at all. But the 'gotcha!' in this is that it only works well for post notifications. What about when we need notifications for the following events:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a. when a user mentions another user in the content of a post?&lt;/li&gt;
&lt;li&gt;b. when a user publishes a comment on someone else's post?&lt;/li&gt;
&lt;li&gt;c. when a user mentions another user in a comment/reply&lt;/li&gt;
&lt;li&gt;d. when a user likes a post&lt;/li&gt;
&lt;li&gt;e. when a user likes a comment/reply&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If we analyze these events, you'll notice that each event references certain columns in different tables beyond Post and User. We could go ahead and add more attributes like &lt;em&gt;"commentId", "replyId"&lt;/em&gt; to our notification model to adjust to the requirements for notifications, but that would make our model contain redundant columns, and make it harder to debug or understand. We would also have more than a few null columns for a row that actually only references at most 2 tables.&lt;/p&gt;
&lt;h2&gt;
  
  
  How do we solve this problem?
&lt;/h2&gt;

&lt;p&gt;I looked up for a conventional approach for storing notifications in databases, and found some that didn't exactly solve this specific issue, but gave me insights on how to resolve this. I didn't want to create separate tables for different kinds of notifications, especially when these notifications are expected to be arranged in a chronological order. Well, thanks to this &lt;a href="https://stackoverflow.com/a/29439644"&gt;stackoverflow answer&lt;/a&gt;, I figured that I could have a separate table for notification event-types, e.g (post-likes, comment-likes, post-mentions, comment-mentions etc) and a notification table that holds only generalized attributes for every form of notification. This notification will contain attributes like timestamp, eventId, recepientId since all forms of notification are expected to have these attributes. That was the first step towards the solution. So now we have an events table like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class NotificationEvent extends Model {}

NotificationEvent.init(
  {
    id: {
      type: DataTypes.INTEGER,
      allowNull: false,
      primaryKey: true
    },
    type: {
      type: DataTypes.STRING,
      allowNull: false,
    }
  },
  {
    sequelize: instance,
    modelName: "notification_events",
    tableName: "notification_events",
    timestamps: true,
    createdAt: true,
    updatedAt: true,
  }
);


NotificationEvent.hasMany(Notification, {
    foreignKey: "eventId",
    foreignKeyConstraint: true,
    constraints: true,
    onUpdate: "CASCADE",
    onDelete: "CASCADE",
})

Notification.belongsTo(NotificationEvent, {
  foreignKey: "eventId",
  onDelete: "CASCADE",
  onUpdate: "CASCADE",
  foreignKeyConstraint: true,
  constraints: true
})

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then our revamped notification model would look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Notification extends Model {}

Notification.init(
  {
    id: {
      type: DataTypes.UUID,
      allowNull: false,
      primaryKey: true,
      defaultValue: UUIDV4
    },
    eventId: {
        type: DataTypes.INTEGER,
        allowNull: false
    },
    targetId: {
      type: DataTypes.UUID,
      allowNull: false,
    },
    isRead: {
        type: DataTypes.BOOLEAN,
        allowNull: false,
        defaultValue: false
    },
  },
  {
    sequelize: instance,
    modelName: "notifications",
    tableName: "notifications",
    timestamps: true,
    createdAt: true,
    updatedAt: true,
  }
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Going back to notification format for various events I listed above, I observed a pattern for each event:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;(a) is a form of notification between a User and a Post table. That is pretty straightforward, so we can have a UserPostNotification table that contains the columns "userId" and "postId".&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;(b) is a form of notification between a Comment, and a Post table. So the main attributes needed here would be the commentId, and the postId for the PostCommentNotification table. With these columns we can easily construct our notification message by fetching the related data they reference. You know that a comment would always be from a User, therefore it would have a column called "userId" so we could fetch the user information based on this column to get data like username, and profileUrl. Also, every post has a "userId" attribute that references a certain user, so we could also get the user that owns the post based on this attribute and use it as the recipient of the notification.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We can now have something like &lt;em&gt;@username commented on your post&lt;/em&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;(c) is a form of notification between a User and a Comment table. We can construct our notification message like the image below using only the attributes "userId" and "commentId".&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;(d) is also a form of notification between a User and a Post table. To get a message like the image below, we can obtain the information using the &lt;code&gt;userId&lt;/code&gt; and &lt;code&gt;postId&lt;/code&gt; attributes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;(e) is a form of notification between a "userId" and &lt;code&gt;commentId&lt;/code&gt; and the message like &lt;code&gt;@echoeyecodes liked your comment&lt;/code&gt; could be constructed using these two attributes.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After observing these patterns, I realized I could have a single table for notifications that are between a User &amp;amp; Post, User &amp;amp; Comment, or User &amp;amp; Reply. These tables would have an &lt;code&gt;id&lt;/code&gt; attribute as primary key that references a row in the notifications table as a One-To-One Relationship. So to query all notifications in chronological order with the various attributes from different notification types, we could use an INNER JOIN for the &lt;code&gt;Notification&lt;/code&gt; table and &lt;code&gt;NotificationEvents&lt;/code&gt; Table, plus a LEFT JOIN with the &lt;code&gt;UserPostNotification&lt;/code&gt; table, and &lt;code&gt;PostCommentNotification&lt;/code&gt; table.&lt;/p&gt;

&lt;p&gt;We could also insert an INNER JOIN clause to each of the sub-tables based on the parent tables they share constraints with, without having to re-query for these pieces of information after obtaining the foreignKey attributes since &lt;code&gt;UserPostNotification&lt;/code&gt; would have foreign key constraints between a User and Post (&lt;code&gt;userId&lt;/code&gt;, &lt;code&gt;postId&lt;/code&gt;), &lt;code&gt;PostCommentNotification&lt;/code&gt; would have a foreign key constraints between a Post and Comment &lt;code&gt;userId&lt;/code&gt;, &lt;code&gt;commentId&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;here's how the &lt;code&gt;UserPostNotification&lt;/code&gt; would look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class UserPostNotification extends Model {}

UserPostNotification.init(
  {
    notificationId: {
      type: DataTypes.UUID,
      allowNull: false,
      primaryKey: true,
    },
    sourceId: {
      type: DataTypes.UUID,
      allowNull: false
  },
    referenceId: {
        type: DataTypes.UUID,
        allowNull: false
    },
  },
  {
    sequelize: instance,
    modelName: "user_post_notifications",
    tableName: "user_post_notifications",
    timestamps: true,
    createdAt: true,
    updatedAt: true,
  }
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then the &lt;code&gt;PostCommentNotification&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class PostCommentNotification extends Model {}

PostCommentNotification.init(
  {
    notificationId: {
      type: DataTypes.UUID,
      allowNull: false,
      primaryKey: true,
    },
    sourceId: {
      type: DataTypes.UUID,
      allowNull: false
  },
    referenceId: {
        type: DataTypes.UUID,
        allowNull: false
    },
  },
  {
    sequelize: instance,
    modelName: "post_comment_notifications",
    tableName: "post_comment_notifications",
    timestamps: true,
    createdAt: true,
    updatedAt: true,
  }
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now to query for all notifications available for a particular user, we would query via the notification table and use a left join for various notification types available like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const NOTIFICATION_INCLUDE_OPTIONS : IncludeOptions[] = [{model: User, required: true},
    {model: NotificationEvent, required: true},
    {model: UserPostNotification, include: [{model: User}]},{model: PostCommentNotification, include: [{model: User}, {model: Comment, include: [{model: User}]}]}]


async function getUserNotifications(userId:string(){
   const result = await Promise.all((await Notification.findAll({include: NOTIFICATION_INCLUDE_OPTIONS, where:{targetId: userId}}))
        .filter((item) =&amp;gt; {
//here we filter off notifications with possible all notification type as null. this kind of state cannot possibly exist since every notification object would be of at least one type, but just to be safe, we need this check
            const result = item.get({plain: true}) as NotificationType
            if(!result.user_post_notification &amp;amp;&amp;amp; !result.post_comment_notification){
                return false
            }
            return true
        })
        .map((item) =&amp;gt; formatNotification(item.get({plain: true}))))
        return result
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, we can write a small utility function that constructs the notification message based on the event type for every notification like the one below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;async function formatNotification(instance:NotificationType){
    const type = instance.notification_event.type as NotificationEventType

   if(type == "post_comment"){
     //format notification based on requirements e.g @echoeyecodes commented on your post
   }else if(type == "post_create"){
     //format notification based on requirements e.g @echoeyecodes uploaded a photo
}
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>database</category>
      <category>javascript</category>
      <category>tutorial</category>
      <category>programming</category>
    </item>
    <item>
      <title>Replies are... well, comments too!</title>
      <dc:creator>EchoEye</dc:creator>
      <pubDate>Mon, 13 Dec 2021 14:37:13 +0000</pubDate>
      <link>https://dev.to/echoeyecodes/replies-are-well-comments-too-4639</link>
      <guid>https://dev.to/echoeyecodes/replies-are-well-comments-too-4639</guid>
      <description>&lt;p&gt;Last week, I did a bit of refactoring on &lt;a href="https://picashot.co"&gt;Picashot's web service&lt;/a&gt;, and went through a rethink of how to store comments and replies in the database. I initially had 2 tables for this, a &lt;code&gt;Comment&lt;/code&gt; table and &lt;code&gt;Reply&lt;/code&gt; table. These tables had very similar columns, and the only thing that made them distinct in any way was that the &lt;code&gt;Comment&lt;/code&gt; table had a &lt;code&gt;comment&lt;/code&gt; column that holds the actual text of the comment, while the &lt;code&gt;Reply&lt;/code&gt; table had a &lt;code&gt;reply&lt;/code&gt; column for the reply text, and a &lt;code&gt;columnID&lt;/code&gt; column that references the comment row it replies to.&lt;br&gt;
Here's how the &lt;code&gt;Comment&lt;/code&gt; model looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Comment extends Model { }

Comment.init(
  {
    userId: {
      type: DataTypes.UUID,
      allowNull: false,
    },
    id: {
      type: DataTypes.UUID,
      allowNull: false,
      primaryKey: true,
      unique: true,
    },
    comment: {
      type: DataTypes.TEXT,
      allowNull: false,
    },
    postId: {
      type: DataTypes.UUID,
      allowNull: false,
    },
  },
  {
    sequelize: instance,
    modelName: "comments",
    tableName: "comments",
    timestamps: true,
    createdAt: true,
    updatedAt: true,
  }
);

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and now the &lt;code&gt;Reply&lt;/code&gt; model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Reply extends Model {}

Reply.init(
  {
    userId: {
      type: DataTypes.UUID,
      allowNull: false,
    },
    id: {
      type: DataTypes.UUID,
      allowNull: false,
      primaryKey: true,
      unique: true,
    },
    reply: {
      type: DataTypes.TEXT,
      allowNull: false,
    },
    commentId: {
        type: DataTypes.UUID,
        allowNull: false,
      },
  },
  {
    sequelize: instance,
    modelName: "replies",
    tableName: "replies",
    timestamps: true,
    createdAt: true,
    updatedAt: true,
  }
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What's even more wild is that I had two controllers that performed the same read/write operations for both tables and really wasn't comfortable with how this was designed. Besides the regular controllers for the table, there was a &lt;code&gt;CommentLike&lt;/code&gt; model that stores comments liked by users using the &lt;code&gt;commentId&lt;/code&gt; and &lt;code&gt;userId&lt;/code&gt; column, however this table was only meant for the Comment table. Replies could not be liked, or even replied to because of the rigid design nature I adopted for it months back🤮. The final bit of crazy was where I had two notification models for both tables, &lt;code&gt;CommentNotification&lt;/code&gt; and &lt;code&gt;ReplyNotification&lt;/code&gt;, each referencing rows in both Comment and Reply table. Yes, this also means writing different controller classes that literally did the same thing, besides a few columns that were distinct🤦&lt;/p&gt;

&lt;p&gt;I finally decided to rethink this design approach, and I think what really helped me out here was the way tweets work on twitter. I spent some time using the twitter api for evaluating tweet acitivities, and noticed how tweet response are usually structured. Essentially every comment, or quote made on twitter is a tweet, which means they all have the same common attributes (columns) that describes them. What could probably distinguish a tweet from another is if one tweet is a standalone tweet, or a reply to another tweet, but generally they are all a single entity - A Tweet&lt;/p&gt;

&lt;p&gt;Having this in mind, I realized that every reply to a comment is still essentially a comment, so I could actually store all replies within the comments table. But how would I be able to distinguish a standalone comment from a reply to a comment, since querying for all comments related to a particular post would include the standalone comments and replies, which isn't what we want? For this, I created a junction table called &lt;code&gt;CommentReply&lt;/code&gt; with two columns commentId, and referenceId like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class CommentReply extends Model { }
CommentReply.init(
    {
        commentId: {
            type: DataTypes.UUID,
            allowNull: false,
            primaryKey: true,
            unique: true,
        },
        referenceId: {
            type: DataTypes.UUID,
            allowNull: true,
        },
    },
    {
        sequelize: instance,
        modelName: "comment_replies",
        tableName: "comment_replies",
        timestamps: true,
        createdAt: true,
        updatedAt: true,
    }
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;commentId&lt;/code&gt; column references the comment that is supposed to be a reply, while the &lt;code&gt;referenceId&lt;/code&gt; column references the comment being replied to. So, whenever a reply is made to a certain comment, the reply is stored in the database as a comment, and the &lt;code&gt;id&lt;/code&gt; of this comment (reply) along, with the &lt;code&gt;id&lt;/code&gt; of the comment that's being replied to is stored in a CommentReply.&lt;/p&gt;

&lt;p&gt;Now how do I query for comments that are originally standalone comments, not replies. The idea is to query for every comment within the database, and perform a left join with the &lt;code&gt;CommentReply&lt;/code&gt; table.  A "left join" would include null columns in the query results for comments that do not have references in the &lt;code&gt;commentId&lt;/code&gt; column of the &lt;code&gt;CommentReply&lt;/code&gt; table. So rows with null &lt;code&gt;commentId&lt;/code&gt; column represents original standalone comments, while the non-null &lt;code&gt;columnID&lt;/code&gt; rows are replies. So based on this ideology, we can query for standalone comments, or just comments that are replies to a certain comment  Here's how I performed the query in the comment controller class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  async getComments({ postId, limit, offset, userId, commentId }: GetShotParams &amp;amp; { shotId: string, commentId: string | null }) {

    /* if query contains commentId, fetch all comments referenced by that id
    else, fetch comments that do not have a row in the replies. Note that: Standalone
    comment ids can never have a row in the columnId for commentReplies, but references so this works!
    */

    const where: WhereOptions = commentId ? { shotId, '$comment_reply."referenceId"$': commentId } : { postId, '$comment_reply."commentId"$': null }

    const comments = (await Comment.findAll({ where, order: [['createdAt', "DESC"]], limit, offset, include: COMMENT_INCLUDE_OPTIONS }))
    return comments
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What makes this even better is that replies also get to have likes, or even nested replies just like "original comments" which wasn't available in the first design. This recursive sequence just keeps going on and on without adding an extra line of code to the controller, making it more flexible than the initial approach.&lt;/p&gt;

&lt;p&gt;After implementing this, I was able to migrate every reply from the &lt;code&gt;Reply&lt;/code&gt; table to the &lt;code&gt;Comment&lt;/code&gt; table, and severe all ties to it😁 Now, I get to delete the reply table, its controllers, and including the notification model that is associated with this table. Damnn that's really a lot of code😵 I think the best part of refactoring code is where you get to delete a number of lines of code that really are just garbage😅&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>programming</category>
      <category>node</category>
      <category>database</category>
    </item>
    <item>
      <title>Creating uneven grids with FlexboxLayoutManager  on android</title>
      <dc:creator>EchoEye</dc:creator>
      <pubDate>Mon, 06 Dec 2021 11:54:34 +0000</pubDate>
      <link>https://dev.to/echoeyecodes/creating-uneven-grids-with-flexboxlayoutmanager-on-android-351o</link>
      <guid>https://dev.to/echoeyecodes/creating-uneven-grids-with-flexboxlayoutmanager-on-android-351o</guid>
      <description>&lt;p&gt;I was looking through the DeviantArt android application for features I could implement in my &lt;a href="https://picashot.co/" rel="noopener noreferrer"&gt;latest project&lt;/a&gt; that could be useful to have in the mobile application, and came across this layout format I liked a lot. As you can see in the image below, the images are arranged in a grid-like form, but each image has different sizes based on their aspect ratio.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh61v5gxmyxsvahmonbb9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh61v5gxmyxsvahmonbb9.png" alt="Deviantart application screenshot"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I initially tried using a workaround with the GridLayoutManager android provides, but that didn't work as expected because this layout wouldn't allow feed items to fill up extra spaces that might be available during positioning.&lt;/p&gt;

&lt;p&gt;Turns out the answer was in the FlexboxLayoutManager - A layout manager based off of CSS' flex box. I've used this quite a number of times for basic layout, especially the "wrap" feature, but never had a use case for something specific like DeviantArt's. I set out to implement this layout manager, but of course it didn't come off as easy as I thought it would. The problem I had at first was that I couldn't control the maximum number of columns that should be displayed on a single row before wrapping, so all hundreds of images were arranged on a single row. Crazy right?😅&lt;/p&gt;

&lt;p&gt;Anyway I did a bit of research here and there for how to achieve this form of layout in CSS Flexbox since the layout manager is based on this. A few minutes later, I came across this post on &lt;a href="https://stackoverflow.com/a/50592638/9781233" rel="noopener noreferrer"&gt;stackoverflow&lt;/a&gt; about setting the min-width and max-width of each flex item, then allowing the default behavior of these flex items to fill up remaining space with the flex-grow property set to 1. I applied this concept on the FlexboxLayoutManager in android, and I'm glad I was able to finally achieve the same results with DeviantArt😄&lt;/p&gt;

&lt;p&gt;Here's how I implemented it on android; since the sizes of the various images to be rendered is based on the aspect ratio, I would return 3 different view-types based on this faactor. The viewTypes are PORTRAIT, LANDSCAPE, and SQUARE. So in the &lt;code&gt;getItemViewType()&lt;/code&gt; method of the RecyclerView adapter, this check is performed to determine the view type to be used as here:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

override fun getItemViewType(position: Int): Int {
        val item = getItem(position)
        return if (item.width &amp;gt; item.height) {
            LANDSCAPE
        } else if (item.width &amp;lt; item.height) {
            PORTRAIT
        } else {
            SQUARE
        }
    }


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now that this is available, the minimum and maximum possible width and height would be determined in the &lt;code&gt;onCreateViewHolder()&lt;/code&gt; and these values would be different based on the view types:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ShotFlexAdapterViewHolder {
val screenWidth = getScreenSize().width

        val view = LayoutInflater.from(parent.context)
            .inflate(R.layout.layout_shot_list_item, parent, false)

        if (viewType == PORTRAIT) {
            val maximumWidth = (0.5 * screenWidth).toInt()
            val minimumWidth = (0.3 * screenWidth).toInt()
            val minimumHeight = (0.5 * screenWidth).toInt()
            val maximumHeight = (0.6 * screenWidth).toInt()

            view.updateViewLayoutParams(minimumWidth, maximumWidth, minimumHeight, maximumHeight)
        } else if (viewType == LANDSCAPE) {
            val maximumWidth = screenWidth.toInt()
            val minimumWidth = (0.55 * screenWidth).toInt()
            val minimumHeight = (0.5 * screenWidth).toInt()
            val maximumHeight = (0.55 * screenWidth).toInt()

            view.updateViewLayoutParams(minimumWidth, maximumWidth, minimumHeight, maximumHeight)
        } else {
            val maximumWidth = (0.7 * screenWidth).toInt()
            val minimumWidth = (0.4 * screenWidth).toInt()
            val minimumHeight = (0.4 * screenWidth).toInt()
            val maximumHeight = (0.7 * screenWidth).toInt()

            view.updateViewLayoutParams(minimumWidth, maximumWidth, minimumHeight, maximumHeight)
        }

        return ShotFlexAdapterViewHolder(view)
    }


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now the extension function that updates the width and height properties:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

private fun View.updateViewLayoutParams(
        minimumWidth: Int,
        maximumWidth: Int,
        minimumHeight: Int,
        maximumHeight: Int
    ) {
        (this.layoutParams as FlexboxLayoutManager.LayoutParams).apply {
            flexGrow = 1f
            this.width = minimumWidth
            this.height = minimumHeight
            this.maxWidth = maximumWidth
            this.minWidth = minimumWidth
            this.minHeight = minimumHeight
            this.maxHeight = maximumHeight
        }
    }


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Here's an explanation of what is going on above. In order not to overcrop the images that would be displayed, the container width and height holding this image should match the view types i.e portrait images should have a container height greater than the container width, landscape images should have a container width greater than the container height, and square images should have container width and height of equal sizes so that the images to be displayed fits almost* perfectly with the container, and not overcropped.&lt;/p&gt;

&lt;p&gt;Now on top the &lt;code&gt;onCreateViewHolder()&lt;/code&gt;. For portrait images, the container is assigned a minimum width 30% the screen width, complemented with a minimum height of half of the screen width, which is slightly higher than the minimum width. This would be a particularly useful for scenarios that allows a maximum of 3 portrait images to be rendered on a single row before wrapping. Now imagine we've got a portrait image and a landscape image competing for space on a row. Obviously the landscape image would need more width size than the portrait (say 50% of the screen width), and that means lesser spaces would be left for other images.&lt;/p&gt;

&lt;p&gt;For this to work in this case, we can only have a maximum of 1 landscape photo, and the remaining 50% of the screen width would be left to be shared amongst other images. Remember we initially, we defined the minimum width of portrait images to be 30% of the screen width, which means only a maximum of 1 photo can go along with a landscape photo on the same row. The remaining 20% would be shared between these two images since we set the 'flex-grow' property of every item to be 1, i.e stretch to fill the remaining space.&lt;/p&gt;

&lt;p&gt;This analogy would also be applied in cases for landscape and square images. The key lies within using the min/max width and height properties to properly configure how much space each item can be allowed to have on a single row based on their aspect ratio, before wrapping subsequent images to the next row. The min width determines the smallest possible width an item can have on a row, while the maximum width determines the maximum possible width an item should have when stretching, regardless of how much space is left on the row. I hope you find this explanation useful. I'm still recovering from the 'eureka' moment I had after I discovered this layout approach😅 and here's what it looks like on the app&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flwodjk27somunxnhkz68.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flwodjk27somunxnhkz68.png" alt="Picashot Screenshot"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>android</category>
      <category>kotlin</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Why's managing background tasks in react native so difficult?</title>
      <dc:creator>EchoEye</dc:creator>
      <pubDate>Tue, 14 Apr 2020 19:56:48 +0000</pubDate>
      <link>https://dev.to/echoeyecodes/why-s-managing-background-tasks-in-react-native-so-difficult-9h</link>
      <guid>https://dev.to/echoeyecodes/why-s-managing-background-tasks-in-react-native-so-difficult-9h</guid>
      <description>&lt;p&gt;Hello React Native developers! So, According to the official react native docs, the only way to implement background tasks is by using HeadlessJS which only works on android. What's confusing is that popular apps like Instagram, Facebook are built with react native and they definitely handle background tasks on both android and iOS devices pretty well. Since this issue seems resolved, is there a reason why their solution hasn't been released as a package for other react native developers to use and integrate seamlessly into their react native applications. After-all, react native is a product of Facebook and I haven't been able to find a perfectly working solution that works really well on both platforms.&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>reactnative</category>
      <category>react</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Creating an animatable bottom bar with Animated and  React Navigation in React Native</title>
      <dc:creator>EchoEye</dc:creator>
      <pubDate>Sun, 02 Feb 2020 17:08:01 +0000</pubDate>
      <link>https://dev.to/echoeyecodes/creating-an-animatable-bottom-bar-with-animated-and-react-navigation-in-react-native-1pn7</link>
      <guid>https://dev.to/echoeyecodes/creating-an-animatable-bottom-bar-with-animated-and-react-navigation-in-react-native-1pn7</guid>
      <description>&lt;p&gt;This tutorial is essentially to show how you can apply animations to the bottom bar view when you press any of the tab buttons in a react native app. I recently saw a UI design concept illustrating this and with a few tweaks from the docs from react-navigation, I was able to achieve this. Note that you should have prior knowledge of creating basic animations in react native as this is not a tutorial to get started with it. We'll need &lt;em&gt;react-navigation&lt;/em&gt; and &lt;em&gt;react-navigation-tabs&lt;/em&gt; for this project. The full code can be viewed &lt;a href="https://github.com/echoeyecodes/animated-bottom-bar" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's a gif showing what we'll be building:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fokar893ukpf0swoto1y7.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fokar893ukpf0swoto1y7.gif" alt="video"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First we import our necessary files in the &lt;strong&gt;App.js&lt;/strong&gt; file with the following code:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

import React, {useState} from 'react'
import {View, Dimensions, Animated} from 'react-native'
import {createBottomTabNavigator, BottomTabBar} from 'react-navigation-tabs'
import {ScreenOne, ScreenTwo, ScreenThree} from './Screens'


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now we create the respective screens for each navigator item. Create a new file and name it &lt;strong&gt;Screens.js&lt;/strong&gt; and input the following&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

import React from 'react'
import {View, Text, StyleSheet} from 'react-native'
const ScreenOne = () =&amp;gt; {
    return(
        &amp;lt;View style={styles.container}&amp;gt;
        &amp;lt;Text&amp;gt;This is the first screeen&amp;lt;/Text&amp;gt;
        &amp;lt;/View&amp;gt;
    )
}

const ScreenTwo = () =&amp;gt;{
    return(
         &amp;lt;View style={styles.container}&amp;gt;
        &amp;lt;Text&amp;gt;This is the second screeen&amp;lt;/Text&amp;gt;
        &amp;lt;/View&amp;gt;
    )
}

const ScreenThree = () =&amp;gt;{
    return(
         &amp;lt;View style={styles.container}&amp;gt;
        &amp;lt;Text&amp;gt;This is the third screeen&amp;lt;/Text&amp;gt;
        &amp;lt;/View&amp;gt;
    )
}

const styles = StyleSheet.create({
    container:{
        flex: 1,
        backgroundColor: '#fff',
        justifyContent: 'center',
        alignItems: 'center'
    }
})
export {ScreenOne, ScreenTwo, ScreenThree}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Back to our App.js, let's map our respective screens to the bottom tab component. It receives two arguement. An object containing the screens, and the configuration for the bottom tab component We continue the code:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

const bottomComponent = createBottomTabNavigator({
    Home:{
        screen: ScreenOne,
        navigationOptions:{
        tabBarIcon: ({tintColor}) =&amp;gt; &amp;lt;Ionicons name='md-home' color={tintColor} size={24} /&amp;gt;
    }
    },
    Notifications:{
        screen: ScreenTwo,
        navigationOptions:{
        tabBarIcon: ({tintColor}) =&amp;gt; &amp;lt;Ionicons name='md-notifications' color={tintColor} size={24} /&amp;gt;
    }
    },
    Profile:{
        screen: ScreenThree,
        navigationOptions:{
        tabBarIcon: ({tintColor}) =&amp;gt; &amp;lt;Ionicons name='md-person' color={tintColor} size={24} /&amp;gt;
    }
    }
})


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We can customize the look of the bottom bar with the &lt;strong&gt;BottomTabBar&lt;/strong&gt; component imported from &lt;strong&gt;createBottomTabNavigator&lt;/strong&gt;. To do this, we add our we create a configuration object that would be passed to the &lt;strong&gt;createBottomTabNavigator&lt;/strong&gt;. It should look like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

const config= {
    tabBarOptions:{
    activeTintColor: '#fff',
    inactiveTintColor: 'rgba(0,0,0,0.7)'
  },
  tabBarComponent: (props) =&amp;gt; &amp;lt;CustomBottomBar {...props} /&amp;gt;
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Our createBottomTabNavigator should now look like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

const bottomNavigator = createBottomTabNavigator({
  Home:{
    screen: ScreenOne,
    navigationOptions:{
      tabBarIcon: ({tintColor}) =&amp;gt; &amp;lt;Ionicons name='md-home' color={tintColor} size={24} /&amp;gt;
    }
  },
  Notifications:{
    screen: ScreenTwo,
    navigationOptions:{
      tabBarIcon: ({tintColor}) =&amp;gt; &amp;lt;Ionicons name='md-notifications' color={tintColor} size={24} /&amp;gt;
    }
  },
  Profile:{
    screen: ScreenThree,
    navigationOptions:{
      tabBarIcon: ({tintColor}) =&amp;gt; &amp;lt;Ionicons name='md-person' color={tintColor} size={24} /&amp;gt;
    }
  }
}, config)


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The important property here is the &lt;strong&gt;tabBarComponent&lt;/strong&gt;. This accepts a component to act as the default bottom tab bar. We named this &lt;strong&gt;CustomBottomBar&lt;/strong&gt;. It also has props that should be passed down to it so that the custom view object still behaves like the default tab bar. React navigation gives us access to the BottomTabBar component so we can configure such component into how we want this to look instead of using the default look and feel of the bottom component.&lt;/p&gt;

&lt;p&gt;Now, let's go on to creating the &lt;strong&gt;CustomBottomBar&lt;/strong&gt; component. Still in the same &lt;strong&gt;App.js&lt;/strong&gt;, do the following:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

const CustomBottomBar = (props) =&amp;gt;{
    //We use the spread operator to pass down all default properties of a bottom bar
    return(
        &amp;lt;View&amp;gt;
        &amp;lt;BottomBar {...props} style={{backgroundColor: 'tranparent'}}&amp;gt;
        &amp;lt;/View&amp;gt;
    )
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Note that the background color of the &lt;em&gt;BottomBar&lt;/em&gt; should be set to &lt;em&gt;transparent&lt;/em&gt; so that it doesn't overshadow the custom indicator. &lt;br&gt;
To avoid complexity, we won't be adding any further styling to the bottom bar. You'll notice we wrapped a view around the &lt;strong&gt;BottomBar&lt;/strong&gt; component. This is so that we can add a custom indicator of our choice to it. Since our aim is to create that movable colored view in the image above, we add a new component to the &lt;strong&gt;CustomBottomBar&lt;/strong&gt;. The code should now look like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

const CustomBottomBar = (props) =&amp;gt;{
    //We use the spread operator to pass down all default properties of a bottom bar

    //custom styles for our indicator
    //The width of the indicator should be of equal size with each tab button. We have 3 tab buttons therefore, the width of a single tab button would be the total width Dimension of the screen divided by 3

    const {width} = Dimensions.get('screen')
    const animStyles = {
        position: 'absolute',
        top: 0,
        left: 0,
        bottom:0,
        width: width/3,
        backgroundColor: 'rebeccapurple'
    }
    return(
        &amp;lt;View&amp;gt;
        &amp;lt;Animated.View style={animStyles} /&amp;gt;
        &amp;lt;BottomTabBar {...props} style={{backgroundColor: 'tranparent'}} /&amp;gt;
        &amp;lt;/View&amp;gt;
    )
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This is how the app should look.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fm165t5czxhphl9hhvyha.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fm165t5czxhphl9hhvyha.png" alt="Screesnhot"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, we animate it. The indicator is required to move to the very position of the tab button pressed. The &lt;strong&gt;BottomTab&lt;/strong&gt; component receives an &lt;em&gt;onTabPress&lt;/em&gt; prop which is a method and this returns the route name of the tab pressed. This method executes an action everytime a tab button is pressed. We'll use this action to properly animate the indicator to the specific location. Still in the &lt;strong&gt;CustomBottomBar&lt;/strong&gt; component, we modify it as:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

const CustomBottomBar = (props) =&amp;gt;{
    //We use the spread operator to pass down all default properties of a bottom bar

    //custom styles for our indicator
    //The width of the indicator should be of equal size with each tab button. We have 3 tab buttons therefore, the width of a single tab button would be the total width Dimension of the screen divided by 3

    const {width} = Dimensions.get('screen')

    //Create an animated value 
    const [position] = useState(new Animated.ValueXY())

    //We attach the x,y coordinates of the position to the transform property of the indicator so we can freely animate it to any position of our choice.
    const animStyles = {
        position: 'absolute',
        top: 0,
        left: 0,
        bottom:0,
        width: width/3,
        backgroundColor: 'rebeccapurple',
        transform: position.getTranslateTransform()
    }
    return(
        &amp;lt;View&amp;gt;
        &amp;lt;Animated.View style={animStyles} /&amp;gt;
        &amp;lt;BottomTabBar {...props} style={{backgroundColor: 'tranparent'}} /&amp;gt;
        &amp;lt;/View&amp;gt;
    )
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;With everything set, we can now animate our position to where we want it. We create a method called &lt;em&gt;animate&lt;/em&gt;, This method would be passed to the &lt;em&gt;onTabPress&lt;/em&gt; prop of the &lt;strong&gt;BottomBar&lt;/strong&gt; component. So we should have our code like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

const CustomBottomBar = (props) =&amp;gt;{
    //We use the spread operator to pass down all default properties of a bottom bar

    //custom styles for our indicator
    //The width of the indicator should be of equal size with each tab button. We have 3 tab buttons therefore, the width of a single tab button would be the total width Dimension of the screen divided by 3

    const {width} = Dimensions.get('screen')

    //Create an animated value 
    const [position] = useState(new Animated.ValueXY())

    //We attach the x,y coordinates of the position to the transform property of the indicator so we can freely animate it to any position of our choice.
    const animStyles = {
        position: 'absolute',
        top: 0,
        left: 0,
        bottom:0,
        width: width/3,
        backgroundColor: 'rebeccapurple',
        transform: position.getTranslateTransform()
    }

    const animate = (value, route) =&amp;gt;{
        //navigate to the selected route on click
        props.navigation.navigate(route)

        //animate indicator
        Animated.timing(position, {
            toValue: {x: value, y: 0},
            duration: 300,
            useNativeDriver: true
        }).start()
    }

    return(
        &amp;lt;View&amp;gt;
        &amp;lt;Animated.View style={animStyles} /&amp;gt;
        &amp;lt;BottomTabBar {...props} onTabPress={({route}) =&amp;gt;{
            switch(route.key){
                case 'Home':
                //animated position should be 0
                     animate(0, route.key)
                     break
                     case 'Notifications':
                     //animated position is width/3
                      animate(width/3 , route.key)
                      break
                      case 'Profile':
                      //animated position is width of screen minus width of single tab button
                       animate(width - (width/3), route.key)
                       break
            }
        }} style={{backgroundColor: 'transparent'}} /&amp;gt;
        &amp;lt;/View&amp;gt;
    )
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;And that's it. We have successfully animated our indicator for the bottom bar to focus on the actively selected screen of the bottom bar. Here is the full. We just had to modify the &lt;strong&gt;BottomTabBar&lt;/strong&gt; component imported from &lt;em&gt;react-navigation-tabs&lt;/em&gt; as we would do for a normal react component. Nothing much here!&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>reactnavigation</category>
    </item>
  </channel>
</rss>
