0.3.3 • Published 2 years ago

@andrewizbatista/use-context v0.3.3

Weekly downloads
-
License
MIT
Repository
github
Last release
2 years ago

useContext

A streamlined way of creating a React.Context based on a schema with ZERO dependencies.

Created by♥ @andrewizbatista

Table of Contents

Getting Started

Prerequisites

This package has peerDependencies that are required for you to include in your app's dependencies:

{
  "dependencies": {
    "react": "^17.0.2"
  }
}

Installing

yarn

yarn add @andrewizbatista/use-context

npm

npm install @andrewizbatista/use-context

Usage

In the following steps we are going to use a UserContext example. You can see more examples in the /examples folder.

1. Creating your Context file

First step is for you to create your context file. This file will export all the things you need to set and use that you just defined.

In the example below it's a simple context that fetches and saves a user object.

// UserContext.ts

import {
  createContextFromSchema,
  State,
  Actions,
  ContextSchema,
} from '@andrewizbatista/use-context';

/**
 * Step 1: Define the `State` interface.
 *
 * This interface should represent the `state` object.
 */
export interface UserState extends State {
  id: number;
  username: string;
  email: string;
}

/**
 * Step 2: Define the `Actions` interface.
 *
 * This interface should represent all the functions/methods
 * of your context.
 */
export interface UserActions extends Actions {
  readonly fetchUser: (id: number) => void;
  readonly getFormattedUserLine: () => string;
}

/**
 * Step 3: Create the `schema`
 *
 * This schema is the heart of everything, define its initial state
 * and all the actions.
 */
const schema: ContextSchema<UserState, UserActions> = {
  initialState: {
    id: 0,
    username: '',
    email: '',
  },
  actions: ({ state, setState }) => ({
    /**
     * Fetches a user from a mocked API
     */
    fetchUser: (id) =>
      fetch(`https://jsonplaceholder.typicode.com/users/${id}`)
        .then((res) => res.json())
        .then((data) => setState(data as UserState)),
    /**
     * Returns a formatted string that contains the `username` and the `email`
     */
    getFormattedUserLine: () => `${state.username} <${state.email}>`,
  }),
};

/**
 * Step 4: Create your context based on the `schema`
 *
 * Call the `createContextFromSchema` so it can generate the `Context`,
 * the `Provider` a `useContext` hook.
 *
 * Tip: In ES6 you can rename your object keys!
 */
export const {
  Context: UserContext,
  Provider: UserProvider,
  useContext: useUser,
} = createContextFromSchema<UserState, UserActions>(schema);

2. Understanding the exports

The context file should have a few exports so you can import them across your app.

import {
  /**
   * The TypeScript interface of your `state`
   */
  UserState,
  /**
   * The TypeScript interface of your `actions`
   */
  UserActions,
  /**
   * The original React Context component (you shouldn't need to use this,
   * because of the Provider below).
   */
  UserContext,
  /**
   * A smart React Context.Provider that handles all the state
   * update/render logic
   */
  UserProvider,
  /**
   * A `useContext` hook to allow you to access the context anywhere
   */
  useUser,
} from './UserContext';

3. Initializing the Provider

Now that you have everything setup, you just need to wrap your app/component with the UserProvider.

/**
 * Basic example of wrapping your app with the provider
 */
import { UserProvider } from 'contexts/UserContext';

function App() {
  return (
    <UserProvider>
      <Navbar />
      <Content />
      <Footer />
    </UserProvider>
  );
}

If you have a child Context that is dependent on the state of the parent one. Pass a render function as the children so you have access to the state object.

/**
 * Example where the child provider (`AuthenticationProvider`) is dependent
 * on the `state` of the parent provider (`UserProvider`)
 */
import { UserProvider } from 'contexts/UserContext';
import { AuthenticationProvider } from 'contexts/AuthenticationProvider'; // Just as an example

function App() {
  return (
    <UserProvider>
      {({ state: userState }) => (
        <AuthenticationProvider value={userState}>
          <Navbar />
          <Content />
          <Footer />
        </AuthenticationProvider>
      )}
    </UserProvider>
  );
}

4. Using the Context

You can access your context anywhere in your app by using the useUser hook

import { useEffect } from 'react';
import { useUser } from 'contexts/UserContext';

function MyUser(userId: number) {
  /**
   * Accessing both the `state` and `actions`
   * of your context.
   */
  const {
    state: { username, email },
    actions: { fetchUser },
  } = useUser();

  /**
   * Calling `fetchUser`
   */
  useEffect(() => {
    fetchUser(userId);
  }, [userId]);

  /**
   * Rendering some `state` props
   */
  return (
    <section>
      <h1>{username}</h1>
      <p>{email}</p>
    </section>
  );
}

Contributing

Want to help? Feel free to open an Issue or create a Pull Request and let's get started 🚀

License

MIT © André Batista (@andrewizbatista) 🎉