Почему redux обновляется только при обновлении браузера?

#reactjs #redux #react-redux #axios #redux-thunk

Вопрос:

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

У меня есть приложение, которое позволяет пользователям входить в систему. Я использую redux для хранения учетных данных пользователя ПОСЛЕ того, как он войдет в систему, чтобы получить свой JWT. Я хочу иметь возможность войти в систему и сразу же увидеть себя вошедшим в систему. Но это происходит только после того, как я войду в систему после обновления браузера.

Итак, в react у меня есть форма входа в систему, которая вызывает функцию ниже после выполнения всех типичных функций сбора информации о пользователе (логин и пароль). Обратите внимание, что мне нужна отправка там, даже если я на самом деле ее не использую, потому что в противном случае я получу сообщение об ошибке «действия должны быть обычными объектами».

В конце этого обещания я звоню getUser, чтобы он взял этот JWT и вернулся с сервера со всей информацией об этой учетной записи. В отладчике он проходит через функцию входа в систему, а затем функцию getUser, но, похоже, никогда не сохраняет ее в redux, если я не обновлю браузер.

 export const loginUser = (credentials) => dispatch => {
    axios.post('api_call', credentials)
        .then(res => {
            debugger;
            const token = res.data.token;
            localStorage.setItem('token', token);
            alert("You have logged in successfully!");
            getUser(token);
        });
}
 
 export const getUser = (token) => dispatch => {
    debugger;
    axios.get('api_call', {
        headers: {"Authorization" : `Bearer ${token}`}
    }).then(user => dispatch({
            type: GET_USER,
            payload: [user.data]
        }));   
}
 

Позвольте мне также показать вам мой редуктор:

 import { LOGIN_USER, REGISTER_USER, GET_USER, LOGOUT_USER } from "../actions/types";

const initialState = {
    items: []
}

export default function(state = initialState, action){
    switch(action.type){
        case REGISTER_USER:
            return{
                ...state,
                items: action.payload
            };
        // case LOGIN_USER:
        //     return{
        //         ...state,
        //         items: action.payload
        //     };
        case GET_USER:
            debugger;
            return{
                ...state,
                items: action.payload
            };
        case LOGOUT_USER:
            return{
                ...state,
                items: []
            }
        default:
            return state;
    }
}
 

I have the LOGIN_USER commented out because I realize I’m not actually dispatching anything to the store, rather, just saving JWT to local storage.

Позвольте мне также упомянуть о том, что я пробовал. Я подумал, что, может быть, getUser не может быть вызван так, как я пытался. Поэтому по навигационной ссылке, которая перенаправляет на дом, я попытался поместить туда вызов getUser. Я попытался поместить getUser в крючок useEffect на домашнем компоненте, чтобы имитировать componentDidMount. Я попытался позвонить getUser непосредственно после вызова LoginUser в реальной форме входа. Это не работает из-за асинхронности (к тому времени в локальном хранилище не было jwt). Я попробовал поменять детали своего редуктора.

Вот мой корневой редуктор и хранилище для хорошей меры. Редуктор аутентификации относится ко всем функциям входа в систему, выхода из системы и регистрации.

 import { combineReducers } from "redux";
import showReducer from './showReducer';
import gearReducer from './gearReducer';
import authReducer from './authReducer';
import musicReducer from './musicReducer';
import profileReducer from './profileReducer';
import bagReducer from './bagReducer';

export default combineReducers({
    shows: showReducer,
    gear: gearReducer,
    auth: authReducer,
    music: musicReducer,
    profile: profileReducer,
    bag: bagReducer
});
 
 import { createStore, applyMiddleware, compose } from "redux";
import thunk from 'redux-thunk';
import rootReducer from './reducers/rootReducer';
import { composeWithDevTools } from 'redux-devtools-extension';

//initial app state
const initialState = {};

//middleware
const middleware = [thunk];

//...middleware (spread operator) because we want it to be added on to the middleware array
const store = createStore(
    rootReducer, 
    initialState, 
    composeWithDevTools(
        applyMiddleware(...middleware)
        )
    );

export default store;
 

Позвольте мне также упомянуть, что когда я обновляю страницу, отладчик выполняет функцию componentDidMount для основного приложения, которое декодирует jwt и вызывает getUser.

Я считаю, что это весь соответствующий код, но я могу обновить его при необходимости. Заранее благодарю вас и прошу прощения за дрянной вопрос.

Ответ №1:

Из того, что я вижу, вы не отправляете свои getUser действия в магазин.

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

 export const loginUser = (credentials) => dispatch => {
  axios.post('api_call', credentials)
    .then(res => {
      const token = res.data.token;
      localStorage.setItem('token', token);
      alert("You have logged in successfully!");
      dispatch(getUser(token)); // <-- dispatch getUser action!
    });
}
 

Комментарии:

1. Да! Я должен был воспринять полученное исключение как намек. Ну что ж, по крайней мере, я больше никогда не совершу этой ошибки, и теперь я немного больше понимаю redux. Спасибо!