[英]How to use the useHook in the component rather than passing the value returned from it as a prop to the components using react and typescript?
i want to use useHook within the component itself rather than passing it as a prop to each component using react and typescript.我想在组件本身中使用 useHook,而不是使用 react 和 typescript 将其作为道具传递给每个组件。
what i am trying to do?我想做什么? I have a useHook named useRefresh which returns isLoading state.我有一个名为 useRefresh 的 useHook,它返回 isLoading state。 This isLoading state is used to display a loading indicator in each of the pages. This isLoading state 用于在每个页面中显示加载指示器。
so i have three pages and whenever this isLoading is true should display a loading indicator in these pages.所以我有三个页面,只要这个 isLoading 为真,就应该在这些页面中显示一个加载指示器。
below is my code,下面是我的代码,
function App(){
const user = useGetUser();
return (
<Router>
<Switch>
<Route
path="/"
render={props: any => (
user ? (<Main {...props} />) : (
<LoginPage/>
);
)}
</Route>
</Switch>
</Router>
);
}
export function useLoad() {
const { refetch: refetchItems } = useGetItems();
const { refetch: refetchOwnedItems } = useListOwnedItems();
return async function() {
await refreshCompany();
refetchItems();
refetchOwnedItems();
};
}
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);
return (
<Router>
<Switch>
<Route
path="/"
render={routeProps => (
<FirstComp {...routeProps} />
)}
/>
<Route
path="/items"
render={routeProps => (
<SecondComp {...routeProps} />
)}
/>
//many other routes like these
</Switch>
</Router>
);
}
function FirstComp () {
return(
<Wrapper>
//some jsx
</Wrapper>
);
}
function SecondComp () {
return(
<Wrapper>
//some jsx
</Wrapper>
);
}
Now i want to pass isLoading state to each of the components in Main component....so i have passed it like below,现在我想将 isLoading state 传递给主要组件中的每个组件....所以我已经像下面一样传递了它,
function Main ({user}: Props) {
const isLoading = useAnother(user.id); //fetching isLoading here from useHook
return (
<Router>
<Switch>
<Route
path="/"
render={routeProps => (
<FirstComp isLoading={isLoading} {...routeProps} />
)}
/>
<Route
path="/items"
render={routeProps => (
<SecondComp isLoading={isLoading} {...routeProps} />
)}
/>
//many other routes like these
</Switch>
</Router>
);
}
function FirstComp ({isLoading}: Props) {
return(
<Wrapper>
displayIndicatorWhen(isLoading);
//some jsx
</Wrapper>
);
}
function SecondComp ({isLoading}: Props) {
return(
<Wrapper>
displayIndicatorWhen(isLoading);
//some jsx
</Wrapper>
);
}
This works.这行得通。 but doesnt seem like a right approach to me.. i dont want to pass this isLoading state as a prop to each of these components.但对我来说似乎不是一个正确的方法.. 我不想通过这个 isLoading state 作为这些组件中的每一个的道具。 there are more than 10 of them.其中有10多个。
is there someway that i can do it other way than this.有没有其他方法可以做到这一点。 could someone help me with this.有人可以帮我解决这个问题。 thanks.谢谢。
The most common solution is to create a context that wraps the entire tree of components.最常见的解决方案是创建一个包含整个组件树的上下文。 This context holds the state that your hook pulls in此上下文包含您的钩子拉入的 state
////LoadingContext.tsx
const LoadingContext = createContext();
const LoadingContextProvider = () => {
const [isLoading, setIsLoading] = useState(false);
return (
<LoadingContextProvider.Provider
value={{
isLoading,
setIsLoading
}}
/>
)
}
export const useLoading = () => useContext(LoadingContext);
You need to wrap the context around anything that will be calling useLoading
:您需要将上下文围绕将调用useLoading
的任何内容:
import { LoadingContextProvider } from './LoadingContext' //or wherever this is relative to Main.tsx
<LoadingContextProvider>
<Router>
...(router stuff)
</Router>
</LoadingContextProvider>
Now you can call useLoading in your lower-level components.现在您可以在较低级别的组件中调用 useLoading。
//in another file defining a lower-level component:
import { useLoading } from '../../LoadingContext' //or wherever the context stuff is relative to this component definition
const FirstComp = () =>
const [isLoading, setIsLoading] = useLoading();
const handleClick = () => {
setIsLoading(true);
callMyApi().then(() => setIsLoading(false));
}
if(isLoading){
return <LoadingGif />
}
else{
return <div onClick={handleClick}>Click me!</div>
}
)}
What you would like to accomplish here is called global state.你想在这里完成的是全局 state。 There are many ways to do it, but I think the simplest is the native React Context API.有很多方法可以做到,但我认为最简单的是原生的 React Context API。
All you have to do is create a ContextProvider
and then use the useContext
hook inside your components to access the values it provides.您所要做的就是创建一个ContextProvider
,然后在组件中使用useContext
挂钩来访问它提供的值。
Here is an example that should work for your case:这是一个适用于您的案例的示例:
Main.js主.js
export const LoadingContext = React.createContext(true); //creating and exporting the context
function Main ({user}: Props) {
const isLoading = useAnother(user.id); //fetching isLoading here from useHook
return (
<LoadingContext.Provider value={isLoading}> {/* providing the value to the children */}
<Router>
<Switch>
<Route
path="/"
render={routeProps => (
<FirstComp {...routeProps} />
)}
/>
<Route
path="/items"
render={routeProps => (
<SecondComp {...routeProps} />
)}
/>
//many other routes like these
</Switch>
</Router>
</LoadingContext.Provider>
);
}
export default Main;
Other components其他组件
import {LoadingContext} from './Main.js'
function FirstComp ({}: Props) {
const isLoading = useContext(LoadingContext); //accessing the value
return(
<Wrapper>
displayIndicatorWhen(isLoading);
//some jsx
</Wrapper>
);
}
function SecondComp ({}: Props) {
const isLoading = useContext(LoadingContext); //accessing the value
return(
<Wrapper>
displayIndicatorWhen(isLoading);
//some jsx
</Wrapper>
);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.