i want to use the context provider to set the state of loading using react and typescript.
what i am trying to do? i want to set loading state to true or false when request starts and ends and provide access to this loading state to all components within main component.
i have tried to do so like in code below,
function useAnother(Id: string) {
const [compId, setCompId] = React.useState(undefined);
const [isLoading, setIsLoading] = React.useState(false);
const comp = useCurrentComp(Id);
const load = useLoad();
if (comp && comp.id !== compId) {
setCompId(comp.id);
const prevCompId = compId !== undefined;
if (prevCompId) {
setIsLoading(true);
load().then(() => {
setIsLoading(false);
});
}
}
}
function Main ({user}: Props) {
useAnother(user.id); //fetching isLoading here from useHook
return (
<Wrapper>
<React.suspense>
<Switch>
<Route
path="/"
render={routeProps => (
<FirstComp {...routeProps} />
)}
/>
<Route
path="/items"
render={routeProps => (
<SecondComp {...routeProps} />
)}
/>
//many other routes like these
</Switch>
</React.suspense>
</Wrapper>
);
}
function FirstComponent (isLoading) {
return (
<Wrapper isLoading={isLoadin}/>
);
}
with the context provider i have tried like below,
function useAnother(Id: string) {
const [compId, setCompId] = React.useState(undefined);
const loading = React.useContext(LoadingContext); //accessing context here
const comp = useCurrentComp(Id);
const load = useLoad();
if (comp && comp.id !== compId) {
setCompId(comp.id);
const prevCompId = compId !== undefined;
if (prevCompId) {
loading.setIsLoading(true); //gives error setIsLoading doesnt exist on type {}
load().then(() => {
loading.setIsLoading(false); //gives error setIsLoading doesnt exist on type {}
});
}
}
}
export const LoadingContext = React.createContext({});
export const LoadingContextProvider = ({ children }: any) => {
const [isLoading, setIsLoading] = React.useState(false);
return (
<LoadingContext.Provider
value={{
isLoading,
setIsLoading,
}}
>
{children}
</LoadingContext.Provider>
);
};
function Main ({user}: Props) {
useAnother(user.id); //fetching isLoading here from useHook
return (
<Wrapper>
<React.suspense>
<LoadingContext.Provider>
<Switch>
<Route
path="/"
render={routeProps => (
<FirstComp {...routeProps} />
)}
/>
<Route
path="/items"
render={routeProps => (
<SecondComp {...routeProps} />
)}
/>
//many other routes like these
</Switch>
</LoadingContext.Provider>
</React.suspense>
</Wrapper>
);
}
I am not sure why i get the error setIsLoading doesnt exist on type {} when i try to access the context in useAnother hook.
could someone help me with this. thanks.
If you initialize context like export const LoadingContext = React.createContext({});
, TS will infer the context state value as an empty object. You have to be explicit about types when creating the context.
For example,
interface ILoadingCtxState {
isLoading: boolean;
setIsLoading: React.Dispatch<React.SetStateAction<boolean>>;
// this is type for setIsLoading if you directly pass the setter you get from the useState hook
}
const initialLoadingState: ILoadingCtxState = {
isLoading: false,
setIsLoading: () => {}
}
export const LoadingContext = React.createContext<ILoadingCtxState>(initialLoadingState);
In the provider component,
export const LoadingContextProvider: React.FC = ({ children }) => {
const [isLoading, setIsLoading] = React.useState<boolean>(false);
// you can memoize the value that you pass by using React.useMemo
// example,
const memoized = React.useMemo(() => ({isLoading, setIsLoading}), [isLoading])
return (
<LoadingContext.Provider
value={memoized}
>
{children}
</LoadingContext.Provider>
);
};
When you use React.useContext
to consume to LoadingContext
you have to destructure the values, example
const {isLoading, setIsLoading} = React.useContext(LoadingContext)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.