Your use case here will be consumed by something outside of React (an Apollo Link), so Context does not make any sense here - Context would make a value available to children in the React tree, but your link is not a child in a React Tree.
Instead you can just export an object and modify that object (you probably cannot reassign it depending on how you import/export it, but you can always modify it).
// index.js
export const globalData = {
auth: null
}
// anywhere else
import { globalData } from './index.js'
globalData.auth = "foo"
That said, you can only work with global data like this if you are not using SSR. If you are using SSR (e.g. in a Client Component in Next.js), you'd need to find another way of doing that.
In that case, you could use Apollo CLient's defaultContext.
reactjs - Using context to store variable globally React.js - Stack Overflow
When Should i use use context and when should i use global state managment . I am new to react can you share some best pratices.
reactjs - How manage global state using context API in React js - Stack Overflow
Is anyone familiar with using Context in react to set global variables
Videos
Your use case here will be consumed by something outside of React (an Apollo Link), so Context does not make any sense here - Context would make a value available to children in the React tree, but your link is not a child in a React Tree.
Instead you can just export an object and modify that object (you probably cannot reassign it depending on how you import/export it, but you can always modify it).
// index.js
export const globalData = {
auth: null
}
// anywhere else
import { globalData } from './index.js'
globalData.auth = "foo"
That said, you can only work with global data like this if you are not using SSR. If you are using SSR (e.g. in a Client Component in Next.js), you'd need to find another way of doing that.
In that case, you could use Apollo CLient's defaultContext.
if u want to store a variable globally u can use context api or redux-tool kit here i am giving a rough idea how u can achieve this using context API first Create A folder usually context.. inside this create a file usually name as DataProvider.jsx and do thing like this
import { createContext, useState } from 'react';
export const DataContext = createContext(null);
const DataProvider = ({ children }) => {
const [Client, setClient] = useState([]);
return (
<DataContext.Provider value={{
Client, setClient
}}
>
{children}
</DataContext.Provider>
)
}
export default DataProvider;
next step u should wrap your app.js like this
import DataProvider from './context/DataProvider';
function App() {
return (
<DataProvider>
<Home />
</DataProvider>
);
}
export default App;
now u can setclient or u can use client data like below
assume u have a file name Client.jsx where u want to set the client data
const { setCleint} = useContext(DataContext)
set the Client data to setClient just as normal state now in similar way u can render the client list anywhere like this
const { Cleint} = useContext(DataContext);
I feel like use context can go pretty much everthing but zustand makes it even more easier .
You can try out this implemetation with reducers to handle for you the state change with localstorage. It is not an exact implemetation of your's but you can see the flow
In the AppContext.jsx
The AppContext holds the global state of the application so that it's easier working with a single context provider and dispatching actons to specific reducers to handle state change without providing many providers.
The combinedReducers handle reducer methods to a given state component
import { useReducer, createContext, useEffect } from "react";
import userReducer from "./reducers/userReducer";
import themeReducer from "./reducers/themeReducer";
export const APP_NAME = "test_app";
//Check the localstorage or set a default state
const initialState = JSON.parse(localStorage.getItem(APP_NAME))
? JSON.parse(localStorage.getItem(APP_NAME))
: {
user: {
username: "",
email: "",
isAdmin: false,
},
theme: { dark: false },
};
//Create your global context
const AppContext = createContext(initialState);
//Create combined reducers
const combinedReducers = ({ user, theme }, action) => ({
user: userReducer(user, action),
theme: themeReducer(theme, action),
});
const AppState = ({ children }) => {
//Making it to provider state
const [state, dispatch] = useReducer(combinedReducers, initialState);
useEffect(() => {
localStorage.setItem(APP_NAME, JSON.stringify(state));
}, [state]);
return (
<AppContext.Provider value={{ state, dispatch }}>
{children}
</AppContext.Provider>
);
};
export default AppState;
export { AppContext, AppState };
The above implementation works like redux but you destructure the given state to a specific reducer to handle the state change
In this I have used localstorage to keep a persistent state because with context API on page reload the state goes. Use the useEffect hook from react and add the state in the dependency array to ensure your state is in sync
In the UserReducer.jsx
const userReducer = (state, action) => {
const { type, payload } = action;
switch (type) {
case "LOGIN":
return { ...state, ...payload };
case "LOGOUT":
return {};
default:
return state;
}
};
export default userReducer;
In the ThemeReducer.jsx
const themeReducer = (state, action) => {
const { type, payload } = action;
switch (type) {
case "DARK":
return { ...payload };
default:
return state;
}
};
export default themeReducer;
Wrapping the whole app with a single provider in the index.jsx
import reactDom from "react-dom"
import React from "react"
import App from "./App"
import "./index.css"
import AppState from "./state/AppState"
reactDom.render(
<React.StrictMode>
<AppState >
<App />
</AppState>
</React.StrictMode>,
document.getElementById("root")
)
Accessing the context from App.jsx
import { useContext } from "react";
import { AppContext } from "./state/AppState";
const App = () => {
const { state, dispatch } = useContext(AppContext);
const handleLogin = () => {
dispatch({
type: "LOGIN",
payload: {
username: "Mike",
email: "[email protected]",
isAdmin: false,
},
});
};
const handleLogout = () => {
dispatch({
type: "LOGOUT",
payload: {},
});
};
return (
<div className="main-container">
<div className="container">
<p>Username: {state.user.username ? state.user.username : "Unknown"}</p>
<p>Email: {state.user.email ? state.user.email : "Unknown"}</p>
</div>
<button onClick={handleLogin}>Login</button>
<button onClick={handleLogout} style={{ background: "red" }}>
Login
</button>
</div>
);
};
export default App;
Here is my code LINK if you want to see the structure Github
Short answer, use react-context-slices. It's a library that allows you to define slices of Context and fetch them through a unique hook, useSlice. You must pass the name of the slice you want to fetch and this hook will return to you the value or state of the slice and a setter/dispatch function, depending on if you defined a reducer or not for the slice.
Here is an example on how you do it with this library:
// slices.js
import getHookAndProviderFromSlices from "react-context-slices"
export const {useSlice, Provider} = getHookAndProviderFromSlices({
count: {initialArg: 0},
// rest of slices of Context you want to define
})
// app.js
import {useSlice} from "./slices"
const App = () => {
const [count, useCount] = useSlice("count")
return <>
<button onClick={() => setCount(c => c + 1)}>+</button>{count}
</>
}
Hope this helps anyone planning to use Context API for state management in a react app.