@andrewizbatista/use-context v0.3.3
useContext
A streamlined way of creating a React.Context
based on a schema
with ZERO dependencies.
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) 🎉