Búsqueda de sitios web

reactjs - ¿Cómo acceder a los datos en el store antes de la consulta en Redux Toolkit Query?


Estoy intentando convertir mis reducers de Redux, la tienda, etc., que usan Thunks, para utilizar Redux-Toolkit (RTK) Query. Actualmente tengo bastantes thunks que acceden a la tienda para obtener algunos datos adicionales antes de realizar cualquier consulta al backend, así:

const someThunkCreator = (params: Params): AppThunk =>
  async (dispatch, getState) => {
    const someData = getState().some.nested.path.to.data
    const moreData = getState().another.nested.path.to.data

    // Probably do something with the data before querying

    const response = await fetch(`${url}/${someData.id}`, {
      method: 'PATCH',
      body: {
        ...moreData,
        ...params
      }
    })
  }

¿Ahora cómo debería convertir eso a un endpoint de RTK-Query? Si tengo múltiples endpoints que están accediendo a algunos datos en el store, es decir, algunos datos de usuario, ¿necesito pasar esos datos como parámetro de consulta o hay alguna manera de siempre inyectar esos datos en algunas consultas específicas? Supongo que con algún enhancer podría inyectarlo en cada consulta, pero entonces no todas las consultas podrían necesitar esos datos.

const myApi = createApi({
  reducerPath: 'myApi',
  baseQuery: fetchBaseQuery(),
  endpoints: builder => ({
    // Is there a way to do it this way?
    updateSomething1: builder.mutation({
      query: (something: TypeForSomething) => ({
        url: `${userManagementUrl}/${userId}`, // Here the userId would be got from the store based on whoever is the current user using the app
        method: 'PATCH',
        something
      })
    }),
    // Or do I need to do it this way and always somewhere in the code first get the data through some other endpoint query?
    updateSomething2: builder.mutation({
      query: (userId: string, something: TypeForSomething) => ({
        url: `${userManagementUrl}/${userId}`,
        method: 'PATCH',
        something
      })
    }),
  })
});

Respuesta #1

En lugar de usar la función query que solo consume un argumento de consulta

export type query = <QueryArg>(
  arg: QueryArg
) => string | Record<string, unknown>

utiliza el queryFn que consume el argumento de consulta pasado además de la API de consulta base, opciones adicionales y la función de consulta base.

queryFn(
  arg: QueryArg,
  api: BaseQueryApi,
  extraOptions: BaseQueryExtraOptions<BaseQuery>,
  baseQuery: (arg: Parameters<BaseQuery>[0]) => ReturnType<BaseQuery>
): MaybePromise<
| {
    error: BaseQueryError<BaseQuery>
    data?: undefined
  }
| {
    error?: undefined
    data: ResultType
  }
>

La BaseQueryApi tiene la función de acceder al estado de la tienda:

export interface BaseQueryApi {
  signal: AbortSignal
  dispatch: ThunkDispatch<any, any, any>
  getState: () => unknown
}

Actualiza el endpoint de mutación para acceder a la tienda desde el argumento api y accede al/los valor(es) que necesites desde el estado.

Ejemplo :

updateSomething1: builder.mutation</* ResultType */, TypeForSomething>({
  queryFn: (something, api, extraOptions, baseQuery) => {
    const state = api.getState() as RootState;
    const userId = state.some.nested.path.to.data;
    // or const userId = selectUserId(state); if you've selector functions

    return baseQuery({
      url: `${userManagementUrl}/${userId}`,
      method: 'PATCH',
      something
    }) as { data: /* ResultType */ };
  },
}),

/* ResultType */ es lo que necesitarás declarar y proporcionar para lo que realmente estás devolviendo.