【问题标题】:What to set as the Provider's value in order to change context from a Consumer, in Typescript?为了在 Typescript 中更改消费者的上下文,需要设置什么作为提供者的值?
【发布时间】:2019-09-09 12:30:00
【问题描述】:

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

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

除其他外,我正在尝试遵循 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;

然后是我的 NavBar,它使用了上下文的 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;

如果我将 Provider 的值设置为这样,所有这些都可以正常工作:

<AuthContext.Provider value={{
    loggedIn: false,
    role: 'someRole'
}}>

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

使用以下内容会给我错误:

<EmailContext.Provider value={[state, setState]}>

Type '({ loggedIn: boolean; role: string; } | Dispatch&lt;SetStateAction&lt;{ loggedIn: boolean; role: string; }&gt;&gt;)[]' 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 操作而不仅仅是值?

【问题讨论】:

    标签: reactjs typescript react-hooks react-context


    【解决方案1】:

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

    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>
    );
    

    【讨论】:

      【解决方案2】:

      要在您的上下文中使用 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 的方式还是一样的。

      【讨论】:

      • 我想你这里有一个类型{{}. ()=&gt; {}}
      猜你喜欢
      • 2018-11-03
      • 2020-03-02
      • 1970-01-01
      • 1970-01-01
      • 2011-08-06
      • 1970-01-01
      • 2021-05-29
      • 2022-08-08
      • 1970-01-01
      相关资源
      最近更新 更多