【问题标题】:Handle async actions that do not store result in state处理不将结果存储在状态中的异步操作
【发布时间】:2017-02-09 20:32:15
【问题描述】:

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

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

但是,通过做出这个决定,我最终在实现实际的React.Component 时遇到了困难。几乎每一个 example 我都在野外看到过这样的异步案例:

  • 定义触发某些 API 调用的 thunk 操作。
  • 将他们取回(或经过一些更改)返回的任何内容存储在状态属性中。
  • 使用mapStateToPropsconnect 将该属性映射到组件中的this.props

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

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?

【问题讨论】:

    标签: javascript reactjs redux redux-thunk


    【解决方案1】:

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

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

    在您的componentDidMount 中,调度操作以获取数据是正确的。一旦触发动作并收到成功响应,您的减速器应该将定义保存到您的 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 存储

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

    另请注意,我在示例中将操作移出,并使用mapDispatchToProps 速记将其放入连接中。

    【讨论】:

    • 好的。你的解释对我来说是有道理的——在某种程度上。您关于在共享状态下第一次(也是唯一一次)使用后包含一个巨大的(没有提到,但在我的情况下相当大)、几乎无用的对象的论点显示出某种微调器?似乎不是一个很好的权衡。另外,我也可以用当地的州来处理这个问题。这不更像是一种试图将解决方案强制融入框架的方式吗?
    • Redux 只是一个简单的状态管理工具。如果你喜欢,你可以使用它,但你不必这样做。您在应用程序开发中所做的一切都取决于您自己,并且有很多方法可以达到类似的目的。每当我构建应用程序时,我都会考虑对 API 的请求何时失败。我不能保证我的definitions 会一直返回给我,我希望开发 UX/UI 以反映我的应用程序何时获取或接收响应。如果您在没有 redux 的情况下拥有所需的功能和组织结构,请随意删除它 - 毕竟它是您的应用程序。
    • 很公平。我的问题更多的是:“除了我所做的之外,还有其他方法吗?”。你当然给了一个。我接受你的回答。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-06-19
    • 2019-10-16
    • 1970-01-01
    • 2013-03-08
    • 1970-01-01
    相关资源
    最近更新 更多