在 fetch 返回的承诺上使用 then() 返回 React 中未定义的



我正在遵循本教程:https://github.com/callicoder/spring-security-react-ant-design-polls-app

我已经有一个生成 JWT 的工作后端,并且 API 使用GET方法 http://localhost:8080/api/user/me 返回当前用户的详细信息。背面都很好(用邮递员测试)。

但是当我尝试将当前用户从 API 加载到我的App组件的状态时,我遇到了问题。这个想法是创建一个到Login组件的路由,并向其传递对handleLogin方法的引用,该方法执行getCurrentUser()并重定向到主页。

所有这些都是通过导入名为APIUtils的文件来完成的,该文件具有与 API 交互的方法。特别是,它有一个通用的request()方法,它使用 fetch 返回一个承诺,并接收请求的参数。问题是我无法获得APIUtils/request()方法返回的承诺的响应。它说它是未定义的。

应用.js

//imports
class App extends Component {
state = {
currentUser: null
}
loadCurrentUser = () => {
// getCurrentUser is imported from APIUtils/index.js
getCurrentUser()
.then(response => {
this.setState({
currentUser: response
});
})
.catch(error => {
console.log(error)
});
}
handleLogin = () => {
this.loadCurrentUser();
this.props.history.push("/");
}
componentDidMount() {
this.loadCurrentUser();
}
render () {
return (
<Switch>
<Route exact path='/' component={Landing} />
<Route path="/login" 
render={
(props) => <Login onLogin={this.handleLogin} {...props} />
}/>
</Route>
</Switch>
);
}
}
export default withRouter(App);

APIUtils/index.js

const request = (options) => {
const headers = new Headers({
'Content-Type': 'application/json',
})
if(localStorage.getItem(ACCESS_TOKEN)) {
headers.append('Authorization', 'Bearer ' + localStorage.getItem(ACCESS_TOKEN))
}
const defaults = { headers: headers };
options = Object.assign({}, defaults, options);
return fetch(options.url, options)
.then(response => {
response.json().then(json => {
if(!response.ok) {
return Promise.reject(json);
}
return json;
})}
);
}
// expects loginRequest = { email: 'something', password: 'something' }
export const login = (loginRequest) => {
return request({
url: API_BASE_URL + "/auth/signin",
method: 'POST',
body: JSON.stringify(loginRequest)
});
}
export const getCurrentUser = () => {
if(!localStorage.getItem(ACCESS_TOKEN)) {
return Promise.reject("No access token set.");
}
return request({
url: API_BASE_URL + "/user/me",
method: 'GET'
});
}

登录.js

class Login extends Component {
state = {
email: '',
password: ''
}
handleChange = (event) => {
this.setState({
[event.target.id]: event.target.value
});
}
handleSubmit = (event) => {
event.preventDefault();
const loginRequest = Object.assign({}, this.state);
login(loginRequest)
.then(response => {
localStorage.setItem(ACCESS_TOKEN, response.accessToken);
this.props.onLogin();
}).catch(error => {
if(error.status === 401) {
console.log('Your Username or Password is incorrect. Please try again!');
} else {
console.log('Sorry! Something went wrong. Please try again!');                                         
}
});
}
render () {
return (
<React.Fragment>
/* 
* form using onSubmit={this.handleSubmit}
* inputs using value={this.state.email} and onChange={this.handleChange}
* button of type="submit"
*/
</React.Fragment>
);
} 
}
export default Login;

有了这个,在我登录并加载登录页面后,通过控制台我检查了并且我在本地存储中有令牌,APIUtils 中的 request() 方法也返回带有 URL: http://localhost:8080/api/user/me 的响应,并返回代码中的json承诺,如下所示:

{
"id": 23,
"name": "john",
"email": "new@mail.com"
}

但是当我尝试使用 then() 访问应用程序中的 getCurrentUser() 的响应时.js它的响应是未定义的,所以我无法将其设置为状态。

您没有返回fetch()的结果:

return fetch(options.url, options)
.then(response => { // you forgot that this is also a function
return response.json().then(json => { // <--- missing return!!
if(!response.ok) {
return Promise.reject(json);
}
return json;
})}
);

我能理解你为什么可能错过了它。这很容易错过。这就是为什么你应该使用承诺的主要功能 - 它们被发明的原因 - 承诺链接:

let ok = null;
return fetch(options.url, options)
.then(response => {
ok = response.ok;
return response.json();
})
.then(json => {
if (!ok) {
return Promise.reject(json);
}
return json;
});

通过这种方式更容易发现缺失的返回,因为您可以轻松检查每个then块是否具有return语句。

最新更新