在 Typescript 中,为了更改 Consumer 的上下文,应将 Provider 的值设置为什么?

Ter*_*esa 1 typescript reactjs react-context react-hooks

我正在尝试学习如何在 React 中使用钩子和上下文,但需要使用 TypeScript(这也是新的)。

我的用例是授权:用户要么登录,要么未登录,并且具有角色(例如“管理员”、“超级管理员”)。根据其授权状态,导航栏的呈现方式有所不同。

除此之外,我试图遵循这个示例,并根据我的需要进行简化。

到目前为止,这是我的背景和提供者:

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;
Run Code Online (Sandbox Code Playgroud)

然后是我的导航栏,它使用了上下文的 Consumer:

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;
Run Code Online (Sandbox Code Playgroud)

如果我将提供者的值设置为这样,那么所有这些都可以正常工作:

<AuthContext.Provider value={{
    loggedIn: false,
    role: 'someRole'
}}>
Run Code Online (Sandbox Code Playgroud)

但是,我还想提供该setAuth功能,以便从登录组件等更改这些值。

使用以下命令会出现错误:

<EmailContext.Provider value={[state, setState]}>
Run Code Online (Sandbox Code Playgroud)

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})}
        }}>
Run Code Online (Sandbox Code Playgroud)

错误data: authType '{ 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'.

我尝试过的其他各种事情也出现类似的错误。

这些都是打字稿错误。如何set以 Typescript 兼容的方式设置我的 Provider 值 - 并包括操作而不仅仅是值?

Asa*_*viv 5

首先定义一个接口,其中包含应通过上下文传递的所有内容

export interface IAuth {
    loggedIn: boolean;
    role: string;
    logIn: () => void;
    logOut: () => void;
}
Run Code Online (Sandbox Code Playgroud)

然后是提供者

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>
    );
};
Run Code Online (Sandbox Code Playgroud)

然后在您的消费者中您可以使用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>
    );
};
Run Code Online (Sandbox Code Playgroud)

最后将 渲染Child为 的子级AuthProvider

const App: FC = () => (
    <AuthProvider>
        <Child />
    </AuthProvider>
);
Run Code Online (Sandbox Code Playgroud)