Hire a web Developer and Designer to upgrade and boost your online presence with cutting edge Technologies

Wednesday, December 25, 2019

Equivalent Experiences: What Are They?

If you spend enough time interacting with digital accessibility practitioners, you may encounter the phrase “equivalent experience.” This saying concisely sums up a lot of the philosophy behind accessibility work.
Our industry tends to place a lot of focus on how, often at the expense of why. For accessibility-related concerns, it is vital to learn about the history, and lived experiences of disabled people as a context for understanding the need for design and code created with access in mind.
This is the first of two articles on the topic of equivalency, and how it relates to digital accessibility. It will help us define what an equivalent experience is. Once we have a common understanding established, I’ll then discuss how to go about implementing equivalent experiences for common accessibility-related issues.

The State Of Things

The truth of the matter is that even though we live in a multi-device world full of smartphones, augmented reality, voice assistants, and IoT smart sensors, our default is still predominately:
  • Visual,
  • large screen,
  • fast connection,
  • powerful computer and display,
  • male,
  • white,
  • wealthy,
  • young,
  • Western,
  • technologically-literate,
  • and abled.
This is reflective of the biases that are inherent in how we design, develop and grow products.
The previous list may not be the most comfortable thing to read. If you haven’t closed the browser tab already, take a moment to consider your daily workflows, as well as who your coworkers are, and you’ll begin to understand what I’m getting at.
At its core, delivering an equivalent experience is ultimately about preserving intent — with the intent being the motivating force behind creating a website or web app and all the content and features it contains.
This translates to making the meaning behind every interaction, every component, every photo or illustration, every line of code being understandable by the widest range of people, regardless of their device or ability.


What Isn’t An Equivalent Experience?

Showing examples of what something is not can be a way to help define it. For equivalent experiences, an example would be a web app geared towards use by the general public not having a mobile breakpoint.


With this example, everyone using a device with a small display is forced to pinch, pan, and zoom to get what they need. Here, the burden is placed on anyone whose only crime was using a smartphone.
Most likely, whoever conceived of, designed, and developed this didn’t stop to think about circumstances other than their own. In this sort of (unfortunately still all too common) scenario, I all but guarantee that the web app looks great on the laptops or desktops of the designers and developers who made it.


People using a smartphone to access this website are victims of circumstance. The extra effort someone needs to do to get it to work indirectly communicates that they weren’t a priority, and therefore not valued. If you’ve used the web for any significant portion of time, I’m willing to bet this, or a similar experience has happened to you.
This example is also a hop, skip, and a jump away from another common, yet serious accessibility issue we often don’t consider: screen zooming:

Screen Zooming

Screen zooming is when someone is prevented from being able to zoom their displays and make text larger—many native mobile apps are guilty of this. When you disallow this sort of behavior, you’re telling prospective users that unless they have vision similar to you, you aren’t interested in them being able to use your app.
For this scenario, a gentle reminder that we will all get older, and with aging comes a whole host of vision-related concerns.

Accessible Experiences Aren’t Necessarily Equivalent Ones

This might be a little difficult of a concept to grasp at first. Let’s use this Rube Goldberg machine made by Joseph Herscher to pass the pepper to his dinner guest to compare.

To pass the pepper, the machine, sends it through an elaborate system of weights, counterweights, ramps, rolling objects, catapults, guillotines, burners, timers, carousels, etc. — all constructed from commonly found kitchen items. While this setup will technically ensure the pepper is passed, it is an annoying, overwrought, time-intensive process.
Many digital experiences are a lot like a Rube Goldberg machine when it comes to accessibility. Since accessibility issues are so prevalent, many forms of assistive technology provide a large suite of features to allow their user to work around common obstacles.
Unfortunately, discovering obstacles, and then figuring out and activating the appropriate combination of features to overcome them can take a disproportionate amount of time and effort.
To say it another way: A simple click on a button for an abled person may take far more time and effort for a disabled person, depending on how the button has been made.


Chilling Effects

Frustratingly, the extra time and effort a disabled person has to put into operating a technically accessible experience may feed back into their disability condition(s). For example, the presence of a motor control disability such as arthritis may make the overall experience even more taxing.
Cognitive accessibility concerns are also another important thing to consider. What may seem easy to understand or intuitive to use for one person may not be for another. This is especially prevalent in situations where there is:
Cognitive accessibility isn’t an abstract concern, either. Poor user interface design that ignores the circumstances of the end user and dumps too much cognitive load onto them can have very real, very serious consequences.

Compounding Effects

These factors are not mutually exclusive. Proponents of Spoon Theory know that inaccessible experiences conspire to sap a person’s mental and physical energy, leaving them exhausted and demotivated. Worse, these sorts of scenarios are often more than just a person perpetually operating at a diminished capacity.
Frustrating digital experiences can lead to a person abandoning them outright, internalizing the system’s fault as their own personal failure. This abandonment may also translate to a person’s willingness and ability to operate other digital interfaces. In other words: the more we turn people away, the more they’ll stop trying to show up.

Consistency

For some, assistive technology can mean specialized browser extensions. These micro-apps are used to enhance, augment, and customize a browsing experience to better suit someone’s needs.
Damien Senger, digital designer, uses a browser extension called Midnight Lizard to enforce a similar experience across multiple websites. This helps them “to focus on the content directly and to limit having too big differences between websites. It is also helping me to avoid too harsh color contrasts that are really uncomfortable.“
Damien also writes, “Often websites are really difficult to read for me because either of the lack of consistency in the layout, too narrow lines or just not enough balance between font size and line height. Related to that, color can create a lot of unhelpful distraction and I am struggling when too harsh contrast is nearby text.”
How To Maintain Equivalency
In addition, Damien also augments their browsing experience by using ad blocking technology “not only for ads but to block animations or content that are too distracting for my ADHD.”
It’s not too difficult to imagine why distracting and annoying your users is a bad idea. In the case of ads, the industry is unregulated, meaning that rules to prohibit ADHD, migraine, and/or seizure-triggering animations aren’t honored. Through this lens, an ad blocker is a form of consumer self-defense.

Kenny Hitt also chimes in about ads: “…regardless of the platform, the thing that annoys me most are websites with ads that essentially cause the site to constantly auto update. This prevents me as a screen reader user from reading the content of those websites.”
Again, a lack of regulation means the user must take measures into their own hands to keep the experience equivalent.

How To Maintain Equivalency

Opportunity

A lack of an equivalent experience translates directly to lost opportunity. Many individuals I spoke with mentioned that they’d abandon a digital experience that was inaccessible more often than not.
Brian Moore mentions, “there are web sites where I like their products a lot but won’t buy them because the site itself is such a struggle, and attempts to reach out have met with either silence or resistance to taking any action.”
Brian cites the Fluance website as the most recent example. The bugs present in its shopping user flows prevents him from buying high-end consumer audio equipment.
Fluance’s entire web presence exists to sell products. While updating a website or web app to be accessible can be an effort-intensive process, it would definitely be in Fluance’s best interest to make sure its checkout user flow is as robust as it could be.



Friday, December 20, 2019

What does Amazon really think about third-party sellers?

 

High-volume sales and a large catalog don’t protect your Amazon account

As we head into peak season, it’s easy for large third-party Amazon sellers to be over-confident about their position with Amazon. Many assume that their high revenue, large order volume or wide selection of offers protects them from enforcement actions by Amazon Seller Performance.
In other cases, sellers have had long-time personal relationships with account managers, sales folks or even executives in Amazon’s Seattle offices. These person-to-person interactions must offer some degree of protection, right?

Unfortunately, the larger Amazon becomes, the less any of these factors truly help a third-party seller:

  1. Broad selection means nothing. Unique selection, however, is seen as a virtue. If you sell items that have a lot of other sellers on them, Amazon is not concerned about losing you as a seller. Someone else is already providing your inventory on the platform.
  2. Similarly, a high volume of orders or big revenue numbers don’t protect you. Amazon can get those same sales from other third-party sellers or vendors.
  3. Personal relationships are becoming less important as the company gets bigger. Many sellers make the mistake of believing that an “account manager” – who is really in sales at Amazon – can protect their account. That’s simply not true. These sales folks are responsible for bringing in new sellers and product selection. They do care about their accounts, since they are goal based on revenue. But they don’t have the power to make enforcement issues go away. Strategic account managers sometimes can help, but their arguments to Seller Performance must be based on facts – not your account’s size or selection.
What do Amazon executives care about? They love feel-good stories that prop up Amazon’s reputation:
  1. Amazon executives like seller-owned brands that sell exclusively on Amazon and spend money for PPC, Early Reviewer, etc. These sellers bring in sales that Amazon wouldn’t have otherwise.
  2. Amazon executives like sellers who bring unique products to the platform, through exclusive relationships with manufacturers, wholesalers and the like.
Being a unique brand or having exclusive offers on Amazon still won’t prevent Seller Performance from taking action if it perceives your products or customer service as poor or risky.

What is the takeaway for large third-party Amazon sellers?

Invest in strategies that ensure your Amazon customers receive excellent-quality products and fantastic service with every transaction. That will protect your account sooner than volume, catalog size or even Amazon relationships.

Tuesday, December 10, 2019

How to get your winning online products into brick-and-mortar retail stores

 Brand building is an essential element as an Amazon FBA seller, but that doesn’t just mean Amazon. You can work on every aspect of your business and use the resources to slowly scale your business beyond an online store into retail space. And you are not alone. Many product-based brands want to be carried by major retailers. The question is how do you get your products into stores?

 

Amazon has already conquered the e-commerce space and is the leading online retailer. But here is the truth; despite the dominance of online stores like Amazon, physical stores still find their way to the top of that pile. The endless benefits retailers offer should be part of your business scaling plan.

In today’s climate, expanding your business past the online space will significantly increase your sales through increased customer reach.

Another benefit of targeting brick-and-mortar stores is having a separate income stream from your Amazon business. Running an Amazon FBA business comes at a risk. With Amazon policies changing now and then, there is no telling when you will run into problems like Amazon suspensions.

If your products are selling at a physical store, it means reduced risk because your goods can continue selling as you sort out your Amazon suspension issues. But the most significant benefit of targeting physical stores is increasing brand recognition and authority.

This article will outline how you can sell in retail stores as the next step in your selling journey.

What do retailers want to see when you approach them to sell your products in their stores?

There is a thrill in seeing your products on the shelf spaces of brick-and-mortar stores. Think about your beautiful packaging sparkling in front of a customer’s eyes!

With so much competition in the physical retail space, only a select few will achieve their retail goals. Landing your product in a major physical store isn’t an easy feat. It will take time and persuasion, and you must demonstrate to the retailer why your product is worth the shelf space.

So, what do retailers want to see before they determine if they’ll carry your product in their store?

#1 Proof of sale data

Retail stores face many challenges like paying overhead for rent, store fixtures, employees, utilities, signage, and furnishings.

Physical stores also operate on thin profit margins, and that’s why a store will have no problem discontinuing a product that isn’t generating enough sales.

So, when you approach a store, the first thing they want to see is data showing that you have had significant sales success online.

Ideally, if your products are not selling on Amazon, what makes you think it will be any different with a physical store? Prove your worth for the retail market.

#2 Showcase stunning branding and product portfolios

For physical stores, branding is everything. A physical store relies on foot traffic to make sales. A product must first attract buyers’ attention before they buy. Beautiful branding is something you need to work on.

Retail stores want to see a brand portfolio of multiple products that could naturally sell in their stores. Think about branding in a systematic approach and rebrand some of your most essential products specifically for retail if they aren’t up to par or if they need a retail refresh.

#3 Effective packaging

Fact: Packaging drives purchasing decisions more than TV ads, online reviews, and customer recommendations. 64% of customers will sometimes buy a product they haven’t even heard of because of the packaging.

Packaging is different for products sold online and in physical stores. At the moment, you might not have adequate retail shelf packaging for products you sell online since you never needed one.

But before you approach a physical store, you must consider packaging. First impressions count. Your goal is to be catchy. It’s common for customers to stop and stare at products. You must convince the retailer that your product can do that. A professional design will make your product worth its space.

Knowledge of marketing strategies

Marketing strategies like endcaps and point-of-purchase displays are vital in retail stores. An average shopper can be exposed to more than 20,000 products per shopping trip. Because of this competition, brands need to ensure that their products stand out and attract customers to make a purchase. Strategies like endcap displays, therefore, come into play.

A point of purchase display (POP display) is a custom display showcasing products outside their natural habitat but in a retail setting. POP displays are great for promoting a product and showcasing special offers and deals. A POP display also helps educate a potential customer on the offering and brand details.

An end cap display allows one to create visually appealing spaces that draw in shoppers. You must demonstrate to the retail store that you understand these strategies and that your product can effectively fit into and work in their retail store footprint.

What are the challenges sellers may face getting their products into retail stores?

Getting into retail stores is challenging, and only a few online sellers make the cut. Here are some of the challenges most sellers face when trying to get into retail:

Relationships with buyers in the chains: If you can’t develop a good relationship with buyers, there is no way a retail store will carry your products. Buyers are interested in only one thing- growing the total category value. If you can’t show them you understand their strategy, they will go with someone who does.

Relationships with the right buyers in the right departments: To get into retail, you must identify the right buyers to pitch to.

Difficulty knowing whether to launch your existing brand or create a diffusion brand with a different price point and adjusted branding: A diffusion brand is the second line of product that is supposed to appeal to a different target market. A diffusion brand could work when getting into retail to target consumers who will have the product flying off the shelves. But then, it could also overshadow your leading brand creating more problems.

Understanding how to set up your vendor number: A vendor number is given by a retail store if they agree to carry your product. However, most Amazon sellers don’t know how to set up a vendor number or what documents are required.

Capital to manufacture enough product for retail orders or financing to underwrite the orders: Getting a retail store to carry your product is one thing, and ensuring you have enough products is another. Most Amazon sellers don’t think about this when approaching retail stores and end up with zero products on the shelves because they don’t have the capital to handle large orders.

Logistics capabilities: You have to nail down everything, including how to manage all your logistics at the lowest cost, so you are not incurring losses in the end.

Tips on how to get your winning online products into retail stores

There are over 1 million retail establishments across the United States, and retail stores have grown almost 4% annually since 2010. In 2020, there were 328,208 brick and mortar retail stores in the United States.

Online retail leaders are less than 10%.

It’s no longer an in-store vs. online debate. The narrative has changed. So, here are ways to get into retail as an online seller.

#1 Research the competition

To make it in the retail business, you need to know where your product sits when it comes to your competition.

    • Who is your competition?
    • What products are they selling?
    • How much are their products selling for?

When researching the competition, we don’t mean going to Amazon. Researching competition on Amazon is useless because you are targeting retailers in this case.

Never underestimate the value of competitor data. Walking into a store, you are targeting will expose you to brands selling similar products. You can then establish their strengths and weaknesses, so you know how to make your product stand out from theirs.

#2 Work on your branding

Being an e-commerce-ready brand doesn’t mean that you are a retail-ready brand. But if you are retail-ready, then you are also e-commerce-ready.

Branding is everything in the retail industry. While growing a brand is not a one-time process, you need to work on your branding before you start selling. Branding, in this case, is all about the colors and images you choose to represent you to the public.

Have good branding for your website, social media pages, lifestyle images, and packaging. Your branding needs to be cohesive and show a preview of your products.

#3 Product data and marketing plan

To get into retail, you must clarify that your product has a unique selling point that will cause it to fly off the shelves. You must also understand your target audience, estimated demand, and suggested retail product price.

Highlight your promotional and marketing plans to the retailer to prove to the buyer that you are invested in helping them sell your product.

#4 Understand the buyer’s category mission and vision

What is the overall strategy of the buyer or retailer? How will you position your brand to align with their vision and mission for that category?

For instance, if the objective of the category is to provide responsible soft drink options, you have to determine how your product meets that pillar and whether your target audience is aligned with the same.

#5 Show you understand the retailer’s customer needs

Customer needs change from time to time and so do specific categories. For a retailer to carry your products, you must convince them you know what their customers in a particular category are looking for. Doing so shows that you know the category inside out.

Summary

Getting your products into retail stores is one of the best ways of expanding your reach. It is also a great way of having another stream of income. Amazon is unpredictable, and you never know what might happen in the future.

To keep your products moving, even when dealing with Amazon issues like suspensions, it helps if you have another way to reach customers. To get into retail, explain to the retailer the reasons why your product will fly off the shelves and what your product has that makes it unique.

That said, there has never been a better time to start your retail journey than now. If you’re looking for more info about your retail sales journey, head to projectretail.com

If your winning Amazon ASINs belong in retail stores, don’t struggle alone.

Wednesday, December 4, 2019

3 easy steps to good Amazon seller account health

 

As Spring nears, it’s a great time to start cleaning after a long winter to prepare for sunny skies ahead. Spring cleaning is typically something we do every year, some of us a few times a year, to keep our homes in tip-top shape through the seasons.

Much like the spring cleaning of your home, your Amazon FBA business requires regular spring cleaning or hygiene to run smoothly all year round. Now is as great a time to develop a step-by-step hygiene routine to maintain your account in good standing, now and for the future.

As a new Amazon seller, you may not have much awareness about Amazon seller account health because your focus to date is growing your FBA business. Without routine hygiene, you may not know that your FBA business can be at severe risk.

This article will detail the most vital aspects of maintaining Amazon account hygiene so you can run a smooth and successful FBA business.

What does Amazon seller account hygiene mean?

  Selling on Amazon is a privilege, and with that privilege comes the responsibility to maintain your Amazon account in good health. As an FBA business owner, you must understand the privilege Amazon extends so that you prioritize account health to avoid account suspension or closure.

Your Amazon seller central account contains a section entirely dedicated to account health. In this section of your account, you’ll find a slew of account metrics to keep your account in good standing and discover account level warnings that require your attention.

To access your Amazon Account Health page in Amazon Seller Central, open the performance tab and choose Account Health. Select Seller Central > Performance Menu > Account Health. Once in this section, you’ll discover an overview of compliances with Amazon policies.

Amazon seller account health is composed of three metrics:

  1. Customer Service Performance
  2. Product Policy Compliance
  3. Shipping Performance

On the Amazon Health page, you’ll be able to review negative feedback, and chargeback claims.

Where to begin with Amazon account hygiene

 

Amazon account hygiene requires ongoing attention to stay on top of policy and account health. When looking to create a systematic process for account hygiene, it’s a good idea to begin with the foundation within your Amazon account.

To start, focus on your catalog of products as the priority. From there, navigate any stranded inventory and negative feedback. While this may sound simple, you’ll want to develop a practical process that ensures you consistently maintain good account hygiene.

Step 1 – Review Your Entire Catalog

As a growing FBA business, you’re likely to consistently add products to your catalog. That’s excellent news in terms of your ability to scale. Unfortunately, adding more products can mean that sellers inadvertently overlook older products not intended for sale.

Often the addition of new products doesn’t always come with the intention of selling these products. Sellers frequently add new products to understand if they meet ungating requirements or specific permissions and compliances. But, if the product remains on the Manage Inventory Page, Amazon fully believes you intend to sell that product.

If for whatever reason, you receive an IP complaint (Intellectual Property Violation or Restricted Product Warning,) you could face a severe ASIN violation without your knowledge. If you were to list this product in the future and were not aware of the ASIN violation, you could experience a negative score against your account.

The Solution

Ensure the deletion of all products from inventory that you have no intention to sell. It’s a simple fix but often overlooked as you begin to scale your FBA business. The added benefit of deleting products you don’t intend to sell is that your inventory performance score will improve. The inventory performance score is vital to the quantity of inventory you can send to Amazon; therefore, a positive score is critical.

Step 2 – Deal With Stranded Inventory

If not careful, you can locate a substantial amount of stranded inventory and a stranded inventory Amazon FBA inventory error in your Amazon account. Stay on top of stranded inventory to keep your account in good health and to maintain a positive inventory performance score.

The Solution

How to fix stranded inventory on Amazon? Go into the stranded inventory page of Amazon Seller Central and reconcile each ASIN one by one. This may mean that you remove stranded inventory to your warehouse or home or that you have it disposed of by Amazon.

Removing stranded inventory can require a refresh of your inventory screen, a call to Seller Support, or an appeal. While appeals are common, it’s best to avoid the Amazon stranded inventory listing error and inventory languishing in this area.

Step 3 – Check The Feedback In Your Storefront

 

Amazon seller feedback is a metric that evaluates your selling performance. It’s available for Amazon customers and can be left when a customer returns an order or through the feedback page on Amazon.

Negative and neutral reviews can be mistakenly entered into this area by customers. A negative review can negatively affect your feedback performance score when that happens.

The Solution

Previously sellers could request negative reviews be removed from the feedback section by clicking a report feedback button. Today, sellers must open a case file for each incorrect feedback to have them removed. Remove all negative or neutral reviews from this area to increase your performance score and continue selling without issue.

Summary

You’ll want to check your Amazon Account Health dashboard on an ongoing basis and add this task to your daily standard operating procedures. Regularly address any ASIN violations or other policy violation warnings in your account health dashboard to maintain good account hygiene. Avoiding problems out of fear only increases risk and can make appeals more challenging if appeals are required.

The instances of poor account health and stranded deep inventory sneak up on sellers, especially if they don’t know where to look or how to address warnings and violations. It’s good to work with an account specialist who can provide a comprehensive violation review and an action plan to address each one.

We can’t stress enough the importance of regular Amazon account hygiene. It’s too easy to sell on the platform and ignore this crucial aspect of business, especially as sales continue to roll in. Create an ongoing hygiene review within your Amazon account, like your spring cleaning regime.

How do you perform routine Amazon account hygiene? Let us know in the comments.

Need help with an ASIN appeal or an Amazon seller account health issue?

Tuesday, December 3, 2019

Handlin Mounting and Unmounting of Navigation routes in React Native

 Often you need two different sets of navigation stacks for pre and post user authentication. Usually, to see more content, you have to be authenticated in some way. Let’s look at how to mount and unmount navigation stack based on a met condition in React Native.

In this article, we are going to walk through mounting and unmounting of navigation routes in React Native. An expected behavior of your app is that once the authentication condition is met, a new set of navigation routes are available only to logged-in users, while the other screens which were displayed before authentication is removed and can’t be returned to unless the user signs out of the application.

For security in your app, protected routes provide you with a way to only display certain information/content on your app to specific users, while restricting access from unauthorized persons.

We will be working with Expo for this project because it’ll help us focus on the problem at hand instead of worrying about a lot of setups. The exact same steps in this article could be followed for a bare React Native application.

You need some familiarity with JavaScript and React Native to follow through with this tutorial. Here are a few important things you should already be familiar with:

  • Custom components in React Native (how to create components, receive, pass, and use props in a component). Read more.
  • React Navigation. Read more.
  • Stack Navigator in React Native. Read more.
  • Basic Knowledge of React Native Core components (<View/>, <Text/>, etc.). Read more.
  • React Native AsyncStorage. Read more.
  • Context API. Read more.

Project Setup And Base Authentication #

If you’re new to using expo and don’t know how to install expo, visit the official documentation. Once the installation is complete, go ahead to initialize a new React Native project with expo from our command prompt:

expo init navigation-project

You will be presented with some options to choose how you want the base setup to be:

In our case, let’s select the first option to set up our project as a blank document. Now, wait until the installation of the JavaScript dependencies is complete.

Once our app is set up, we can change our directory to our new project directory and open it in your favorite code editor. We need to install the library we will be using for AsyncStorage and our navigation libraries. Inside your folder directory in your terminal, paste the command above and choose a template (blank would work) to install our project dependencies.

Let’s look at what each of these dependencies is for:

  • @react-native-community/async-storage
    Like localStorage on the web, it is a React Native API for persisting data on a device in key-value pairs.
  • @react-native-community/masked-view, react-native-screens, react-native-gesture-handle
    These dependencies are core utilities that are used by most navigators to create the navigation structure in the app. (Read more in Getting started with React Native navigation.)
  • @react-navigation/native
    This is the dependency for React Native navigation.
  • @react-navigation/stack
    This is the dependency for stack navigation in React Native.
npm install @react-native-community/async-storage @react-native-community/masked-view @react-navigation/native @react-navigation/stack react-native-screens react-native-gesture-handle

To start the application use expo start from the app directory in your terminal. Once the app is started, you can use the expo app from your mobile phone to scan the bar code and view the application, or if you have an android emulator/IOS simulator, you can open the app through them from the expo developer tool that opens up in your browser when you start an expo application. For the images examples in this article, we will be using Genymotions to see our result.

 

Folder Structures #

Let us create our folder structure from the start so that it’s easier for us to work with it as we proceed:

We need two folders first:

  • context
    This folder will hold the context for our entire application as we will be working with Context API for global state management.
  • views
    This folder will hold both the navigation folder and the views for different screens.

Go ahead and create the two folders in your project directory.

Inside the context folder, create a folder called authContext and create two file inside of the authContext folder:

  • AuthContext.js,
  • AuthState.js.

We will need these files when we start working with Context API.

Now go to the views folder we created and create two more folders inside of it, namely:

  • navigation,
  • screens.

Now, we are not yet finished, inside the screens folder, create these two more folders:

  • postAuthScreens,
  • preAuthScreens.

Creating Our First Screen #

Now let’s create our first screen and call it the welcomeScreen.js inside the preAuthScreens folder.

preAuthScreens > welcomeScreen.js

Here’s the content of our welcomeScreen.js file:

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

const WelcomeScreen = () => {

  const onUserAuthentication = () => {
    console.log("User authentication button clicked")
  }

  return (
    <View style={styles.container}>
      <Text style={styles.header}>Welcome to our App!</Text>
      <View>
        <TextInput style={styles.inputs} placeholder="Enter your email here.." />
        <TextInput style={styles.inputs} secureTextEntry={true} placeholder="Enter your password here.." />
<Button  title="AUTHENTICATE" onPress={onUserAuthentication} />
      </View>
    </View>
  )
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
  header: {
    fontSize: 25,
    fontWeight: 'bold',
    marginBottom: 30
  },
  inputs: {
    width: 300,
    height: 40,
    marginBottom: 10,
    borderWidth: 1,
  }
})

export default WelcomeScreen

Here’s what we did in the code block above:

First, we imported the things we need from the React Native library, namely, View, Text, Button, TextInput. Next, we created our functional component WelcomeScreen.

You’ll notice that we imported the StyleSheet from React Native and used it to define styles for our header and also our <TextInput />.

Lastly, we export the WelcomeScreen component at the bottom of the code.

Now that we are done with this, let’s get this component to function as expected by using the useState hook to store the values of the inputs and update their states anytime a change happens in the input fields. We will also bring import the useCallback hook from React as we will be needing it later to hold a function.

First, while we are still in the WelcomeScreen component, we need to import the useState and useCallback from React.

import React, { useState, useCallback } from 'react';

Now inside the WelcomeScreen functional component, let’s create the two states for the email and password respectively:

...
const WelcomeScreen = () => {
  const [email, setEmail] = useState('')
  const [password, setPassword] = useState('')
  return (
    ...
  )
}
...

Next, we need to modify our <TextInput /> fields so that the get their value from their respective states and update their state when the value of the input is updated:

import React, { useState, useCallback } from 'react';
import { View, Text, Button, StyleSheet, TextInput } from 'react-native';

const WelcomeScreen = () => {
  const [email, setEmail] = useState('')
  const [password, setPassword] = useState('')

  const onInputChange = (value, setState) => {
    setState(value);
  }
  return (
    <View>
      ...      
      <View>
        <TextInput
          style={styles.inputs}
          placeholder="Enter your email here.."
          value={email}
          onChangeText={(value) => onInputChange(value, setEmail)}
        />
        <TextInput
          style={styles.inputs}
          secureTextEntry={true}
          placeholder="Enter your password here.."
          value={password}
          onChangeText={(value) => onInputChange(value, setPassword)}
        />
        ...
      </View>
    </View>
  )
}
...

In the code above, here is what we did:

  • We made the value of each of the text inputs to point to their respective states.
  • We added the onChangeText handler to our text inputs. This fires up anytime a new value is entered or deleted from the input fields.
  • We called our onInputChange function which accepts two arguments:
    • The current value is supplied by the onChangeText handler.
    • The setter of the state that should be updated (for the first input field we pass setEmail and the second we pass setPassword.
    • Finally, we write our onInputChange function, and our function does only one thing: It updates the respective states with the new value.

The next thing we need to work on is the onUserAuthentication() function with is called whenever the button for the form submission is clicked.

Ideally, the user must have already created an account and login will involve some backend logic of some sort to check that the user exists and then assign a token to the user. In our case, since we are not using any backend, we will create an object holding the correct user login detail, and then only authenticate a user when the values they enter matches our fixed values from the login object of email and password that we will create.

Here’s the code we need to do this:

...

const correctAuthenticationDetails = {
  email: 'demouser@gmail.com',
  password: 'password'
}
const WelcomeScreen = () => {
  ...

  // This function gets called when the `AUTHENTICATE` button is clicked
  const onUserAuthentication = () => {
    if (
      email !== correctAuthenticationDetails.email ||
      password !== correctAuthenticationDetails.password
    ) {
      alert('The email or password is incorrect')
      return
    }
      // In here, we will handle what happens if the login details are       // correct
  }

  ...
  return (
    ...
  )
}
...

One of the first things you’ll notice in the code above is that we defined a correctAuthenticationDetails (which is an object that holds the correct login details we expect a user to supply) outside of the WelcomeScreen() functional component.

Next, we wrote the content of the onUserAuthentication() function and used a conditional statement to check if the email or password held in the respective states does not match the one we supplied in our object.

If you would like to see what we have done so far, import the WelcomeScreen component into your App.js like this:

Open the App.js file and put this replace the entire code with this:

import { StatusBar } from 'expo-status-bar';
import React from 'react';
import { View } from 'react-native';
import WelcomeScreen from './views/screens/preAuthScreens/welcomeScreen';
export default function App() {
  return (
    <View>
      <StatusBar style="auto" />
      <WelcomeScreen />
    </View>
  );
}

Looking closely at the code above, you’ll see that what we did was import the WelcomeScreen component and then used it in the App() function.

Now that we are done building the WelcomeScreen component, let’s move ahead and start working with Context API for managing our global state.

Why Context API? #

Using Context API, we do not need to install any additional library into ReactJS, it is less stressful to set up, and is one of the most popular ways of handling global state in ReactJS. For lightweight state management, it is a good choice.

Creating Our Context #

If you recall, we created a context folder earlier and created a subfolder inside of it called the authContext.

Now let’s navigate to the AuthContext.js file in the authContext folder and create our context:

context > authContext > AuthContext.js


import React, { createContext } from 'react';
const AuthContext = createContext();
export default AuthContext;

The AuthContext we just created holds the loading state value and the userToken state values. Currently, in the createContext we declared in the code-block above, we didn’t initialize any default values here so our context is currently undefined. An example value of the auth context could be {loading: false, userToken: 'abcd}

The AuthState.js file holds our Context API logic and their state values. Functions written here can be called from anywhere in our app and when they update values in state, it is updated globally also.

First, let’s bring in all the imports we will need in this file:

context > AuthContext > AuthState.js

import React, { useState } from 'react';
import AuthContext from './AuthContext';
import AsyncStorage from '@react-native-community/async-storage';

We imported the useState() hook from ReactJS to hold our states, we imported the AuthContext file we created above because this is where our empty context for authentication is initialized and we will need to use it as you’ll see later on while we progress, finally we import the AsyncStorage package (similar to localStorage for the web).

AsyncStorage is a React Native API that allows you to persist data offline over the device in a React Native application.

...

const AuthState = (props) => {
    const [userToken, setUserToken] = useState(null);
    const [isLoading, setIsLoading] = useState(true);

    const onAuthentication = async() => {
        const USER_TOKEN = "drix1123q2"
        await AsyncStorage.setItem('user-token', USER_TOKEN);
        setUserToken(USER_TOKEN);
        console.warn("user has been authenticated!")
    }

    return (
        <AuthContext.Provider
            value={{
                onAuthentication,
            }}
        >
            {props.children}
        </AuthContext.Provider>
    )
}
export default AuthState;

In the code block above here’s what we did:

  • We declared two states for the userToken and isLoading. The userToken state will be used to store the token saved to AsyncStorage, while the isLoading state will be used to track the loading status (initially it is set to true). We will find out more about the use of these two states as we proceed.

  • Next, we wrote our onAuthentication() function. This function is an async function that gets called when the login button is clicked from the welcomeScreen.jsx file. This function will only get called if the email and password the user has supplied matches the correct user detail object we provided. Usually what happens during authentication is that a token is generated for the user after the user is authenticated on the backend using a package like JWT, and this token is sent to the frontend. Since we are not going into all of that for this tutorial, we created a static token and kept it in a variable called USER_TOKEN.

  • Next, we use the await keyword to set our user token to AsyncStorage with the name user-token. The console.warn() statement is just used to check that everything went right, you can take it off whenever you like.

  • Finally, we pass our onAuthenticated function as a value inside our <AuthContext.Provider> so that we can access and call the function from anywhere in our app.

screens > preAuth > welcomeScreen.js

First, import useContext from ReactJS and import the AuthContext from the AuthContext.js file.

import React, { useState, useContext } from 'react';
import AuthContext from '../../../context/authContext/AuthContext'
...

Now, inside the welcomeScreen() functional component, let’s use the context which we have created:

...
const WelcomeScreen = () => {
  const { onAuthentication } = useContext(AuthContext)
  const onUserAuthentication = () => {
    if (
      email !== correctAuthenticationDetails.email ||
      password !== correctAuthenticationDetails.password
    ) {
      alert('The email or password is incorrect')
      return
    }
    onAuthentication()
  }
  return (
    ...
  )
}
...

In the above code block, we destructured the onAuthentication function from our AuthContext and then we called it inside our onUserAuthentication() function and removed the console.log() statement which was there before now.

Right now, this will throw an error because we don’t yet have access to the AuthContext. To use the AuthContext anywhere in your application, we need to wrap the top-level file in our app with the AuthState (in our case, it is the App.js file).

Go to the App.js file and replace the code there with this:

import React from 'react';
import WelcomeScreen from './views/screens/preAuthScreens/welcomeScreen';
import AuthState from './context/authContext/AuthState'

export default function App() {
  return (
    <AuthState>
      <WelcomeScreen />
    </AuthState>
  );
}

We’ve come so far and we’re done with this section. Before we move into the next section where we set up our routing, let’s create a new screen. The screen we are about to create will be the HomeScreen.js file which is supposed to show up only after successful authentication.

Go to: screens > postAuth.

Create a new file called HomeScreen.js. Here’s the code for the HomeScreen.js file:

screens > postAuth > HomeScreen.js

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

const HomeScreen = () => {

  const onLogout = () => {
    console.warn("Logout button cliked")
  }

  return (
    <View style={styles.container}>
      <Text>Now you're authenticated! Welcome!</Text>
      <Button title="LOG OUT" onPress={onLogout} />
    </View>
  )
}

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

export default HomeScreen

For now, the logout button has a dummy console.log() statement. Later on, we will create the logout functionality and pass it to the screen from our context.

Setting Up Our Routes #

We need to create three (3) files inside our navigation folder:

  • postAuthNavigator.js,
  • preAuthNavigator.js,
  • AppNavigator.js.

Once you’ve created these three files, navigate to the preAuthNaviagtor.js file you just created and write this:

navigation > preAuthNavigator.js

import React from "react";
import { createStackNavigator } from "@react-navigation/stack";
import WelcomeScreen from "../screens/preAuthScreens/welcomeScreen";

const PreAuthNavigator = () => {
    const { Navigator, Screen } = createStackNavigator();

    return (
        <Navigator initialRouteName="Welcome">
            <Screen
                name="Welcome"
                component={WelcomeScreen}
            />
        </Navigator>
    )
}
export default PreAuthNavigator;

In the file above, here’s what we did:

  • We imported the createStackNavigator from the @react-navigation/stack which we are using for our stack navigation. The createStackNavigatorProvides a way for your app to transition between screens where each new screen is placed on top of a stack. By default the stack navigator is configured to have the familiar iOS and Android look & feel: new screens slide in from the right on iOS, fade in from the bottom on Android. Click here if you want to learn more about the stack navigator in React Native.
  • We destructured Navigator and Screen from the createStackNavigator().
  • In our return statement, we created our navigation with the <Navigator/> and created our screen with the <Screen/>. this means that if we had multiple screens that can be accessed before authentication, we will have multiple <Screen/> tags here representing them.
  • Finally, we export our PreAuthNavigator component.

Let us do a similar thing for the postAuthNavigator.js file.

navigation > postAuthNavigator.js

import React from "react";
import { createStackNavigator } from "@react-navigation/stack";
import HomeScreen from "../screens/postAuthScreens/HomeScreen";
const PostAuthNavigator = () => {
  const { Navigator, Screen} = createStackNavigator();
  return (
    <Navigator initialRouteName="Home">
      <Screen
        name="Home"
        component={HomeScreen}
      />
    </Navigator> 
  )
}
export default PostAuthNavigator;

As we see in the code above, the only difference between the preAuthNavigator.js and the postAuthNavigator.js is the screen being rendered. While the first one takes the WelcomeScreen, the postAuthNavigator.js takes the HomeScreen.

To create our AppNavigator.js we need to create a few things.

Since the AppNavigator.js is where we will be switching and checking which route will be available for access by the user, we need several screens in place for this to work properly, let’s outline the things we need to create first:

  1. TransitionScreen.js
    While the app decides which navigation it is going to mount, we want a transition screen to show up. Typically, the transition screen will be a loading spinner or any other custom animation chosen for the app, but in our case, we will use a basic <Text/> tag to display loading….
  2. checkAuthenticationStatus()
    This function is what we will be calling to check the authentication status which will determine which navigation stack is going to be mounted. We will create this function in our context and use it in the Appnavigator.js.

Now, let’s go ahead and create our TransitionScreen.js file.

screens > TransitionScreen.js

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

const TransitionScreen = () => {
  return (
    <View>
      <Text>Loading...</Text>
    </View>
  )
}

export default TransitionScreen

Our transition screen is just a simple screen that shows loading text. We will see where to use this as we proceed in this article.

Next, let us go to our AuthState.js and write our checkAuthenticationStatus():

context > authContext > AuthState.js

import React, { useState, useEffect } from 'react';
import AuthContext from './AuthContext';
import AsyncStorage from '@react-native-community/async-storage';

const AuthState = (props) => {
    const [userToken, setUserToken] = useState(null);
    const [isLoading, setIsLoading] = useState(true);

    ...
    useEffect(() => {
        checkAuthenticationStatus()
    }, [])
    
    const checkAuthenticationStatus = async () => {
        try {
            const returnedToken = await AsyncStorage.getItem('user-toke             n');
            setUserToken(returnedToken);
            console.warn('User token set to the state value)
        } catch(err){
            console.warn(`Here's the error that occured while retrievin             g token: ${err}`) 
        }
        setIsLoading(false)
    }


    const onAuthentication = async() => {
        ...
    }

    return (
        <AuthContext.Provider
            value={{
                onAuthentication,
                userToken,
                isLoading,
            }}
        >
            {props.children}
        </AuthContext.Provider>
    )
}
export default AuthState;

In the code block above, we wrote the function checkAuthenticationStatus(). In our function, here’s what we are doing:

  • We used the await keyword to get our token from AsyncStorage. With AsyncStorage, if there’s no token supplied, it returns null. Our initial userToken state is set to null also.
  • We use the setUserToken to set our returned value from AsyncStorage as our new userToken. If the returned value is null, it means our userToken remains null.
  • After the try{}…catch(){} block, we set isLoading to false because the function to check authentication status is complete. We’ll need the value of isLoading to know if we should still be displaying the TransitionScreen or not. It’s worth considering setting an error if there is an error retrieving the token so that we can show the user a “Retry” or “Try Again” button when the error is encountered.
  • Whenever AuthState mounts we want to check the authentication status, so we use the useEffect() ReactJS hook to do this. We call our checkAuthenticationStatus() function inside the useEffect() hook and set the value of isLoading to false when it is done.
  • Finally, we add our states to our <AuthContext.Provider/> values so that we can access them from anywhere in our app covered by the Context API.

Now that we have our function, it is time to go back to our AppNavigator.js and write the code for mounting a particular stack navigator based on the authentication status:

navigation > AppNavigator.js

First, we will import all we need for our AppNavigator.js.

import React, { useEffect, useContext } from "react";
import PreAuthNavigator from "./preAuthNavigator";
import PostAuthNavigator from "./postAuthNavigator";
import { NavigationContainer } from "@react-navigation/native"
import { createStackNavigator } from "@react-navigation/stack";
import AuthContext from "../../context/authContext/AuthContext";
import TransitionScreen from "../screens/TransitionScreen";

Now that we have all our imports, let’s create the AppNavigator() function.

...
const AppNavigator = () => {

}

export default AppNavigator

Next, we will now go ahead to write the content of our AppNavigator() function:

import React, { useState, useEffect, useContext } from "react";
import PreAuthNavigator from "./preAuthNavigator";
import PostAuthNavigator from "./postAuthNavigator";
import { NavigationContainer } from "@react-navigation/native"
import { createStackNavigator } from "@react-navigation/stack";
import AuthContext from "../../context/authContext/AuthContext";
import TransitionScreen from "../screens/transition";

const AppNavigator = () => {
    const { Navigator, Screen } = createStackNavigator();
    const authContext = useContext(AuthContext);
    const { userToken, isLoading } = authContext;
    if(isLoading) {
      return <TransitionScreen />
    }
    return (
    <NavigationContainer>
      <Navigator>
        { 
          userToken == null ? (
            <Screen
              name="PreAuth"
              component={PreAuthNavigator}
              options={{ header: () => null }}
            />
          ) : (
            <Screen 
              name="PostAuth"
              component={PostAuthNavigator}
              options={{ header: () => null }}
            />
          )
        }
      </Navigator>
    </NavigationContainer>
  )
}

export default AppNavigator

In the above block of code, here’s an outline of what we did:

  • We created a stack navigator and destructured the Navigator and Screen from it.
  • We imported the userToken and the isLoading from our AuthContext
  • When the AuthState mounts, the checkAuthenticationStatus() is called in the useEffecct hook there. We use the if statement to check if isLoading is true, if it is true the screen we return is our <TransitionScreen /> which we created earlier because the checkAuthenticationStatus() function is not yet complete.
  • Once our checkAuthenticationStatus() is complete, isLoading is set to false and we return our main Navigation components.
  • The NavigationContainer was imported from the @react-navigation/native. It is only used once in the main top-level navigator. Notice that we are not using this in the preAuthNavigator.js or the postAuthNavigator.js.
  • In our AppNavigator(), we still create a stack navigator. If the userToken gotten from our Context API is null, we mount the PreAuthNavigator, if its value is something else (meaning that the AsyncStorage.getItem() in the checkAuthenticationStatus() returned an actual value), then we mount the PostAuthNavigator. Our conditional rendering is done using the ternary operator.

Now we’ve set up our AppNavigator.js. Next, we need to pass our AppNavigator into our App.js file.

Let’s pass our AppNavigator into the App.js file:

App.js

 ...
import AppNavigator from './views/navigation/AppNavigator';

...
return (
    <AuthState>
      <AppNavigator />
    </AuthState>
  );

Let’s now see what our app looks like at the moment:

Here’s what happens when you supply an incorrect credential while trying to log in:

Adding The Logout Functionality #

At this point, our authentication and route selection process is complete. The only thing left for our app is to add the logout functionality.

The logout button is in the HomeScreen.js file. We passed an onLogout() function to the onPress attribute of the button. For now, we have a simple console.log() statement in our function, but in a little while that will change.

Now, let’s go to our AuthState.js and write the function for logout. This function simply clears the AsyncStorage where the user token is saved.

context > authContext > AuthState.js

...
const AuthState = (props) => {
    ...

    const userSignout = async() => {
        await AsyncStorage.removeItem('user-token');
        setUserToken(null);
    }


    return (
      ...
    )
}

export default AuthState;

The userSignout() is an asynchronous function that removes the user-token from our AsyncStorage.

Now we need to call the userSignout() function in our HomeScreen.js any time the logout button is clicked on.

Let’s go to our HomeScreen.js and use ther userSignout() from our AuthContext.

screens > postAuthScreens > HomeScreen.js

import React, { useContext } from 'react';
import { View, Text, Button, StyleSheet } from 'react-native';
import AuthContext from '../../../context/authContext/AuthContext'

const HomeScreen = () => {
  const { userSignout } = useContext(AuthContext)
  
  const onLogout = () => {
    userSignout()
  }
  return (
    <View style={styles.container}>
      <Text>Now you're authenticated! Welcome!</Text>
 <Button title="LOG OUT" onPress={onLogout} />
    </View>
  )
}
...

In the above code block we imported thee useContext hook from ReactJS, then we imported our AuthContext. Next, we destructured the userSignout function from our AuthContext and this userSignout() function is called in our onLogout() function.

Now whenever our logout button is clicked, the user token in our AsyncStorage is cleared.

Voila! our entire process is finished.

Here’s what happens when you press the back button after you’re logged in:

Pressing the back button after logging into the app.

Here’s what happens when you press the back button after logging out:

Pressing the back button after logging out of the app.

Here are some different behaviors we notice when using this pattern in our navigation stack switching:

  1. You’ll notice that there was nowhere we needed to make use of navigation.navigate() or navigation.push() to go to another route after login. Once our state is updated with the user token, the navigation stack rendered is automatically changed.
  2. Pressing the back button on your device after login is successful cannot take you back to the login page, instead, it closes the app entirely. This behavior is important because you don’t want the user to be able to return back to the login page except they log out of the app. The same thing applies to logging out — once the user logs out, they cannot use the back button to return to the HomeScreen screen, but instead, the app closes.

Conclusion #

In many Apps, authentication is one of the most important parts because it confirms that the person trying to gain access to protected content has the right to access the information. Learning how to do it right is an important step in building a great, intuitive, and easy to use/navigate the application.

Building on top of this code, here are a few things you might consider adding:

Here are also some important resources I found that will enlighten you more about authentication, security and how to do it right:

Resources #