#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);