【问题标题】:HOC for fetching data in Redux在 Redux 中获取数据的 HOC
【发布时间】:2016-11-23 07:31:11
【问题描述】:

在我的应用程序(React、Redux、React-Router、Express)中,我想制作高阶组件来获取每个视图的初始数据。它将发送请求(每个视图一个或多个)并显示 Loader 组件,直到所有请求都成功,然后显示正确的组件。

const FetchData = (ComposedComponent) => {
  class FetchData extends React.Component {
    constructor(props){
      super(props)
      this.state={isLoading: true}
    }
    componentDidMount(){
      this.fetchData()
    }

    fetchData() {
      const that = this
      Promise.all(
        Object.keys(this.props)
          .filter(element => _.isFunction(this.props[element]))
          .map(element => this.props[element])
      ).then(result => that.setState({isLoading:false})
      )
    }

    displayContent(){
      let content = this.state.isLoading ? <Loader /> : <ComposedComponent {...this.props} />
      return content
    }

    render() {
      return (
        <div>
         {this.displayContent()}
        </div>
      )
    }
  }

  return FetchData;
}

export default FetchData

这是我要包装并最终显示的组件:

import requireData from '../utils/requireData'

class Photos extends Component {

  render() {
    return (
      <h1>Photos</h1>
    );
  }
}

export default connect(null, {getTodos,getPhotos})(requireData(Photos))

我的解决方案是构建包装 MainComponent (Container) 并通过 props 获取所有需要的操作的 HOC。它触发 componentDidMount 中的所有操作,然后更新存储并在最后呈现 MainComponent(使用连接)。它看起来很简单,但是在获取初始数据的操作中会出现问题,我必须使用参数,例如。来自商店的 userId oraz 来自 url (react-router) 的任何其他 ID。有些动作需要额外的参数,有些则不需要。

还有一个问题... setState 在 Promise.all() 成功之前触发。我该如何处理? 如何将正确的参数传递给 HOC?

问候

【问题讨论】:

  • 我不确定我是否完全理解您的情况,但我想知道 Redux Saga (yelouafi.github.io/redux-saga) 是否会有所帮助。基本上,您将在 componentDidMount 中调度一个动作,该动作将被一个 saga 捕获,该 saga 将执行所有异步操作,然后它会将一个动作由您的 reducer 处理,以便在一切完成后更新组件。

标签: reactjs react-redux


【解决方案1】:

感谢您在这个问题和另一个问题上的建议。我设法让我的 HOC 用于在 Redux 中获取数据。它仍然需要改进但有效:) 我发布了我的解决方案 - 也许有人会受益。这里是回购:https://github.com/krzysztof4M/hoc-data-redux

非常欢迎提出建议和建议。

这是我的 HOC:

import React, { Component } from 'react'
import _ from 'lodash'

import Loader from '../components/Loader'


const FetchData = (ComposedComponent) => {
  class FetchData extends Component {
    constructor(props){
      super(props)
      this.state={
        isLoading: true
      }
    }

    componentDidMount(){
      this.fetchData()
    }

    fetchData(){
      const that = this;
      Promise.all(
        Object.keys(this.props)
          .filter(el => _.isFunction(this.props[el]))
          .map(el => this.props[el]())
      )
      .then(() => {
        console.log('I did everything!', new Date().getTime());
        that.setState({isLoading:false})
      })
    }

    displayContent(){
      const { isLoading } = this.state
      let content = isLoading ? <Loader /> : <ComposedComponent {...this.props}/>
      return content
    }

    render() {
      return (
        <div>
          {this.displayContent()}
        </div>
      );
    }
  }

  return FetchData
}

export default FetchData

这是我在组件中的 HOC 实现(可能有点奇怪):

import React, { Component } from 'react'
import { connect } from 'react-redux'

import requireData from '../utils/requireData'

import { getTodos } from '../actions/todosActions'
import { getPhotos } from '../actions/photosActions'
import { getUsers } from '../actions/usersActions'

class Todos extends Component {
  render() {
    return (
        <div>
        <h1>Users: {this.props.users.length}</h1>
        <h1>Photos: {this.props.photos.length}</h1>
        <h1>Todos: {this.props.todos.length}</h1>
      </div>
    );
  }
}

function mapStateToProps(state){
    return {
        todos: state.todos,
        photos: state.photos,
        users: state.users
    }
}

export default connect(null,{ getTodos, getPhotos, getUsers })(requireData(connect(mapStateToProps)(Todos)))

【讨论】:

    猜你喜欢
    • 2019-01-18
    • 1970-01-01
    • 2020-10-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-12
    • 2021-11-11
    • 1970-01-01
    相关资源
    最近更新 更多