Selector возвращает пустой массив из состояния redux, даже если в массиве есть значения

#redux #react-redux #immutability #reselect #immer.js

#redux #реагировать-redux #неизменность #повторный выбор #immer.js

Вопрос:

У меня есть следующее нормализованное состояние redux:

 rootReducer: {
  blocks: {
    "key1": {
      id: "key1",
      beverages: [], // Array of objects
    }
  }
}
 

и я пытаюсь выбрать значение beverages для напитка с идентификатором "key1" использования этого селектора:

 export const getBlockBeverages = (state, blockId) => {
    console.log("selector", state.blocks[blockId].beverages);
    return state.blocks[blockId].beverages;
};
 

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

Начальное состояние

 selector []
selector []
 

Добавление нового напитка:

 selector []
selector [{/*beverage1*/}]

// Adding another beverage
selector []
selector [{/*beverage1*/}, {/*beverage2*/}]
 

Я был бы очень признателен за любую помощь / объяснение, почему вызывается селектор, а beverages значение для экземпляра блока является пустым массивом.

Ниже приведен код для редукторов, которые я использую — я не вижу, где я мог бы изменять исходное состояние, я использовал Immer’s produce с самого начала, и проблема все еще присутствует. Затем я попытался использовать Lodash.clonedeep, чтобы убедиться, что я возвращаю новое состояние, но селектор по-прежнему регистрирует этот пустой массив.

 const blockReducer = (state = { id: "", beverages: [] }, action) => {
    if (action.type === ADD_BEVERAGE_TO_BLOCK) {
        const { beverageId } = action.payload;
        const newBeverage = { id: uuid4(), beverageId };
        return produce(state, (draft) => {
            draft.beverages.push(newBeverage);
        });
    }
    return state;
};


const blocks = (state = {}, action) => {
    const key = action.payload.key;
    if (key amp;amp; (state[key] || action.type === CREATE_BLOCK)) {
        const instanceState = blockReducer(state[key], action);
        return produce(state, (draft: any) => {
            draft[key] = instanceState;
        });
    }
    return state;
};
 

Есть идеи, почему селектор возвращает пустой массив вместо массива длиной 0, 1, 2 и т.д., когда я добавляю новые напитки? Я невежественен и буду признателен за любую помощь.

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

1. Можете ли вы также зарегистрировать идентификатор блока в селекторе?

2. Значение @HMR blockId равно «key1» при каждом вызове селектора.

3. это сложно проверить без полного порядка кода, можете ли вы загрузить это на github или codesanbox, чтобы помочь вам?

4. @crizcl Я создам образец репозитория и попытаюсь смоделировать проблему, я дам вам знать

5. круто! буду ждать этого!

Ответ №1:

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

 export const makeGetBlockBeveragesLength = () => createSelector(
    (state, blockId) => getBlockBeverages(state, blockId),
    (blockBeverages) => blockBeverages.length,
);
 

и вместо mapStateToProps я использовал createMapStateToProps:

 const createMapStateToProps = (state, { blockId }) => () => {
    const getBlockBeveragesLength = makeGetBlockBeveragesLength();
    return {
        length: getBlockBeveragesLength(state, blockId),
    };
};

export const Component = connect(createMapStateToProps)(MyComponent);
 

Пустой массив, зарегистрированный в одном из журналов, относится к более старому состоянию (в данном случае к исходному состоянию).

Я исправил код для этого, и он работает:

 export const getBlockBeveragesLength = createSelector(
    (state, blockId) => getBlockBeverages(state, blockId),
    (blockBeverages) => blockBeverages.length,
);
 
 const mapStateToProps = (state, { blockId }) => ({
    length: getBlockBeveragesLength(state, blockId),
});

export const Component = connect(mapStateToProps)(MyComponent);