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

IT技术 ajax reactjs redux react-redux
2021-05-21 21:10:18

我对 React 世界有点陌生,最近当我开始在组件中编写 Ajax 内容时感到困惑。

据我所知,这里有两种将异步数据渲染到组件中的方法,如下所示:

第一种方式:

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 操作封装在 Reselect 库中使用的 Selector 中,我认为它非常干净并且可以使组件性能受益(通过缓存)

第二种解决方案:

它是坏的吗?因为很多时候我被几篇文章警告过,不鼓励 componentWillReceiveProps 设置状态(反模式)?而且它的实现方式比较冗长


哪一个是最佳实践或任何其他更好的选择?加载和刷新 Ajax 数据时

1个回答

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

其背后的原因是即使没有必要的数据也应该安装您的组件,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它感兴趣的状态部分(with ),并且componentWillReceiveProps您可以根据收到的新props更新组件的内部状态从你的经理那里。你展示的是一种我不推荐的混合体。

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检查状态是否完全相同,在这种情况下,它可能会阻止重新渲染。否则我不会从选择器发出 ajax 请求。如果我要跳入您的代码,我绝不会期望在选择器中执行异步调用,这不是它们的用途。

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