2017-04-21 102 views
0

首先我的代码工作(一切正常导出等),但它并没有等待数据的异步返回。 我使用终极版 - 咚我的异步中间件React/Redux异步不等待返回的响应

我有一个名为动作async.js

export function itemsHasErrored(bool) { 
    return { 
     type: 'ITEMS_HAS_ERRORED', 
     hasErrored: bool 
    }; 
} 

export function itemsIsLoading(bool) { 
    return { 
     type: 'ITEMS_IS_LOADING', 
     isLoading: bool 
    }; 
} 

export function itemsFetchDataSuccess(items) { 
    return { 
     type: 'ITEMS_FETCH_DATA_SUCCESS', 
     items 
    }; 
} 

export function itemsFetchData(url) { 
    return (dispatch) => { 
     dispatch(itemsIsLoading(true)); 

     fetch(url) 
      .then((response) => { 
       if (!response.ok) { 
        throw Error(response.statusText); 
       } 

       dispatch(itemsIsLoading(false)); 

       return response; 
      }) 
      .then((response) => response.json()) 
      .then((items) => dispatch(itemsFetchDataSuccess(items))) 
      .catch(() => dispatch(itemsHasErrored(true))); 
    }; 
} 

我减速

export function itemsHasErrored(state = false, action) { 
    switch (action.type) { 
     case 'ITEMS_HAS_ERRORED': 
      return action.hasErrored; 

     default: 
      return state; 
    } 
} 

export function itemsIsLoading(state = false, action) { 
    switch (action.type) { 
     case 'ITEMS_IS_LOADING': 
      return action.isLoading; 

     default: 
      return state; 
    } 
} 

export function items(state = [], action) { 
    switch (action.type) { 
     case 'ITEMS_FETCH_DATA_SUCCESS': 
      return action.items; 

     default: 
      return state; 
    } 
} 

我有一个容器组件, asyncContainer.js

import React, {Component} from 'react'; 
import PropTypes from 'prop-types'; 
import { connect } from 'react-redux' 

import {itemsFetchData} from '../../../actions/async'; 
import AsyncUI from './asyncUI' 

class AsyncContainer extends Component { 

    componentDidMount() { 
     this.props.fetchData('http://5826ed963900d612000138bd.mockapi.io/items'); 
    } 

    render() { 

     if (this.props.hasErrored) { 
      return <p>Sorry! There was an error loading the items</p>; 
     } 

     if (this.props.isLoading) { 
      return <p>Loading…</p>; 
     } 
//This fails to wait 
     return (
       <AsyncUI /> 
     ); 
    } 
} 

AsyncContainer.propTypes = { 
    fetchData: PropTypes.func.isRequired, 
    items: PropTypes.array.isRequired, 
    hasErrored: PropTypes.bool.isRequired, 
    isLoading: PropTypes.bool.isRequired 
}; 

const mapStateToProps = (state) => { 
    return { 
     items: state.items, 
     hasErrored: state.itemsHasErrored, 
     isLoading: state.itemsIsLoading 
    }; 
}; 

const mapDispatchToProps = (dispatch) => { 
    return { 
     fetchData: (url) => dispatch(itemsFetchData(url)) 
    }; 
}; 

export default connect(mapStateToProps, mapDispatchToProps)(AsyncContainer); 

最后我有一个名为一个简单的UI组件asyncUI.js写在一个功能性的方式

import React, {Component} from 'react'; 
import PropTypes from 'prop-types'; 
import { connect } from 'react-redux' 

const AsyncUI = (items) => { 

    return (
     <ul> 
      {items.map((item) => (
       <li key={item.id}> 
        {item.label} 
       </li> 
      ))} 
     </ul> 
    ); 
} 

const mapStateToProps = (state) => { 
    return { 
     items: state.items 
    }; 
}; 

export default connect(mapStateToProps)(AsyncUI); 

asyncContainer.js你可以看到呼叫我简单的UI组件

return (
       <AsyncUI /> 
     ); 

但是在调用REDX存储的物业物品asyncUI.js空数组,所以items.map失败

然而,如果我从asyncUI.js删除代码,并将其放置在asyncContainer.js它工作

这是工作代码在asyncContainer.js

class AsyncContainer extends Component { 
     componentDidMount() { 
      this.props.fetchData('http://5826ed963900d612000138bd.mockapi.io/items'); 
     } 

     render() { 
      if (this.props.hasErrored) { 
       return <p>Sorry! There was an error loading the items</p>; 
      } 

      if (this.props.isLoading) { 
       return <p>Loading…</p>; 
      } 

//THIS IS WHERE I HAD <Async /> 
      return (
       <ul> 
        {this.props.items.map((item) => (
         <li key={item.id}> 
          {item.label} 
         </li> 
        ))} 
       </ul> 
      ); 
     } 
    } 

    AsyncContainer.propTypes = { 
     fetchData: PropTypes.func.isRequired, 
     items: PropTypes.array.isRequired, 
     hasErrored: PropTypes.bool.isRequired, 
     isLoading: PropTypes.bool.isRequired 
    }; 

    const mapStateToProps = (state) => { 
     return { 
      items: state.items, 
      hasErrored: state.itemsHasErrored, 
      isLoading: state.itemsIsLoading 
     }; 
    }; 

    const mapDispatchToProps = (dispatch) => { 
     return { 
      fetchData: (url) => dispatch(itemsFetchData(url)) 
     }; 
    }; 

    export default connect(mapStateToProps, mapDispatchToProps)(AsyncContainer); 

我认为这个问题是该组件在项目数据准备好之前进行渲染。这是正常的反应行为。那么如何“延缓”渲染?正如你所看到的,我正尝试使用容器/组件风格的体系结构。我总是可以使用上面提到的解决方案,但我想坚持使用此容器/组件。 我需要深入研究Promise等吗? 我不应该使用asyncUI.js的函数式写法吗? 我有点困惑。

回答

2

尝试:

const AsyncUI = ({items}) => { 
       /*^see^*/ 
    return (
     <ul> 
      {items.map((item) => (
       <li key={item.id}> 
        {item.label} 
       </li> 
      ))} 
     </ul> 
    ); } 

这拉items值关闭您在mapStateToProps功能,这是反应道具一个对象,而不是一个数组(因此没有map函数)。

注:这应该可以解决您的问题,但它仍然是技术上努力使项目他们之前准备在2个实例:

  1. 第一次组件呈现。 itemsIsLoading的初始状态为false,所以第一次渲染将会失败所有安全检查。 items的默认值是[],所以它应该只是呈现<ul></ul>一段时间,直到itemsIsLoading(true)操作被调度。您可以设置初始状态为true制止这种,或者改变装载检查以

    if (this.props.isLoading || this.props.items.length != 0) { 
        return <p>Loading…</p>; 
    } 
    

    的参数可以如何要么这些解决方案的需要实际上是进行。

  2. fetch后返回的动作被分派会导致另一个简短的装载状态设置为false设置项目之前的<ul></ul>呈现的顺序。请参阅dgrijuela's answer以解决此问题。另一种方法是不派遣单独的动作,并让ITEMS_FETCH_DATA_SUCCESSITEMS_HAS_ERRORED动作也将itemsIsLoading值更改回false(多个减速器可以对相同的动作类型起作用)。

+0

嗨,谢谢,这是有效的,这是我犯的一个简单的错误。我已经提出你的答案,欢呼 – Rory

+0

任何特殊原因不接受它呢? –

+0

opps,我忘了:-) – Rory

0

你叫dispatch(itemsIsLoading(false))dispatch(itemsFetchDataSuccess(items))

尝试这样的:

// async.js 
... 

export function itemsFetchData(url) { 
    return (dispatch) => { 
    dispatch(itemsIsLoading(true)); 

    fetch(url) 
     .then((response) => { 
      if (!response.ok) { 
       throw Error(response.statusText); 
      } 

      return response; 
     }) 
     .then((response) => response.json()) 
     .then((items) => { 
      dispatch(itemsFetchDataSuccess(items)); 
      dispatch(itemsIsLoading(false)); 
     }) 
     .catch(() => dispatch(itemsHasErrored(true))); 
    }; 
} 
+0

没有工作,完全一样。 asyncUI在数据(项目)准备好之前呈现 – Rory

+0

您的答案对某个学位是正确的,但我也需要Micheal Peyper的回答以及 – Rory

0

看到迈克尔Peyper一个很好的答案

事实证明,问题是我asyncUI分量的编码的功能性风格。我将它转换回'标准'有状态组件并且它的效果非常好。

asyncContainer.js

class AsyncContainer extends Component { 

    componentDidMount() { 
     this.props.fetchData('http://5826ed963900d612000138bd.mockapi.io/items'); 
    } 

    render() { 

      if (this.props.hasErrored) { 
        return <p>Sorry! There was an error loading the items</p>; 
       } 

       if (this.props.isLoading) { 
        return <p>Loading…</p>; 
       } 
       return (
        <AsyncUI />  
     ) 

    } 
} 

asyncUI.js

import React, {Component} from 'react'; 
import PropTypes from 'prop-types'; 
import { connect } from 'react-redux' 

    class AsyncUI extends Component { 

     render() { 
       return (
       <ul> 
       {this.props.items.map((item) => (
        <li key={item.id}> 
         {item.label} 
        </li> 
       ))} 
      </ul> 
      ) 
     } 
    } 

    const mapStateToProps = (state) => { 
     return { 
      items: state.items, 
     }; 
    }; 

export default connect(mapStateToProps)(AsyncUI); 

希望这有助于任何人:-)