Объедините запрос RTK и избыточность для сценария изменения

Я создал фрагмент API следующим образом:

export const authSlice = createApi({
    reducerPath: "auth",
    baseQuery: fetchBaseQuery({
        baseUrl: resolveApiBaseUrl(),
        prepareHeaders(headers) {
            headers.set("Content-Type", "application/json")
            headers.set("X-XSRF-TOKEN", <string>resolveUserToken())
            return headers
        }
    }),

    endpoints(builder) {
        return {
            login: builder.mutation<GymAppResponse, Login>({
                query: (payload) => ({
                    url: "/login",
                    method: "POST",
                    body: payload
                }),
            })
       }
})

export const {
    useLoginMutation,
} = authSlice

Я получаю токен пользователя после входа в систему и сохраняю его в localStorage, чтобы ограничить доступ пользователей к некоторой части моего приложения.

  1. Я пытаюсь использовать redux toolkit для взаимодействия с userToken, и в качестве состояния по умолчанию для userToken я хочу использовать значение localStorage. Поэтому я не хочу писать код в своем компоненте для проверки localStorage и выполнения необходимой логики. Я хочу использовать redux, поэтому, когда значение userToken обновится в localStorage, Redux автоматически обновит компонент для меня, используя useEffect(() => {...}, userTokenWhichRetrivedFromRedux).
  2. Я не смог найти в документе никакой информации о том, как использовать mutation и комбинировать его с набором инструментов Redux! Раньше я использовал redux-saga, который называл redux actions после success или fail запроса/ответа.

Вопрос: вот и спрашиваю у всех знающих:

  1. Какова лучшая практика здесь?
  2. К сожалению, redux-persist активно не поддерживается, и мне приходится прагматично использовать localStorage. Есть ли пакет или лучшая практика для обработки данных, которые нам нужно сохранить после вызова API?

🤔 А знаете ли вы, что...
С React можно работать с данными через HTTP-запросы, используя библиотеки, такие как Axios или Fetch API.


98
3

Ответы:

Если я правильно понял, вам нужно добиться двух вещей:

  1. Извлеките токен, полученный в результате мутации входа в систему, и сохраните его в другом фрагменте сокращения.
  2. Меняйте это значение каждый раз, когда изменяется локальное хранилище.

В первой части, я думаю, вы можете добиться этого с помощью утилиты onQueryStarted, которая позволяет вам дождаться завершения запроса на вход, а также дает вам доступ к функции отправки, чтобы вы могли выполнять другие действия с любым другим фрагментом. Обновлено: Теперь, когда я увидел ответ Фрая - да, лучшим решением было бы сопоставление события выполнения запроса с дополнительным редуктором.

Для второй части это может быть немного сложнее, но однажды я заставил его работать, используя событие хранения . По сути, добавьте прослушиватель событий для локального хранилища где-нибудь на верхнем уровне вашего приложения, а затем обновляйте токен каждый раз, когда событие запускается, т. е. используя то же действие, что и на предыдущем шаге, для первоначального заполнения локального хранилища.


Вы можете найти соответствующие примеры здесь, в разделе «примеры» RTK Query

Насколько я понимаю, вы хотите настроить состояние Redux в результате мутации. В этом случае самым простым способом сделать это будет добавление extraReducer для выполнения действия мутации к вашему фрагменту.

Что касается redux-persist: эта библиотека в значительной степени «закончена» несколько лет назад — она не требует активного обслуживания, чтобы быть полезной, особенно учитывая ее подключаемый характер. Вы должны быть в порядке, используя это.


Решено

Вот как я это сделал в аналогичном случае использования:

export const authSlice = createSlice({
   name: "auth",
   initialState,
   reducers: {},
   extraReducers: (builder) => {
     builder
       .addMatcher(authApi.endpoints.login.matchFulfilled, (state, action) => {
         state.user = action.payload;
       })
       .addMatcher(authApi.endpoints.logout.matchFulfilled, (state, action) => {
        state.user = null;
       });
   },
});

Вы также можете использовать createListenerMiddleware для доступа к срезу состояния и обеспечения обратного вызова, который будет выполняться на основе matchers

const authListenerMiddleware = createListenerMiddleware();

authListenerMiddleware.startListening({
  matcher: isAnyOf(
    authApi.endpoints.login.matchFulfilled,
    authApi.endpoints.logout.matchFulfilled
  ),
  effect: (action, listenerApi) => {
    if (action.meta.arg.endpointName === "login") {
      const user = listenerApi.getState().auth.user;
      localStorage.setItem(AUTHENTICATED_USER, JSON.stringify(user));
    }
    if (action.meta.arg.endpointName === "logout") {
      localStorage.removeItem(AUTHENTICATED_USER);
    }
  },
});