我应该使用 ComponentDidMount 还是 connect 函数的 mergeProps 来获取数据?

Should I use ComponentDidMount or mergeProps of connect function for data fetching?

我使用 react with redux 并有一个组件显示从外部源获取的一些数据集。我当前的代码如下:

const ConnectedComponent = connect(
  state => ({
    dataSet: state.dataSet
  }),
  dispatch => ({
    loadData: () => {
      ...
      fetch data and dispatch it to the store
      ...
    }
  })
)(MyComponent); 

class MyComponent extends Component {
  ...
  componentDidMount() {
    const { dataSet, loadData } = this.props;
    if (!dataSet) {
      loadData();
    }
  } 
  ... 
  render () {
    const { dataSet } = this.props;
    if (dataSet) {
      // render grid with data
    } else {
      // render Loading...
    }
  }
}

上面的代码有效,但我想知道摆脱 componentDidMount 并只检查数据并从 connect[ 中加载它会更好吗? =26=]函数?代码可能如下所示:

const ConnectedComponent = connect(
  state => ({
    dataSet: state.dataSet
  }),
  dispatch => ({ 
    dispatch 
  }),
  (stateProps, dispatchProps) => {
    const { dataSet } = stateProps;
    const { dispatch } = dispatchProps;

    if (!dataSet) {
      // fetch data asynchronously and dispatch it to the store
    } 

    return {
      ...stateProps
    };
  }
)(MyComponent); 

class MyComponent extends Component {
  render () {
    const { dataSet } = this.props;
    if (dataSet) {
      // render grid with data
    } else {
      // render Loading...
    }
  }
}

后面的代码看起来更吸引我,因为 MyComponent 变得更简单了。当 componentDidMount 检测到没有准备好显示的数据时,不会先从连接的组件向前传递到展示,然后再向后传递执行。

这种方法有什么缺点吗?

PS: 我使用 redux-thunk 进行异步抓取。

第二种方法,作为概念分离,可能是一个很好的解决方案,因为层和职责分离 - ConnectedComponent 负责数据获取,而MyComponent 充当演示组件。好!

但是,在连接 mergeProps 中调度操作似乎不是一个好主意,因为你引入了 副作用

另外,我看到的另一个缺点是,获取和返回数据的流程将在不同的页面(组件)之间重复。一般来说,会重复以下流程:

  1. 已连接的组件为所需的实体调用 API。
  2. 在获取实体时,我们正在显示加载程序。
  3. 当数据可用时,我们将其传递给演示组件。

由于上述缺点,我建议您在 HOC.

中组织和重用您的数据获取流程

这是解决上述缺点的伪代码和流程(摘自我的文章):

* 我过去一年一直在使用它,并继续坚持下去。

Fetcher HOC:

import authorActions from 'actions/author'

const actions = {
  'Author': authorActions
}

export default (WrappedComponent, entities) => {

  class Fetcher extends React.Component {
    // #1. Calls the API for the needed Entities.
    componentDidMount () {
      this.fetch()
    }

    fetch () {
      const { dispatch } = this.props

      entities.forEach(name => dispatch(actions[name].get()))
    }

    render () {
      const { isFetching } = this.props

      // #2. While fetching the Entities, we're showing an Loader.
      if (isFetching) return <Loader />

      return <WrappedComponent {...this.props} />
    }
  }

  const mapStateToProps = state => {
    const isFetching =  entities
      .map(entity => state[entity].isFetching)
      .filter(isFetching => isFetching)

    return { isFetching: isFetching.length > 0 }
  }

  return connect(mapStateToProps)(Fetcher)
}

用法:

const MyComponent = ({ authors }) => <AuthorsList authors={authors} />

const mapStateToProps = state => ({
  authors: state.authors
})

const Component = connect(mapStateToProps)(MyComponent)
export default Fetcher(Component, ['Author'])

在这里您可以阅读这篇文章并深入了解它的想法和概念:

* Fetcher 概念在第 2 课:增强型容器

Long-term React & Redux SPA — Lessons learned