【问题标题】:How to do AuthContext, createDataContext using Typescript for React Native Expo dev?如何使用 Typescript 为 React Native Expo 开发做 AuthContext、createDataContext?
【发布时间】:2021-02-03 14:01:27
【问题描述】:

AuthContext.tsx

import createDataContext from './createDataContext';
import serverApi from '../api/server';

const authReducer = ({state, action}: any) => { 
    switch(action.type){
        default:
            return state;
    }
};

const signup = () => {
    return  async ({email, password}: any) => {
        try{
            const response = await serverApi.post('/signup', {email, password});
            console.log(response.data)
        }catch(err){
            console.log(err.message);
        }
    };
}

const signin = ({dispatch}:any) => {
    return ({email, password}: any) => {    };
}

const signout = ({dispatch}: any) => {
    return () => {};
}

export const {Provider, Context} = createDataContext(
    authReducer,
    {signin, signout, signup},
    {isSignedIn: false}
);

createDataContext

import React, { useReducer } from 'react';

export default ({reducer, actions, defaultValue}: any) => {
    const Context = React.createContext();

    const Provider = ({ children }: any) => {
        const [state, dispatch] = useReducer(reducer, defaultValue);
    
        const boundActions: any = {};
        for (let key in actions) {
          boundActions[key] = actions[key](dispatch);
        }
    
        return (
          <Context.Provider value={{ state, ...boundActions }}>
            {children}
          </Context.Provider>
        );
      };
    
      return { Context, Provider };
}

我从一个视频教程中复制了代码,其中使用 js 扩展开发了 react native 应用程序。但是我正在从事的项目具有 tsx 扩展名,即 TypeScript。 如何转换上述代码,使其在我的 typescript react native 移动应用程序中工作?

【问题讨论】:

    标签: reactjs typescript react-native


    【解决方案1】:

    ({reducer, actions, defaultValue}: any) 期望具有三个属性的 一个 参数。但是当你调用它时,你传递了三个单独的参数。所以你想要(reducer: any, actions: any, defaultValue: any)。同样,reducer 需要两个参数,所以你需要authReducer = (state: any, action: any) =&gt;,等等你的一堆函数。

    现在我们要去掉所有的any 并使用实际类型!其中一些类型我们可以从react 导入,其他类型我们将自己定义。

    棘手的部分是让您的上下文了解特定动作创建者的类型以及每个动作创建者需要什么参数。您需要这样做,以便您可以获得有关操作的自动完成建议,这样您就可以知道您是否不正确地调用它们。但这需要更高级的打字稿,例如 genericsmapped types,所以只需复制并粘贴即可,不要太担心。

    import React, { useReducer, FunctionComponent, Reducer, Dispatch } from 'react';
    
    interface DataState {
      isSignedIn: boolean;
      // add any other properties here
    }
    
    interface SignInProps {
      email: string;
      password: string;
    }
    
    // you can change this
    // it is common to use a type for `Action` that is a union of your specific actions
    interface Action {
      type: string;
      payload: any;
    }
    
    // this is where I am getting tricky
    type BoundActions<T> = {
      [K in keyof T]: T[K] extends (d: Dispatch<Action>) => infer R ? R : never
    }
    type ContextValue<T> = {
      state: DataState;
    } & BoundActions<T>
    
    export const createDataContext = <T extends {}>(reducer: Reducer<DataState, Action>, actions: T, defaultValue: DataState) => {
      // context needs a defaultValue
      const Context = React.createContext({state: defaultValue} as ContextValue<T>);
    
      // type of children is known by assigning the type FunctionComponent to Provider
      const Provider: FunctionComponent = ({ children }) => {
        const [state, dispatch] = useReducer(reducer, defaultValue);
    
        const boundActions = {} as BoundActions<T>;
        for (let key in actions) {
          // @ts-ignore - I don't want to make a confusing mess so just ignore this
          boundActions[key] = actions[key](dispatch);
        }
    
        return (
          <Context.Provider value={{ state, ...boundActions }}>
            {children}
          </Context.Provider>
        );
      };
    
      return { Context, Provider };
    }
    
    const authReducer = (state: DataState, action: Action): DataState => {
      switch (action.type) {
        default:
          return state;
      }
    };
    
    const signup = (dispatch: Dispatch<Action>) => {
      return async ({ email, password }: SignInProps) => {
        try {
          const response = await serverApi.post('/signup', { email, password });
          console.log(response.data)
        } catch (err) {
          console.log(err.message);
        }
      };
    }
    
    const signin = (dispatch: Dispatch<Action>) => {
      return ({ email, password }: SignInProps) => { };
    }
    
    const signout = (dispatch: Dispatch<Action>) => {
      return () => { };
    }
    
    export const { Provider, Context } = createDataContext(
      authReducer,
      { signin, signout, signup },
      { isSignedIn: false }
    );
    

    做这一切的目的是在您使用上下文时获得智能感知和类型检查。

    import React, { useContext } from 'react';
    import { Provider, Context } from .... // your path
    
    const SampleComponent = () => {
      // knows all of the properties available on the context
      const {state, signin, signout, signup} = useContext(Context);
    
      const handleClick = () => {
        // knows that these need email and password
        signin({email: '', password: ''});
        signup({email: '', password: ''});
        // knows that this one is ok to call with no args
        signout();
      }
    
      return (
        <div>{state.isSignedIn ? "Signed In!" : "Not Signed In"}</div>
      )
    }
    
    const SampleApp = () => (
      <Provider>
        <SampleComponent/>
      </Provider>
    )
    

    【讨论】:

      猜你喜欢
      • 2023-03-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-27
      • 1970-01-01
      • 2020-12-06
      • 1970-01-01
      • 2021-07-12
      相关资源
      最近更新 更多