我在解决这个反应时遇到了问题.js
loadFromServer(pageSize) {
fetch('http://localhost:8080/api/employees')
.then(response => {
return fetch('http://localhost:8080/api/profile/employees',
{
headers: new Headers({
'Accept': 'application/schema+json'
})
}).then(schema => {
this.scheme = schema;
return response.json();
}
)
})
.then(response =>
this.setState(
{
employees: response._embedded.employees,
attributes: Object.keys(this.scheme.json().properties),
pageSize: pageSize,
links: response._links}
)
);
}
在这一部分
attributes: Object.keys(this.scheme.json().properties),
始终返回(承诺(TypeError: Cannot convert undefined or null to object.
如果我放console.log(this.scheme.json())
我可以看到承诺,但是,为什么在里面setState
我得到空对象?
这里有几个问题:
- 最主要的是
this.schema.json()
返回一个承诺(正如您从console.log
中知道的那样(。承诺没有properties
属性,因此您将undefined
传递给Object.keys
,然后会给您该错误。 - 你也没有以两种不同的方式检查来自
fetch
的错误:你没有检查.ok
(这是我在贫乏的小博客上发布的一个常见错误(,你没有检查承诺拒绝。
您还在做一些不必要的承诺嵌套,并且可能会更多地重叠您的fetch
调用。
首先,由于您似乎经常获取 JSON,我建议为自己提供一个实用程序函数:
function fetchJSON(...args) {
return fetch(...args)
.then(response => {
if (!response.ok) {
throw new Error('HTTP error ' + response.status);
}
return response.json();
});
}
请注意.ok
检查。
然后,同样在"将问题分解为更小的部分"类别中,我将有一个fetchSchema
函数:
function fetchSchema(url) {
return fetchJSON(url, {
headers: new Headers({
'Accept': 'application/schema+json'
})
});
}
然后,loadFromServer
可以使用Promise.all
和解构来并行运行操作:
// (I assume this is in a `class` or object initializer, as it doesn't have `function` in front of it)
loadFromServer(pageSize) {
Promise.all(
fetchJSON('http://localhost:8080/api/employees'),
fetchSchema('http://localhost:8080/api/profile/employees')
)
.then(([empResponse, schema]) => {
this.schema = schema;
this.setState({
employees: empResponse._embedded.employees,
attributes: Object.keys(schema.properties),
pageSize: pageSize,
links: empResponse._links
})
)
.catch(error => {
// Do something with the error
});
}
请注意.catch
,因为您不会从loadFromServer
返回承诺。(如果要将错误反转到链上,请在Promise.all
前面添加return
,并将.catch
移动到调用代码。
旁注:您的代码已使用
this.scheme = schema;
请注意,左侧的属性是scheme
的(带有最终e
(,但变量是schema
的(带有最终a
(。我想你的意思是schema
所以我在上面包含了这个变化,但如果属性真的应该this.scheme
,你会想要调整它。或者,如果您不需要该属性来处理loadFromServer
中的代码以外的任何内容,请完全删除该行。
我认为您应该使用Promise.all
在 parrallel 中运行两个请求,然后检索两个响应(顺便说一下response.json()
返回一个Promise
,这就是您的代码中有错误的原因(:
loadFromServer(pageSize) {
Promise.all([
fetch('http://localhost:8080/api/employees')
.then(response => {
if (!response.ok) throw Error(response.statusText);
return response.json();
),
fetch('http://localhost:8080/api/profile/employees')
.then(response => {
if (!response.ok) throw Error(response.statusText);
return response.json();
),
]).then(responses => {
this.setState({
employees: responses[0]._embedded.employees,
attributes: Object.keys(responses[1].properties),
pageSize: pageSize,
links: responses[0]._links
})
}).catch(error => {...})
}
我认为你需要这样的东西:
loadFromServer(pageSize) {
fetch('http://localhost:8080/api/employees')
.then(response => {
return fetch('http://localhost:8080/api/profile/employees', {
headers: new Headers({
'Accept': 'application/schema+json'
})
}).then(schema => {
schema.json().then(data => {
this.scheme = data
})
});
return response.json();
})
.then(response =>
this.setState({
employees: response._embedded.employees,
attributes: Object.keys(this.scheme.properties),
pageSize: pageSize,
links: response._links
})
);
}
Fetch API 中的响应json()
方法返回一个承诺。因此,fetch
请求应始终与.then(response => response.json())
链接,以获取普通对象。
扁平化承诺可能会产生更可靠的控制流。由于使用了来自两个请求的响应,因此这需要嵌套then
回调或通过链传递另一个响应then
。async
可能很有用,因为它可以方便地解决扁平化问题:
async loadFromServer(pageSize) {
const employeesResponse = await fetch('http://localhost:8080/api/employees', {
headers: new Headers({ 'Accept': 'application/schema+json' })
});
const employees = await employeesResponse.json();
const schemeResponse = await fetch('http://localhost:8080/api/profile/employees', {
headers: new Headers({ 'Accept': 'application/schema+json' })
});
const scheme = await schemeResponse.json();
this.setState({
employees: employees._embedded.employees,
attributes: Object.keys(scheme.properties),
pageSize: pageSize,
links: response._links
});
}
由于请求不相互依赖,因此它们可以与Promise.all
并行执行。
async loadFromServer(pageSize) {
const employeesPromise = fetch('http://localhost:8080/api/employees', {
headers: new Headers({ 'Accept': 'application/schema+json' })
})
.then(res => res.json());
const schemePromise = fetch('http://localhost:8080/api/profile/employees', {
headers: new Headers({ 'Accept': 'application/schema+json' })
})
.then(res => res.json());
const [employees, scheme] = await Promise.all([employeesPromise, schemePromise]);
this.setState({
employees: employees._embedded.employees,
attributes: Object.keys(scheme.properties),
pageSize: pageSize,
links: response._links
});
}