Estoy tratando de tener un comportamiento similar al de redux 'usando contextApi y ganchos, pero tengo algunos problemas con el mecanografiado.

Quiero proporcionar tanto el estado de mi aplicación como el envío para poder acceder y modificar la tienda desde dentro de un componente. El problema es que cuando uso createContext, todavía no tengo ni los objetos state ni dispatch a mano, porque solo puedo llamar a useReducer dentro de un React componente. Por lo tanto, solo pude llamar a createContext declarando que el tipo de argumento es any, para pasar nulo en ese punto y pasar otro envío y estado más adelante.

    import React, { createContext, useReducer } from 'react';
    import reducerAuth, { initialState } from './reducerAuth';
    const ContextAuth = createContext<any>(null);
    const StateProvider = (
      { children }:{children:JSX.Element},
    ) => {
      const { Provider } = ContextAuth;
      const [state, dispatch] = useReducer(reducerAuth, initialState);
      return (<Provider value={{ state, dispatch }}>{children}</Provider>);
    };
    export { ContextAuth, StateProvider };

¿Hay alguna forma de pasar state y dispatch sin tener que declarar el tipo any y sin tener conflictos de mecanografía?

No quería usar redux para lograr todo esto, porque quiero usar herramientas nativas, pero redux parecía más fácil, aunque muy similar.

Intenté pasar el tipo de objeto {state,dispatch} para crear contexto, de la siguiente manera:

    const [state, dispatch] = useReducer(reducerAuth, initialState);
      type UseReducer = {
        state: typeof state,
        dispatch: typeof dispatch,
      }
      const ContextAuth = createContext<UseReducer | null>(null);

Pero en este caso ya no puedo exportar la autenticación de contexto, porque luego se crea dentro de la función StateProvider.

0
André Guimarães Aragon 22 ene. 2021 a las 01:26

1 respuesta

La mejor respuesta

La raíz de su problema es que está tratando de inferir el tipo de un objeto después de haber sido creado en lugar de comprender qué tipo de objeto se creará. En mi opinión, este es un diseño al revés.

Es mejor evitar el uso de typeof cuando sea posible. Hay cosas que puede aclarar con type o interface que typeof no puede inferir por sí solo. ¿Puede string "myString" ser cualquier valor string o es una cadena literal? ¿Esta propiedad null solo puede ser null, o podría ser null o algún otro tipo? ¿Y de qué otro tipo sería? Con suerte, entiendes el punto.

dispatch tiene un tipo conocido. Es una función que realiza una acción y devuelve void. No es necesario utilizar typeof dispatch para obtener su tipo.

type Dispatch<A> = (value: A) => void;

La variable genérica A representa los argumentos action aceptables. Lo que use depende de qué tan estrictamente tipeado quiera que esté su aplicación. Puede configurarlo en una unión de sus tipos de acción específicos o en una interfaz general que cumplirán todas sus acciones. Redux exporta tipos generales Action y AnyAction pero React no lo hace, así que tienes que definirlo tú mismo.

interface MyAction {
  type: string;
  payload: any;
}
type MyDispatch = Dispatch<MyAction>

Del mismo modo, ya debería conocer el tipo / interfaz esperado para su State. Si no, ¡defínalo!

Aquí hay un ejemplo de código completo. El lugar para implementar los tipos está en su initialState y reducerAuth. Si se escriben correctamente, entonces StateProvider no necesita escritura adicional ya que el gancho useReducer puede inferir los tipos de state y dispatch.

import React, { createContext, useReducer } from 'react';

interface MyState {
    // some actual data here
}

// initialState must fulfill the `MyState` interface
const initialState: MyState = {};

// just an example, you can define this type however you want
interface MyAction {
    type: string;
    payload: any;
}

// reducer declaration depends on the types for `MyState` and `MyAction`
const reducerAuth = (state: MyState, action: MyAction): MyState => {
    // actual reducer here
    return state;
};

// these are the values in your context object
interface MyContext {
    state: MyState;
    dispatch: React.Dispatch<MyAction>
}

const ContextAuth = createContext<MyContext | null>(null);

const StateProvider = ({ children }: { children: JSX.Element }) => {
    const { Provider } = ContextAuth;
    const [state, dispatch] = useReducer(reducerAuth, initialState);
    return (
        <Provider value={{ state, dispatch }}>
            {children}
        </Provider>
    );
};
1
Linda Paiste 23 ene. 2021 a las 23:16