我正在使用react的上下文来跨组件共享数据。
例如,我可以创建一个用户上下文:
const useFirebaseUser = () => {
const [user, setUser] = useState({} as User);
useEffect(() => {
return firebase.auth().onAuthStateChanged((user) => {
if (user) {
const { displayName, photoURL, uid } = user;
setUser({
displayName,
photoURL,
uid,
isAuthenticated: true,
} as User);
} else {
setUser({} as User);
}
});
}, []);
return user;
};
export const FirebaseUserContext = createContext({} as User);
export const GlobalFirebaseUserProvider = ({ children }: { children: ReactNode }) => (
<FirebaseUserContext.Provider value={useFirebaseUser()}>{children}</FirebaseUserContext.Provider>
);
类似地,我也可以创建一个类似的上下文来共享其他数据,比如todos
const useTodos = () => {
const [todos, setTodos] = useState(['']);
// ..
return { todos, setTodos };
};
export const TodosContext = createContext(
{} as { todos: string[]; setTodos: React.Dispatch<React.SetStateAction<string[]>> }
);
export const TodosContextProvider = ({ children }: { children: ReactNode }) => (
<TodosContext.Provider value={useTodos()}>{children}</TodosContext.Provider>
);
在此基础上,我想抽象出价值部分。我正在尝试创建一个通用提供商:
import React, { createContext, ReactNode } from 'react';
export const CreateGenericContext = <T extends {}>(value: T) => {
const GenericContext = createContext({} as T);
const GenericContextProvider = ({ children }: { children: ReactNode }) => (
<GenericContext.Provider value={value}>{children}</GenericContext.Provider>
);
return { GenericContext, GenericContextProvider };
};
因此,我的用户上下文可以简化为
export const {
GenericContext: UserContext,
GenericContextProvider: UserContextProvier,
} = CreateGenericContext(useUser());
但是,React抛出错误消息:错误:无效的挂钩调用。钩子只能在函数组件的主体内部调用。这可能是由于以下原因之一:
- React和渲染器的版本可能不匹配(例如React DOM(
- 你可能违反了胡克规则
- 同一应用程序中可能有多个React副本
这是否意味着无法为React创建通用上下文提供?我在网上搜索过,教程似乎显示,对于上下文,不使用钩子是可行的。然而,在使用react钩子的情况下,如何在react中创建通用上下文提供程序?
延迟自定义钩子,钩子只能在函数组件内部调用。
import React, { createContext, ReactNode } from 'react';
export const createGenericContext = <T extends {}>(hook: () => T) => {
const GenericContext = createContext({} as T);
const GenericContextProvider = ({ children }: { children: ReactNode }) => (
<GenericContext.Provider value={hook()}>{children}</GenericContext.Provider>
);
return { GenericContext, GenericContextProvider };
};