2016-11-23 44 views
1

在我的應用程序(React,Redux,React-Router,Express)中我想製作高階組件以獲取每個視圖的初始數據。它將發送請求(每個視圖一個或多個)並顯示Loader Component,直到所有請求都成功並顯示正確的組件。HOC用於在Redux中獲取數據

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)) 

我的解決方案是構建HOC它包裝MainComponent(集裝箱),並通過道具獲得所有必要的行動。它觸發componentDidMount中的所有操作,然後更新存儲並在最後MainComponent(使用連接)被呈現。它看起來很簡單,但是在動作獲取初始數據時會出現問題,例如,我必須使用params。來自商店的userId或來自url的任何其他ID(react-router)。有些行動需要額外的參數,有些則不行。

還有另一個問題... setState在Promise.all()成功之前觸發。我該如何處理? 如何將正確的參數傳遞給HOC?

問候

+0

我不知道如果我完全理解你的處境,但我想知道Redux Saga(http://yelouafi.github.io/redux-saga/)是否有幫助。基本上,你會在componentDidMount中派發一個動作,這個動作將被一個會做所有異步事件的傳奇所捕獲,然後它會讓你的reducer處理一個動作,以便在完成所有事情後更新組件。 – MrOBrian

回答

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)))