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元素,但是我有很多承诺
答案 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
}