我在解决此react.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())
,我可以看到Promise,但是为什么在setState
里面却得到空对象?
答案 0 :(得分:2)
这里有几个问题:
this.schema.json()
返回了一个承诺(如您从console.log
所知)。承诺没有properties
属性,因此您要将undefined
传递给Object.keys
,这会给您该错误。fetch
的错误:您不是在检查.ok
(这是常见的错误I've posted about it on my anemic little blog),而是不检查承诺是否被拒绝。您还在做一些不必要的Promise嵌套,可能会使您的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
返回承诺。 (如果要消除错误,请在return
前面添加Promise.all
,然后将.catch
移至调用代码。)
旁注:您的代码已使用
this.scheme = schema;
请注意,左侧的属性为scheme
(带最后一个e
),但变量为schema
(带最后一个a
)。我认为您的意思是schema
,因此我已经在上面包含了该更改,但是如果该属性确实应该为this.scheme
,则需要进行调整。或者,如果除了loadFromServer
中的代码之外,您不需要该属性,请完全删除该行。
答案 1 :(得分:2)
我认为您应该使用Promise.all
并行运行两个请求,然后检索两个响应(通过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 => {...})
}
答案 2 :(得分:1)
Fetch API returns a promise中的响应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
});
}
答案 3 :(得分:1)
我认为您需要类似的东西:
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
})
);
}