Learn how to implement AuthContext and createDataContext in React Native Expo development using TypeScript

AuthContext.tsx

import createDataContext from './createDataContext';
import serverApi from '../api/server';

const authReducer = ({state, action}: any) => { 
    switch(action.type){
        default:
            return state;
    }
};

const signup = () => {
    return  async ({email, password}: any) => {
        try{
            const response = await serverApi.post('/signup', {email, password});
            console.log(response.data)
        }catch(err){
            console.log(err.message);
        }
    };
}

const signin = ({dispatch}:any) => {
    return ({email, password}: any) => {    };
}

const signout = ({dispatch}: any) => {
    return () => {};
}

export const {Provider, Context} = createDataContext(
    authReducer,
    {signin, signout, signup},
    {isSignedIn: false}
);

createDataContext

import React, { useReducer } from 'react';

export default ({reducer, actions, defaultValue}: any) => {
    const Context = React.createContext();

    const Provider = ({ children }: any) => {
        const [state, dispatch] = useReducer(reducer, defaultValue);
    
        const boundActions: any = {};
        for (let key in actions) {
          boundActions[key] = actions[key](dispatch);
        }
    
        return (
          <Context.Provider value={{ state, ...boundActions }}>
            {children}
          </Context.Provider>
        );
      };
    
      return { Context, Provider };
}

I took inspiration from a video tutorial on developing a react native app with js extension. However, the project I am currently working on uses tsx extension, which is TypeScript. How can I modify the above code to make it compatible with my TypeScript react native mobile app?

Answer №1

({reducer, actions, defaultValue}: any)
is anticipating a single argument with three properties. However, when you invoke it, you are providing three distinct arguments. Therefore, the correct format should be
(reducer: any, actions: any, defaultValue: any)
. Similarly, a reducer expects two arguments, so you should have
authReducer = (state: any, action: any) =>
, and so forth for several of your functions.

Now, the goal is to eliminate all instances of any and utilize actual types! Some of these types can be imported from react, while others will need to be defined by us.

The challenging part lies in guiding your context to recognize the types for your specific action creators and the arguments required by each one. This way, you can benefit from autocomplete suggestions for the actions and detect any improper calls. Yet, this requires more advanced TypeScript concepts such as generics and mapped types. So, just copy and paste this code without getting overly concerned.

import React, { useReducer, FunctionComponent, Reducer, Dispatch } from 'react';

interface DataState {
  isSignedIn: boolean;
  // Include any additional properties here
}

interface SignInProps {
  email: string;
  password: string;
}

// You have the flexibility to modify this
// It's common to use a type for `Action` that represents a union of your specific actions
interface Action {
  type: string;
  payload: any;
}

// Here's where things get interesting
type BoundActions<T> = {
  [K in keyof T]: T[K] extends (d: Dispatch<Action>) => infer R ? R : never
}
type ContextValue<T> = {
  state: DataState;
} & BoundActions<T>

export const createDataContext = <T extends {}>(reducer: Reducer<DataState, Action>, actions: T, defaultValue: DataState) => {
  // The context necessitates a defaultValue
  const Context = React.createContext({state: defaultValue} as ContextValue<T>);

  // By assigning the type FunctionComponent to Provider, the type of children is recognized
  const Provider: FunctionComponent = ({ children }) => {
    const [state, dispatch] = useReducer(reducer, defaultValue);

    const boundActions = {} as BoundActions<T>;
    for (let key in actions) {
      // @ts-ignore - We're going to ignore this to avoid confusion
      boundActions[key] = actions[key](dispatch);
    }

    return (
      <Context.Provider value={{ state, ...boundActions }}>
        {children}
      </Context.Provider>
    );
  };

  return { Context, Provider };
}

const authReducer = (state: DataState, action: Action): DataState => {
  switch (action.type) {
    default:
      return state;
  }
};

const signup = (dispatch: Dispatch<Action>) => {
  return async ({ email, password }: SignInProps) => {
    try {
      const response = await serverApi.post('/signup', { email, password });
      console.log(response.data)
    } catch (err) {
      console.log(err.message);
    }
  };
}

const signin = (dispatch: Dispatch<Action>) => {
  return ({ email, password }: SignInProps) => { };
}

const signout = (dispatch: Dispatch<Action>) => {
  return () => { };
}

export const { Provider, Context } = createDataContext(
  authReducer,
  { signin, signout, signup },
  { isSignedIn: false }
);

The purpose behind these efforts is to enable intellisense and type validation when using the context.

import React, { useContext } from 'react';
import { Provider, Context } from .... // Insert your path

const SampleComponent = () => {
  // Familiarizes itself with all available properties on the context
  const {state, signin, signout, signup} = useContext(Context);

  const handleClick = () => {
    // Recognizes the requirement for email and password in these calls
    signin({email: '', password: ''});
    signup({email: '', password: ''});
    // Understands that this call needs no arguments
    signout();
  }

  return (
    <div>{state.isSignedIn ? "Signed In!" : "Not Signed In"}</div>
  )
}

const SampleApp = () => (
  <Provider>
    <SampleComponent/>
  </Provider>
)

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Exploring Inclusivity within React-Native

I came across an article discussing the AccessibilityInfo API as part of react-native AX APIs, but I couldn't locate it in their repository. Does anyone know if this feature is still supported? Check out the react-native GitHub repository here ...

Setting the timezone for the DateTimeInput component in React-Admin is a crucial step for

My API returns datetime in the format '2021-12-31T16:00:00.000Z' I need to use DateTimeInput and consistently show it in UTC+8 timezone. After the user submits the form, it should convert back to the original format '2021-12-31T16:00:00.000 ...

Error: React Beautiful D&D is unable to retrieve dimensions when no reference is specified

Hey everyone! I'm currently working on a meta form creator and having some trouble with performance issues. I created a sandbox to ask for help, but keep getting the error message "Cannot get dimension when no ref is set" when trying to drag a second ...

Issue with binding nested ViewModels/components in Knockoutjs using TypeScript does not resolve

Struggling with implementing a viewModel within another viewModel in knockout. Any assistance would be greatly appreciated. Using typescript and aiming to have a list of address controls, each with their individual viewmodel. Initially, the project functi ...

Do not use unnecessary variables for storing references in ES6

Despite using react es6, I am still unsure how to refrain from needing to use the variable that for this scenario: const that = this; UploadApi.exec(file).then(data => { that.setState({ loading : false}); }); ...

Exploring Angular 4 with the power of Rangy modules

I've recently started working with Angular 4 and decided to create a basic app by forking the Angular quickstart. Now, I'm facing a challenge as I try to incorporate Rangy into my project. In my package.json, the dependencies are listed as follo ...

Should I generate separate views in React for every table in my backend?

As a beginner in the world of React, I find myself grappling with its intricate structure. Currently, my backend consists of three tables that are powered by Express.js; however, the focus now shifts to creating a CRUD UI interface for these tables withi ...

Exploring Heroes in Angular 2: Retrieving Object Information by Clicking on <li> Items

Currently, I am delving into the documentation for an angular 4 project called "Tour of Heroes" which can be found at https://angular.io/docs/ts/latest/tutorial/toh-pt2.html. <li *ngFor="let hero of heroes" (click)="onSelect(hero)">{{hero.name}}< ...

Changing the designated materialUI class

Within the project, I am utilizing this theme: export const theme = createMuiTheme({ ...defaultThemeConfig, overrides: { ...defaultThemeConfig.overrides, MuiListItem: { root: { '&:nth-child(odd)': { backgro ...

How can JSON be best connected in Angular for optimal performance?

My JSON structure is as follows: { items:[], errors:[], foundItems:9 } One part of my program requires access to "items", while another part needs access to "errors." To resolve this issue, I decided to create a new interface and a new class to hand ...

Is it feasible to deduce the generic type of a function by considering all remaining arguments?

I'm working with code that looks like this: type Boxed<T> = { inner: T } const box = <T>(inner: T): Boxed<T> => ({ inner }); function test<T extends Boxed<any>>(...args: T[]): T extends Boxed<infer I> ? I : ne ...

Although VSCode is functioning properly, there seems to be a discrepancy between the VSCode and the TS compiler, resulting in an

While developing my project in VSCode, I encountered an issue with accessing req.user.name from the Request object for my Node.js Express application. VSCode was indicating that 'name' does not exist in the 'user' object. To address thi ...

What steps can be taken to troubleshoot and resolve this specific TypeScript compilation error, as well as similar errors that may

I am struggling with this TypeScript code that contains comments and seems a bit messy: function getPlacesToStopExchange(): { our: { i: number; val: number; }[]; enemy: { i: number; val: number; }[]; //[party in 'our' | 'enemy' ]: ...

Using flexbox for a sleek React design

As a newcomer to the world of React Native, I am embarking on a quest to create this particular layout: The challenge lies in achieving a design where the upper box dynamically adjusts its height based on content while also reaching half the screen height ...

Issues with Next.js and Framer Motion

My component is throwing an error related to framer-motion. What could be causing this issue? Server Error Error: (0 , react__WEBPACK_IMPORTED_MODULE_0__.createContext) is not a function This error occurred during page generation. Any console logs will be ...

How do I remove the scroll bar from the datagrid using Material UI?

https://i.stack.imgur.com/lM01l.png Is there a way to remove the scroll bar at the bottom of the page? I have already attempted using autoPageSize, but it did not solve the issue. Here is the link to the autoPageSize documentation. import { DataGrid } f ...

Adjust the text size for groupBy and option labels in Material UI Autocomplete without altering the size of the input field

Currently, I am utilizing Material-UI and ReactJS to implement grouped autocomplete functionality. See the code snippet below: import * as React from "react"; import TextField from "@mui/material/TextField"; import Autocomplete from &q ...

Utilizing NPM Workspace Project in conjunction with Vite to eliminate the necessity of the dist folder during the Vite build process

I am currently working on a project that involves a module using full path exports instead of index files. This project is divided into 2 NPM workspaces: one called core and the other called examples. The challenge I am facing is avoiding long import pat ...

What is the best way to showcase the outcome of a function on the user interface in Angular 2?

The code snippet below was originally in my .component.html file: <div class="someContainer"> <div class="text--bold">Display this please:</div> <div>{{ myObject.date ? '2 Jun' : 'Now' }}</div&g ...

What is the best way to implement buttons for updating and deleting items in an Autocomplete menu using Material-ui in React.js?

Currently, I am working on developing an autocomplete feature that allows me to dynamically add, update, and delete options in the select menu while it is open. With the help of Material-UI Autocomplete Creatable component, I was able to easily implement ...