Я столкнулся с проблемой React Redux, когда мне нужно, чтобы одна страница отображала несколько списков элементов из одного и того же API. Например, у меня есть конечная точка /items с параметром GET /items?city=Berlin. Мне нужно отобразить списки элементов 5 городов на главной странице.
В настоящее время у меня есть 1 действие для обработки вызова API.
Вот мой reducer.js:
...
const initialState = fromJS({
...
items: [],
...
})
export default function reducer (state = initialState, action) {
...
switch (action.type) {
case fetchItemsByCityRoutine.SUCCESS:
return state.update('items', (items) => items.push(...action.payload.data))
...
} }
saga.js:
function * fetchItemsByCity ({ payload: city }) {
try {
yield put(fetchItemsByCityRoutine.request())
const response = yield call(apiClient.fetchItemsByCity, city)
response.city = city
yield put(fetchItemsByCityRoutine.success(response))
} catch (error) {
yield put(fetchItemsByCityRoutine.failure(extractErrorMessage(error)))
} finally {
yield put(fetchItemsByCityRoutine.fulfill())
}
}
function * watchItemsByCitySaga () {
yield takeEvery(fetchItemsByCityRoutine.TRIGGER, fetchItemsByCity)
}
На Домашняя страница я отображаю список таких городов:
const renderCityListSections = () => homepageCityLists.map((city) => <ItemList key = {city.cityName} {...city} />)
Компонент ItemList:
class ItemList extends Component {
componentDidMount () {
const { cityName } = this.props
this.props.fetchItemsByCityRoutine(cityName)
}
render () {
const { items, title } = this.props
return (
items.length > 0 &&
<Wrapper>
<SlickSlider>
{items.map((item) => <Item key = {item.id} {...item} />)}
</SlickSlider>
</Wrapper>
)
}
}
ПРОБЛЕМА заключается в том, что текущее решение заставляет повторно визуализировать представление слишком много раз, потому что каждый раз, когда я получаю новый список для какого-то города, он добавляется в items, поэтому элементы меняются, и это приводит к запуску повторного отображения представления.
У меня была мысль создать 5 разных действий для каждого города, но это не кажется разумным решением.
КАК лучше всего отображать несколько списков городов на одной странице?
ОБНОВИТЬ:
Итак, я изменил редуктор, чтобы он выглядел так:
const initialState = fromJS({
...
items: {
Miami: [],
Prague: [],
Melbourne: [],
Venice: [],
Barcelona: [],
},
...
})
export default function reducer (state = initialState, action) {
switch (action.type) {
...
case fetchItemsByCityRoutine.SUCCESS:
return state.updateIn(['items', action.payload.city], (list) => (
list.concat(action.payload.data)
))
...
}
}
поэтому каждый массив неизменяем, но опять же приходится слишком много перерисовывать.

У всех, у кого есть такая проблема, у меня получился этот РЕШЕНИЕ:
В моем редуктор я развязал каждый элемент для города следующим образом:
const initialState = fromJS({
...
itemsForBerlin: [],
itemsForAnotherCity: [],
...
})
export default function reducer (state = initialState, action) {
switch (action.type) {
...
case fetchItemsByCityRoutine.SUCCESS:
return state.set(`itemsFor${action.payload.city}`, action.payload.data)
...
}
}
@MartinKadlec, вы ведь говорите о редукторе? Если да, то мне кажется, что результат будет таким же, потому что он обновляет items с новой парой ключ => значение, не так ли?
Ага, редуктор. При изменении карта предметов будет новой, но все ее участники, кроме нового города, должны по-прежнему иметь исходную ссылку, если все сделано правильно.
let items = { Berlin: [1, 2, 3] }; let newItems = { ...items, Prague: [4, 5, 6] }; newItems.Berlin === items.Berlin; // true@MartinKadlec, кажется, я знаю, в чем проблема. Мой проект основан на ImmutableJS, поэтому я думаю, что должен быть какой-то метод для добавления пары ключ / значение в массив items.
Он не зря называется неизменяемым :) если вы добавляете элементы в массив, вы должны получить новый массив, иначе он не будет неизменным. К сожалению, мои знания о Immutable.js не так хороши, поскольку мне всегда было слишком утомительно использовать O :) - поэтому я не использовал его в моем примере выше.
Вот вам рабочий пример codeandbox.io/s/3vl8vwjmrq
@MartinKadlec, спасибо, но большая разница в том, что мне нужно получить все 5 городов одновременно. Вот где возникают проблемы с повторной визуализацией
Если вы каждый раз получаете данные по всем городам, вы не можете использовать неизменяемость, чтобы проверять, что наборы элементов одинаковы. Вам нужно будет либо использовать проверку deepEqual, либо передать хеш версии с сервера.
@MartinKadlec, ты прав. Вот почему я обновил свой вопрос решением, которое у меня было. Спасибо за помощь!





Как насчет того, чтобы хранить товары в магазинах по городам?
state.items[city] = cityItems?