React Redux - 每个条件的项目列表

时间:2018-05-04 14:08:56

标签: reactjs redux redux-saga

当我需要一个页面呈现来自同一API的多个项目列表时,我遇到了React Redux的问题。例如,我有GET参数/items的端点/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种不同的动作,但这似乎不是合理的解决方案。

在一个页面上呈现多个城市列表的最佳方法是什么?

更新

所以我将 reducer 更改为:

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)
      ))
    ...
  }
}

所以每个数组都是不可变的,但它再次遇到了太多的重新渲染。 enter image description here

遇到这种问题的每个人我最终都得到了这个解决方案

在我的 reducer 中,我将城市的每个项目分开,如下所示:

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)
    ...
  }
}

0 个答案:

没有答案