处理不将结果存储在状态中的异步操作

Handle async actions that do not store result in state

我偶然发现了一个 vanilla JS webapp 部分的需求,它需要一个 JSON "definitions" 对象来呈现。定义在最开始通过HTTP请求加载、读取、解析并传递给另一层应用。对象本身在其整个生命周期中永远不会改变。

我现在正尝试在 ReactJS, using Redux + redux-thunk 中模拟此场景。我创建了一个 thunk/async 操作来获取 JSON 对象,提取它需要的东西并最终更新状态 - 但它确实不在状态中存储对象本身。这似乎是正确的、合乎逻辑的方法,因为如前所述,定义永远不会以任何方式修改。我认为它只是不是严格意义上的状态

然而,通过做出那个决定,我最终在实施实际 React.Component 时遇到了困难。几乎每一个 example 我在野外都见过这样的异步情况:

在我的例子中,我真的没有状态 属性 可以绑定到 。所以我最终在我的异步操作中返回了定义对象,并使用组件的本地状态来获得我需要的东西。

class ContainerComponent extends React.Component {
  state = { definitions: {} };

  componentDidMount() {
    const { dispatch } = this.props;
    dispatch(fetchDefinitions())
      .then((definitions) => this.setState({ definitions }));
  }

  render() {
    return (<PresentationalComponent definitions={this.state.definitions} />);
  }
}

export default connect()(ContainerComponent);

并不是说 this.setState 应该 be avoided,但这看起来非常像 我在引入 Redux 之前所拥有的:一个 API 调用返回一个承诺 - 只有更多的间接干预。

  componentDidMount() {
    const { dispatch } = this.props;
    fetch(`${API_URL}/definitions`)
      .then((res) => res.json())
      .then((definitions) => this.setState({ definitions }));
  }

那么,我应该怎么做呢?我在这里缺少什么特别的东西吗?我应该遵循什么模式?也许,为了这件事完全避免使用 Redux?

您说得对,拥有组件状态不一定是坏事,但我相信您对 API 调用后将数据存储在哪里感到困惑。

你提到它不一定是状态,但我不这么认为。在进行 API 调用之前,您的应用程序没有该数据。您可能在应用程序启动时有某些 UX/UI 指示,例如可以指示是否正在获取数据:definitions.all.isFetching.

在您的 componentDidMount 中,调度获取数据的操作是正确的。触发操作并收到成功响应后,您的 reducer 应该将定义保存到您的 redux 存储中,如

import { assign, get } from 'lodash';

const all = (
  state = { isFetching: false, data: [] },
  action,
) => {
  switch (action.type) {
    case types.LIST_DEFINITIONS:
      return assign({}, state, { isFetching: true });
    case types.LIST_DEFINITIONS_SUCCESS:
      return assign({}, state, get(action, 'result.data'), { isFetching: false });
    default: return state;
  }
};

然后在你的组件中,你会 connect 你的 redux store

function mapStateToProps(state){
  return {
    definitions: state.definitions.all.data
  };
}
export default connect(mapStateToProps, { listDefinitions })(ContainerComponent);

另请注意,我将示例中的操作移出,并将其放入与 mapDispatchToProps shorthand 的连接中。