Доступ к состоянию редуктора из другого редуктора

У меня есть редуктор, посредством которого я перенастраиваю соответствующее состояние при отправке действия. Теперь я вызываю API через равные промежутки времени, поэтому результат будет вызывать действие снова и снова. Итак, я хочу, чтобы, если состояние редуктора уже имело данные, то другой редуктор не отображал состояние загрузки во время отправки вызова. Он должен поддерживать свое состояние загрузки только при первом получении данных. Я надеюсь, что смогу объяснить это правильно

Вот мои фрагменты кода

Редуктор состояния нагрузки

const loading = (state = false, action) => {

    switch (action.type) {
    case 'GET_AUDIT_DATA':         // here I want to return true only when there is no data available
        return true
    case 'GET_AUDIT_DATA_RECEIVED':  
        return false
    case 'GET_AUDIT_DATA_ERROR':
        return false
    default:
        return state
    }
}

Объединение редукторов

const allReducers = combineReducers({
    auditData: AuditData,
    auditLoading: AuditLoading,
    modifiedOrders: ModifiedOrders
});

export default allReducers;

Редуктор возвращает данные о действии, вызванном суперагентом

const auditData = (state = [], action) => {
    switch(action.type) {
        case 'GET_AUDIT_DATA_RECEIVED': 
        console.log(action.data);
            return action.data;
        case 'GET_AUDIT_DATA_ERROR': 
            return action.err;
        default :
            return state;
    }
}
export default auditData;

Так что изначально auditData не содержит никаких данных, только после первого успешного вызова возвращает данные. Когда это вызывается одновременно loading state reducer называется, и он должен вернуть истину в GET_AUDIT_DATA действие только в том случае, если редуктор данных аудита не содержит никаких данных.

Также возвращает только текущие полученные данные из auditData правильный путь или я должен сделать это по-другому. В основном я хочу overwrite current data с new one,

5 ответов

Решение

Лучший способ продолжить - отправить в редуктор состояния загрузки информацию, чтобы узнать, есть ли у другого редуктора данные. Иметь в конце:

const loading = (state = false, action) => {

    switch (action.type) {
    case 'GET_AUDIT_DATA':
        if(!action.dataAlreadyInitialized){
            return true
        }
    case 'GET_AUDIT_DATA_RECEIVED':  
        return false
    case 'GET_AUDIT_DATA_ERROR':
        return false
    default:
        return state
    }
}

Вы должны иметь доступ от вашей функции действия к состоянию приложения и делать:

dispatch({
  type:'GET_AUDIT_DATA',
  dataAlreadyInitialized: appState.auditData.length > 0
});

Ты можешь позвонить getState() через магазин, чтобы получить список редукторов и текущее состояние внутри редукторов.

  1. Импортировать store в auditLoading (используйте хранилище, чтобы получить значения. Не изменяйте хранилище)
  2. store.getState().auditLoading даст вам состояние auditLoading редуктор.

Этот подход похож на обратный вызов, предоставляемый redux-thunk, В котором (dispatch, getState) => {} будут возвращены к действию.

Надеюсь это поможет!

Принятый ответ хорош (передать длину данных через действие), но может оказаться трудоемким, если это часть информации, которая широко используется. Есть другое решение, которое иногда предпочтительнее для чего-то вроде "текущего пользователя", которое может использоваться при каждом действии.

Согласно Redux FAQ https://redux.js.org/faq/reducers, вполне допустимо добавить третий аргумент в функцию reducer. Т.е.:

Редуктор состояния нагрузки

const loading = (state = false, action, noData) => {

    switch (action.type) {
    case 'GET_AUDIT_DATA':
        return noData
    case 'GET_AUDIT_DATA_RECEIVED':  
        return false
    case 'GET_AUDIT_DATA_ERROR':
        return false
    default:
        return state
    }
}

Комбинирование редукторов

К сожалению, это означает, что мы должны писать код для объединения редукторов, а не использовать ярлык combReducers. Но это не так уж сложно, вы просто вызываете каждый редуктор и создаете новый объект, если что-то изменилось:

const allReducers = (state = null, action) => {
    const auditData = AuditData(state?.auditData, action);
    const auditLoading = AuditLoading(state?.auditLoading, action, !state?.auditData?.length);
    const modifiedOrders = ModifiedOrders(state?.modifiedOrders, action);
    return (auditData !== state?.auditData ||
      auditLoading !== state?.auditLoading ||
      modifiedOrders !== state?.modifiedOrders) ?
      { auditData, auditLoading, modifiedOrders } : state;
});

export default allReducers;

Обратите внимание на третий аргумент, переданный редуктору AuditLoading. Никаких изменений в других редукторах или в коде, вызывающем действие, не требуется. Что приятно!

import store from '../../../redux/store'

console.log(store.getState().loginReducer.accessToken)

Благодаря этому заявлению мы получим состояние accessToken

Вы можете использовать Thunk, чтобы решить эту проблему.

Предположим, что ваш создатель действий выглядит так

      const getAuditDataAction  = (data) => {
    return { type: "GET_AUDIT_DATA", data }
} 

Вам нужно будет добавить промежуточное программное обеспечение Redux Thunk, если у вас его еще нет.

Создатель вашего действия может стать чем-то вроде этого

      const getAuditDataAction  = (data) => {
    return async (dispatch, getState) => {
        const { auditData, auditLoading, modifiedOrders } = getState();
        // Here depending on data you have in your store you 
        // can dispatch the default action or another action 
        // that does something else
        dispatch({ type: "GET_AUDIT_DATA", data })
     }
}
Другие вопросы по тегам