[React]将异步数据提取到组件中的不同方式

时间:2018-01-18 15:57:53

标签: ajax reactjs redux react-redux

当我开始在组件内部编写Ajax内容时,我对React世界有点新,并且最近感到困惑。

据我所知,以下是将异步数据呈现到Component中的两种方法,如下所示:

第一种方式:

class MyComponent extends React.Component
{
    render() {
      this.props.userList.map((userInfo) => (<span>{userInfo.name}</span>));
      // proceed to render userList
    }
}

//userAjaxSelect is a customized selector based on the Reselect lib
//ajax operation happens here!!
const mapStateToProps = (state, props) => {
  return {
      userList:userAjaxSelect(state, props)
  }
}

const mapDispatchToProps = null;// mapDispatchToProps is omitted here

export default connect(mapStateToProps, mapDispatchToProps)(MyComponent)
第二种方式:

export default class MyComponent extends React.Component
{

  componentDidMount() {
    //FetchUserList is a redux ActionCreator and omitted here
    //it dispatches redux action
    //To get ajax response and sync to local UI state.
    this.setState({userList: FetchUserList(this.props.groupId)})
  }  

  componentWillReceiveProps(nextProps) {
      if(nextProps != this.props)
      //FetchUserList is a redux ActionCreator and omitted here
      //it dispatches redux action
      //To get ajax response and sync to local UI state.
      this.setState({userList: FetchUserList(nextProps.groupId)})
    }

    render() {
      this.state.userList.map((userInfo) => (<span>{userInfo.name}</span>);
      // proceed to render userList
    }
}

从我的角度来看,

第一个解决方案:

ajax操作封装在Select中,用于Reselect lib,我认为它很干净,可以使组件性能受益(通过缓存)

第二个解决方案:

这是一个糟糕的吗?因为很多次我被一些文章警告过,不鼓励使用componentWillReceiveProps设置状态(反模式)?而且它实现的方式相对冗长

哪一个是最佳做法或任何其他更好的替代方案?在加载和刷新Ajax数据时

1 个答案:

答案 0 :(得分:2)

老实说,我从未使用过您展示过的任何方法。根据文档,您可能希望componentDidMount中有任何AJAX请求,并避免在componentWillReceiveProps中执行AJAX。

背后的原因是即使没有必要的数据也应该安装你的组件,你不想阻止视图(例如,如果你使用componentWillMount会发生这种情况)如果请求也需要长。我经常看到的模式如下:

export default class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = { isFetching: false, userList: [] };
  }

  componentDidMount() {
    this.setState({ isFetching: true });
    // In this case FetchUserList is just a simple AJAX call
    // not an action
    FetchUserList(this.props.groupId)
      .then((data) => {
        this.setState({ userList: data, isFetching: false });
      });
  }

  render() {
    this.state.userList.map((userInfo) => (<span>{userInfo.name}</span>);
  }
}

这不考虑错误处理,但我希望你能得到图片(你可以使用.catch)。如果您的状态已经填充,您甚至可以阻止发送请求,或者如果数据已经存在则可以避免设置状态等等...

另一方面,如果您使用的是redux,那么有许多中间件可以像redux-thunk一样帮助它,或者我创建了一个中间件,也称为redux-slim-async,它可以减少样板,并且是redux文档中显示的内容和一些其他功能的组合。在一天结束时,请使用您熟悉的内容以及对代码库更有意义的内容。

使用redux的另一种方法可能是在componentDidMount内触发异步操作,然后你的组件会监听状态的一部分(mapStateToProps)对componentWillReceiveProps感兴趣并对export default class MyComponent extends React.Component { constructor(props) { super(props); this.state = { userList: [] }; } componentDidMount() { // In this case FetchUserList is an Action FetchUserList(this.props.groupId) } componentWillReceiveProps(nextProps) { if(nextProps != this.props) { this.setState({ userList: nextProps.propFromStateManager }); } } render() { this.state.userList.map((userInfo) => (<span>{userInfo.name}</span>); } } 感兴趣,您可以根据从经理处收到的新道具更新组件的内部状态。你展示的是一种我不推荐的混合物。

componentWillReceiveProps

请注意,仅当您需要根据某些props更改更新组件的内部状态时才应使用reselect。我看到fetch派上用场的场景就是当您想要发送reselect请求时,无论如何更新状态,然后$ cordova run android Android Studio project detected ANDROID_HOME=/Users/User/Library/Android/sdk JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home studio Starting a Gradle Daemon (subsequent builds will be faster) :wrapper BUILD SUCCESSFUL Total time: 7.673 secs Subproject Path: CordovaLib Subproject Path: app publishNonDefault is deprecated and has no effect anymore. All variants are now published. FAILURE: Build failed with an exception. * What went wrong: A problem occurred configuring project ':CordovaLib'. > Failed to notify project evaluation listener. > com.google.common.base.Preconditions.checkArgument(ZLjava/lang/String;Ljava/lang/Object;)V * Try: Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. * Get more help at https://help.gradle.org BUILD FAILED in 2s (node:24627) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: /Users/User/Sites/testing/cordova/hello/platforms/android/gradlew: Command failed with exit code 1 Error output: FAILURE: Build failed with an exception. * What went wrong: A problem occurred configuring project ':CordovaLib'. > Failed to notify project evaluation listener. > com.google.common.base.Preconditions.checkArgument(ZLjava/lang/String;Ljava/lang/Object;)V * Try: Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. * Get more help at https://help.gradle.org 将检查状态是否完全相同,在这种情况下,它可能会阻止重新渲染。否则我不会从选择器发出ajax请求。如果我要跳入你的代码,我永远不会期望在选择器中获取异步调用,这不是它们的用途。

如果您需要澄清,请告诉我,我会更新答案。