Skip to content

Instantly share code, notes, and snippets.

@mrasadatik
Last active May 10, 2022 12:57
Show Gist options
  • Save mrasadatik/b2e0f05b1415a94c62e49f2e0f63c090 to your computer and use it in GitHub Desktop.
Save mrasadatik/b2e0f05b1415a94c62e49f2e0f63c090 to your computer and use it in GitHub Desktop.
Detailed example and implementation of React ContextAPI in TypeScript way

//!!!!! TypeScript Solution - For JavaScript visit my profile

/* Implement React ContextAPI in TypeScript using the complex way
and use it to the calmy way.
Optional COOKIE feature added (npm i universal-cookie)*/

//** First thing first create a provider component
//** πŸ“„ StateProvider.ts (.tsx)
import * as React from "react";
/*import Cookies from "universal-cookie";

const cookies = new Cookies();

interface CookieExpiryProps {
    interval: number;
    intervalBy: "ms" | "s" | "m" | "h" | "d" | "mo" | "y";
}

const CookieExpiry = (props: CookieExpiryProps) => {
    const { interval, intervalBy } = props; // Here interval variable is holding the period and intervalBy variable holding the unit (eg. millisecond, second, munite, hour, day, month and year)
    let expire = new Date();
    if (intervalBy === "ms") {
        expire.setMilliseconds(expire.getMilliseconds() + interval);
    } else if (intervalBy === "s") {
        expire.setSeconds(expire.getSeconds() + interval);
    } else if (intervalBy === "m") {
        expire.setMinutes(expire.getMinutes() + interval);
    } else if (intervalBy === "h") {
        expire.setHours(expire.getHours() + interval);
    } else if (intervalBy === "d") {
        expire.setDate(expire.getDate() + interval);
    } else if (intervalBy === "mo") {
        expire.setMonth(expire.getMonth() + interval);
    } else if (intervalBy === "y") {
        expire.setFullYear(expire.getFullYear() + interval);
    }
    return expire;
};

const cookieOptions = {
    path: "/",
    expires: CookieExpiry({ interval: 1, intervalBy: "y" }),
    maxAge: (CookieExpiry({ interval: 1, intervalBy: "y" }).getTime() - new Date().getTime()) / 1000,
    secure: true, //if you are on localhost set it to - false
    httpOnly: true, //if you are on localhost set it to - false
    sameSite: true, //value can be changed to - Lax, None, Strict
};*/ //(Uncomment if you're adding cookie Feature)

interface StateProviderProps {
    children?:
        | React.ReactChild
        | React.ReactNode
        | React.ReactElement
        | React.ReactChild[]
        | React.ReactNode[]
        | React.ReactElement[];
}

type ModeContextTypes = {
    mode: "light" | "dark";
    changeMode: (newMode: "light" | "dark") => void;
};

const ModeContextDefaultValue: ModeContextTypes = {
  	mode: "light", // (comment it if you're adding cookie Feature)
    //mode: cookies.get("mode") === undefined ? "light" : cookies.get("mode"), //(Uncomment if you're adding cookie Feature)
  	changeMode: () => {},
};
export const ModeContext = React.createContext<ModeContextTypes>(ModeContextDefaultValue);

const StateProvider = ({ children }: StateProviderProps) => {
	// this state will be shared with all components
	const [mode, setMode] = React.useState<"light" | "dark">(ModeContextDefaultValue.mode);
  	const changeMode = (newMode: "light" | "dark") => {
        //cookies.set("mode", newMode, cookieOptions); //(Uncomment if you're adding cookie Feature)
        setMode(newMode);
    };
 	return(
    	// this is the provider providing state
        <ModeContext.Provider value={{ mode, changeMode }}>
     		{children}
        </ModeContext.Provider>
    );
}

export default StateProvider;
//** End of πŸ“„ StateProvider.ts (.tsx)

/* *** We created and modified our provider, now our second work is to add
or call this provider into the root file of our project, maximum time our
root file is called App.js (.jsx). Let's create it or modife existing one!*/
//** πŸ“„ App.ts (.tsx)
import * as React from "react";
import StateProvider from "./StateProvider"; //Path to your StateProvider.js (.jsx) file
import Index from "./Index"; //Path to you Index Component you can import any component.

const App = () => {
	return(
    	<StateProvider>
      		<Index />
      		// Define Every single component where you want to access states that is defined into StateProvider.
      	</StateProvider>
    );
}

export default App;
//** End of πŸ“„ App.ts (.tsx)

/* In above steps we created and modified our provider and then we
impliment or you can say initialized our provider into root file of
our project. Now we are ready to access our states that is defined
into our provider from any component that is defined or call inside
App's StateProvider Block. Currently for testing purpose we added - Index
component into StateProvider Block of App file. So technically we can
access all the states defined into provider from Index component. Let's
see how we can do it.*/
//** πŸ“„ Index.tsx (.ts)
import * as React from "react";
import { ModeContext } from "./StateProvider";

const Index = () => {
  	//const { mode } = React.useContext(ModeContext); // Uncomment if you are only accessing the state and don't want to update the state.
  	//const { changeMode } = React.useContext(ModeContext); // Uncomment if you are only updating the state and don't want to access the state.
	const { mode, changeMode } = React.useContext(ModeContext); // we are using this because we are accessing the state and want to update this state at the same time or same component.
  	const updateMode = (event: React.MouseEvent<HTMLElement>) => {
      	changeMode(event.target.value); // If you added the cookie feature this one call will also set cookie for you no additioan work needed.
      	//console.log(event.target.value); //see update on log
    }
  	return (
    	<React.Fragment>
      		<h1>Current display color mode is set to {mode}</h1>
			<div>
      			<h6>Play with it</h6>
      			<div onChange={updateMode}>
                  	<input type="radio" value="light" name="mode" checked={mode === "light"} /> Light
                  	<input type="radio" value="dark" name="mode" checked={mode === "dark"}/> Dark
                </div>
      		</div>
      	</React.Fragment>
    );
}
//** End of πŸ“„ Index.tsx (.ts)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment