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

时间:2017-02-09 20:32:16

标签: javascript reactjs redux redux-thunk

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

我现在正尝试使用ReactJS + Reduxredux-thunk中对此方案进行建模。我创建了一个thunk / async动作来获取JSON对象,提取它所需要的东西并最终用它来更新状态 -  但它不会将对象本身存储在状态中。这似乎是正确的逻辑方法,因为如上所述,定义永远不会以任何方式被修改。从严格意义上讲,我认为它只是 not state

然而,通过做出这个决定,我在实施实际React.Component时最终陷入困境。几乎每一个example我都在野外看到过像这样的异步案例:

  • 定义触发某些API调用的thunk操作。
  • 在国有财产中存储他们所得到的任何东西(或在经过一些改动之后)。
  • 使用this.propsmapStateToProps将该属性映射到组件中的connect

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

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这件事?

1 个答案:

答案 0 :(得分:2)

你是对的,拥有一个组件状态并不一定是件坏事,但我相信你对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商店

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

另请注意,我在我的示例中移动了操作,并将其放入与mapDispatchToProps简写的连接中。