反应如何在循环中进行异步,然后返回react元素

时间:2019-09-13 05:06:49

标签: reactjs

getLinkName(segments) {
    let arr = segments.split('/') // cars/honda
    let el = []
    let baseUrl = arr[0]
    arr.map(async (item, index) => {
        let name = await getCategoryNameFromSlug(baseUrl)
        baseUrl = baseUrl + '/' + arr[index]
        let i = (
            <Link to={'/' + baseUrl} key={index}>
                {name}
            </Link>
        )
        el.push(i)
    })
    console.log('el', el)
    return el
}

我有这个功能,它遍历一个数组。在每个索引。它先获取数据,然后返回数据和一个react元素。

问题,我期望的结果是一组react元素,但是我有很多承诺

2 个答案:

答案 0 :(得分:0)

对于common pattern in React这样的情况,首先要获取异步数据,然后将其保存为状态,从而触发组件的重新呈现。

React元素是React每次触发渲染阶段(例如使用类组件的render方法)寻找changes并创建时使用的基本构建块。作为其内部差异算法实现的一部分,React可能会多次调用render,因此最好不要在渲染阶段依赖异步操作-它需要一个同步返回值。

您可以像这样为类组件实现它:

class ExampleComp extends React.Component {
  state = { nameBaseUrlTuples: [] };

  componentDidMount() {
    this.getLinkName("cars/honda");
  }

  render() {
    return this.state.nameBaseUrlTuples.map((nameBaseUrlTuple, index) => (
      <Link to={"/" + nameBaseUrlTuple[1]} key={index}>
        {nameBaseUrlTuple[0]}
      </Link>
    ));
  }

  async getLinkName(segments) {
    const arr = segments.split("/"); // cars/honda
    let baseUrl = arr[0];
    const nameBaseUrlTuples = await Promise.all(
      // not sure, if you also want to iterate over first index
      // seems as first is your root path segment containing sub categories
      arr.map(async (item, index) => {
        let name = await getCategoryNameFromSlug(baseUrl);
        // You could remove this side effect by
        // using map callback's third "array" argument and
        // compose your URL with array.slice(0, index+1).join("/") or similar
        baseUrl = baseUrl + "/" + item;
        return [name, baseUrl];
      })
    );
    this.setState({ nameBaseUrlTuples });
  }
}

答案 1 :(得分:0)

这是可以预期的,因为这是异步js的工作方式,函数可以运行完成,因此,当getLinkName函数返回时,您的el arr将有很多承诺。

React中的网络请求应在eventListeners或生命周期组件(例如componentDidMount或(如果使用钩子,则为useEffect))上完成

假设您使用的是类组件,则代码应如下所示

// make sure babel supports this or set the initial state in the constructor
state = { categoryNames: null}

componentDidMount() {
    let  baseUrl = segments.split('/')[0]
 Promise.all(segments.split('/').map((item,index) => {
    let name = await getCategoryNameFromSlug(baseUrl)
    baseUrl = baseUrl + '/' + arr[index]
    return name;

})).then(categoryNames => this.setState({categoryNames}))
}



render(){
    // here use categoryNames like you wanted to do in your question

}