在 React-Redux 中转换 API 数据:Action 或 Reducer

Converting API data in React-Redux: Action or Reducer

我有一个天气应用程序,api 数据有不同的格式,所以我创建了一个方法对象,我可以将该数据转换为英制格式,并将时间从 UTC 转换为 GMT。

现在我在 reducer 中的数据上调用了这些方法。

问题:是 "okay" 还是应该在将有效负载传送到 reducer 之前在相应的操作中完成转换?只是好奇这样的最佳实践是什么。

仅供参考:我使用 axios 作为基于 promise 的 HTTP 客户端,并使用 redux-promise-middlewareredux-lodgerredux-promise 作为商店中的中间件。

动作创作者:

export const fetchCurrentWeather = (city) => {
const url = `${CURRENT_ROOT_URL}&q=${city},us`;
const promise = new Promise((resolve, reject) => {
   axios.get(url)
     .then(res => resolve(res.data))
     .catch(err => reject(err));

});
return {
  type: FETCH_CURRENT_WEATHER,
  payload: promise
  };
};

减速器:

export default(state = initialState, action) => {
const data = action.payload;
switch (action.type) {
    case `${FETCH_CURRENT_WEATHER}_PENDING`:
        return {};
    case `${FETCH_CURRENT_WEATHER}_FULFILLED`:
    const prefix = 'wi wi-owm-';
    const code = data.weather[0].id;
    const icon = prefix + code;
        return {
            ...state,
            weatherData: {
              humidity: data.main.humidity,
              icon,
              name: data.name,
              pressure: unitConverter.toInchesHG(data.main.pressure),
              sunrise: unitConverter.toGMT(data.sys.sunrise),
              sunset: unitConverter.toGMT(data.sys.sunset),
              temp: unitConverter.toFarenheit(data.main.temp),
              winddir: unitConverter.toCardinal(data.wind.deg),
              windspd: unitConverter.toMPH(data.wind.speed)
            },
            isFetched: true
        };
    case `${FETCH_CURRENT_WEATHER}_REJECTED`:
        return {
            ...state,
            isFetched: true,
            err: data
        };
    default:
        return state;
  }
};

您可以在三个位置有效地处理您的原始数据:

  • 组件的render()函数

    这通常不是一个好主意,因为这意味着每次渲染组件时都会处理数据。如果你使用像 reselect 这样的包,你可以通过缓存来缓解性能问题,但即便如此,实际的代码例如sortingfiltering 应保留在 mapStateToProps().

  • 中减速机

    在 reducer 中处理数据可以有一个更好的案例,但我认为出于清晰和关注点分离的原因,这仍然不是最好的地方。 reducer 的工作非常明确 - 承认动作并将先前状态与动作结果合并,任何其他事情只会模糊责任和可测试性的界限。

  • 一个动作 thunk

    在我看来,action thunk 是一次性数据转换(例如导入原始数据的规范化/转换)的正确位置。它不仅通常是一个明确的操作子任务(例如获取天气数据 -> 将摄氏度转换为华氏度),而且还具有不存储无用数据的额外优势,即使是暂时的状态。

    引用 Dan Abramov 的话:

    ... action objects [are] minimal representations of what happened and state objects [are] minimal representations of what’s necessary for rendering right now.

最后的说明 - 选择器

虽然我上面说组件不是执行原始数据转换的好地方,但实际上我认为存储 原始数据 在 redux-state 中并使用像 reselect 这样的包来根据需要通过 selectors 呈现规范化或计算的值。

实现此目的的一种方法是使用 selector 函数对原始数据的定义部分执行数据规范化。使用 reselect 包,此转换将被缓存,因此只执行一次。它的优点是 延迟转换 仅在需要时才转换数据。