为了在 Typescript 中更改来自消费者的上下文,将什么设置为提供者的值?
What to set as the Provider's value in order to change context from a Consumer, in Typescript?
我正在尝试学习如何在 React 中使用钩子和上下文,但需要使用 TypeScript(也是新手)。
我的用例是授权:用户登录或未登录,并具有角色(例如 'Admin'、'Super Admin')。根据他们的授权状态,导航栏呈现不同。
除其他外,我正在尝试遵循 this 示例,根据我的需要进行了简化。
到目前为止,这是我的上下文和提供者:
import React, { createContext, useContext, Context, FC SetStateAction, useState } from 'react';
export interface IAuth {
loggedIn: boolean,
role: string
}
export const AuthContext = React.createContext<IAuth>({
loggedIn: false,
role: ''
});
const AuthProvider: FC = ({children}) => {
const [auth, setAuth] = useState({
loggedIn: false,
role: ''
});
return (
<AuthContext.Provider value={/*What to set as value?*/}>
{children}
</AuthContext.Provider>
)
}
export default AuthProvider;
然后是我的导航栏,它使用了上下文的消费者:
class Nav extends React.Component {
render() {
return (
<AuthContext.Consumer>
{context => (
< div >
.. stuff ...
</div>
<ul className="nav">
{context.loggedIn ? (
<Fragment> .. links .. </Fragment>
) : (<Fragment> .. links .. </Fragment>
)}
</ul>
</div>
)
}
</AuthContext.Consumer>
)
}
} export default Nav;
如果我这样设置 Provider 的值,所有这些都可以正常工作:
<AuthContext.Provider value={{
loggedIn: false,
role: 'someRole'
}}>
但是,我还想提供 setAuth
功能,以便从登录组件等更改这些值。
使用以下命令会出现错误:
<EmailContext.Provider value={[state, setState]}>
即Type '({ loggedIn: boolean; role: string; } | Dispatch<SetStateAction<{ loggedIn: boolean; role: string; }>>)[]' is missing the following properties from type 'IAuth': loggedIn, role
使用以下也给我错误:
<AuthContext.Provider value={{data: auth,
updateAuth: () => { setAuth({... auth, loggedIn: true})}
}}>
data: auth
错误:Type '{ data: { loggedIn: boolean; role: string; }; updateAuth: () => void; }' is not assignable to type 'IAuth'.
Object literal may only specify known properties, and 'data' does not exist in type 'IAuth'.
我尝试过的各种其他事情也出现类似错误。
这些都是 Typescript 错误。如何以 Typescript 兼容的方式设置我的 Provider 值 - 并包括 set
操作而不仅仅是值?
要在您的上下文中使用 auth 和 setAuth 状态,这是一种方法:
export const AuthContext = React.createContext<IAuth>({{}, ()=> {}});
const [auth, setAuth] = useState({
loggedIn: false,
role: ''
});
return (
<AuthContext.Provider value={{auth, setAuth}}>
{children}
</AuthContext.Provider>
)
在nav组件中,可以导入{AuthContext}
和
const {auth, setAuth} = React.useContext(AuthContext)
您不需要使用带钩子的 renderProps。您可以在代码中直接使用 auth
的值。
PS:我没用过typescript,但是react的方式还是一样的。
首先定义一个接口,其中包含应通过上下文传递的所有内容
export interface IAuth {
loggedIn: boolean;
role: string;
logIn: () => void;
logOut: () => void;
}
然后是提供者
export const AuthContext = React.createContext<IAuth>(null);
const AuthProvider: FC = ({ children }) => {
const [auth, setAuth] = useState({
loggedIn: false,
role: ""
});
const logIn = () => {
setAuth(prevState => ({
...prevState,
loggedIn: true
}));
};
const logOut = () => {
setAuth(prevState => ({
...prevState,
loggedIn: false
}));
};
return (
<AuthContext.Provider
// Here as value you need to pass the same interface as IAuth
// You can also just pass setAuth and do whatever you want
// from the children
value={{
...auth,
logIn,
logOut
}}>
{children}
</AuthContext.Provider>
);
};
然后在您的消费者中,您可以使用 useContext
挂钩来访问值
const Child: FC = () => {
const { loggedIn, role, logIn, logOut } = useContext(AuthContext);
return (
<div>
<p>{`loggedIn: ${loggedIn}`}</p>
<p>{`role: ${role}`}</p>
<button onClick={logIn}>logIn</button>
<button onClick={logOut}>logOut</button>
</div>
);
};
最后将 Child
渲染为 AuthProvider
的子级
const App: FC = () => (
<AuthProvider>
<Child />
</AuthProvider>
);
我正在尝试学习如何在 React 中使用钩子和上下文,但需要使用 TypeScript(也是新手)。
我的用例是授权:用户登录或未登录,并具有角色(例如 'Admin'、'Super Admin')。根据他们的授权状态,导航栏呈现不同。
除其他外,我正在尝试遵循 this 示例,根据我的需要进行了简化。
到目前为止,这是我的上下文和提供者:
import React, { createContext, useContext, Context, FC SetStateAction, useState } from 'react';
export interface IAuth {
loggedIn: boolean,
role: string
}
export const AuthContext = React.createContext<IAuth>({
loggedIn: false,
role: ''
});
const AuthProvider: FC = ({children}) => {
const [auth, setAuth] = useState({
loggedIn: false,
role: ''
});
return (
<AuthContext.Provider value={/*What to set as value?*/}>
{children}
</AuthContext.Provider>
)
}
export default AuthProvider;
然后是我的导航栏,它使用了上下文的消费者:
class Nav extends React.Component {
render() {
return (
<AuthContext.Consumer>
{context => (
< div >
.. stuff ...
</div>
<ul className="nav">
{context.loggedIn ? (
<Fragment> .. links .. </Fragment>
) : (<Fragment> .. links .. </Fragment>
)}
</ul>
</div>
)
}
</AuthContext.Consumer>
)
}
} export default Nav;
如果我这样设置 Provider 的值,所有这些都可以正常工作:
<AuthContext.Provider value={{
loggedIn: false,
role: 'someRole'
}}>
但是,我还想提供 setAuth
功能,以便从登录组件等更改这些值。
使用以下命令会出现错误:
<EmailContext.Provider value={[state, setState]}>
即Type '({ loggedIn: boolean; role: string; } | Dispatch<SetStateAction<{ loggedIn: boolean; role: string; }>>)[]' is missing the following properties from type 'IAuth': loggedIn, role
使用以下也给我错误:
<AuthContext.Provider value={{data: auth,
updateAuth: () => { setAuth({... auth, loggedIn: true})}
}}>
data: auth
错误:Type '{ data: { loggedIn: boolean; role: string; }; updateAuth: () => void; }' is not assignable to type 'IAuth'.
Object literal may only specify known properties, and 'data' does not exist in type 'IAuth'.
我尝试过的各种其他事情也出现类似错误。
这些都是 Typescript 错误。如何以 Typescript 兼容的方式设置我的 Provider 值 - 并包括 set
操作而不仅仅是值?
要在您的上下文中使用 auth 和 setAuth 状态,这是一种方法:
export const AuthContext = React.createContext<IAuth>({{}, ()=> {}});
const [auth, setAuth] = useState({
loggedIn: false,
role: ''
});
return (
<AuthContext.Provider value={{auth, setAuth}}>
{children}
</AuthContext.Provider>
)
在nav组件中,可以导入{AuthContext}
和
const {auth, setAuth} = React.useContext(AuthContext)
您不需要使用带钩子的 renderProps。您可以在代码中直接使用 auth
的值。
PS:我没用过typescript,但是react的方式还是一样的。
首先定义一个接口,其中包含应通过上下文传递的所有内容
export interface IAuth {
loggedIn: boolean;
role: string;
logIn: () => void;
logOut: () => void;
}
然后是提供者
export const AuthContext = React.createContext<IAuth>(null);
const AuthProvider: FC = ({ children }) => {
const [auth, setAuth] = useState({
loggedIn: false,
role: ""
});
const logIn = () => {
setAuth(prevState => ({
...prevState,
loggedIn: true
}));
};
const logOut = () => {
setAuth(prevState => ({
...prevState,
loggedIn: false
}));
};
return (
<AuthContext.Provider
// Here as value you need to pass the same interface as IAuth
// You can also just pass setAuth and do whatever you want
// from the children
value={{
...auth,
logIn,
logOut
}}>
{children}
</AuthContext.Provider>
);
};
然后在您的消费者中,您可以使用 useContext
挂钩来访问值
const Child: FC = () => {
const { loggedIn, role, logIn, logOut } = useContext(AuthContext);
return (
<div>
<p>{`loggedIn: ${loggedIn}`}</p>
<p>{`role: ${role}`}</p>
<button onClick={logIn}>logIn</button>
<button onClick={logOut}>logOut</button>
</div>
);
};
最后将 Child
渲染为 AuthProvider
const App: FC = () => (
<AuthProvider>
<Child />
</AuthProvider>
);