我刚接触React、Redux和Thunk,并且一直在关注这个主题的教程,最近在Pluralsight上使用了Building Applications with React and Redux in ES6。我一直在将本教程从ES6转换为Typescript 3,并将React v3转换为React v4。
我遇到了很多问题,我已经能够按照这个模式解决(最值得注意的是任何与路由相关的问题),但我遇到了一个我不能解决的问题。从各种来源的Inc. Cannot read property '.then' of undefined when testing async action creators with redux and react 听起来,我不能在返回空的函数上使用.then()函数,但它是一个(应该)返回promise的异步函数,但是intellisense并非如此。下面的代码。
saveCourse = (event: any) => {
event.preventDefault();
this.props.actions.saveCourse(this.state.course)
.then(this.setState({ fireRedirect: true }));
}上面的代码在我的组件上,props.actions通过mapStateToProps连接到redux存储,这个函数在点击按钮时调用。是上面这个函数上的.then()出错了。此函数调用下面的操作
export const saveCourse = (course: Course) => {
return (dispatch: any, getState: any) => {
dispatch(beginAjaxCall());
courseApi.saveCourse(course).then((savedCourse: Course) => {
course.id ? dispatch(updateCourseSuccess(savedCourse)) :
dispatch(createCourseSuccess(savedCourse));
}).catch(error => {
throw (error);
});
}
}上面的操作是asyc调用,这里的.then()没有错误,但是VS代码说整个saveCourse函数返回空。
从教程中可以看出,实际上并没有什么不同之处(箭头是用来代替常规的,等等)。所以我想知道是不是在版本之间有一个模糊的变化,我错过了,但不确定到哪里去寻找,并且可能缺少一些基本的东西。有人知道为什么我不能在saveCourse()函数上执行.then()了吗?
如果你需要更多信息,请告诉我。
编辑: courseApi只是一个mock api,代码如下。
import delay from './delay';
const courses = [
{
id: "react-flux-building-applications",
title: "Building Applications in React and Flux",
watchHref: "http://www.pluralsight.com/courses/react-flux-building-applications",
authorId: "cory-house",
length: "5:08",
category: "JavaScript"
},
{
id: "clean-code",
title: "Clean Code: Writing Code for Humans",
watchHref: "http://www.pluralsight.com/courses/writing-clean-code-humans",
authorId: "cory-house",
length: "3:10",
category: "Software Practices"
},
{
id: "architecture",
title: "Architecting Applications for the Real World",
watchHref: "http://www.pluralsight.com/courses/architecting-applications-dotnet",
authorId: "cory-house",
length: "2:52",
category: "Software Architecture"
},
{
id: "career-reboot-for-developer-mind",
title: "Becoming an Outlier: Reprogramming the Developer Mind",
watchHref: "http://www.pluralsight.com/courses/career-reboot-for-developer-mind",
authorId: "cory-house",
length: "2:30",
category: "Career"
},
{
id: "web-components-shadow-dom",
title: "Web Component Fundamentals",
watchHref: "http://www.pluralsight.com/courses/web-components-shadow-dom",
authorId: "cory-house",
length: "5:10",
category: "HTML5"
}
];
function replaceAll(str: any, find: any, replace: any) {
return str.replace(new RegExp(find, 'g'), replace);
}
//This would be performed on the server in a real app. Just stubbing in.
const generateId = (course: any) => {
return replaceAll(course.title, ' ', '-');
};
class CourseApi {
static getAllCourses() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(Object.assign([], courses));
}, delay);
});
}
static saveCourse(course: any) {
course = Object.assign({}, course); // to avoid manipulating object passed in.
return new Promise((resolve, reject) => {
setTimeout(() => {
// Simulate server-side validation
const minCourseTitleLength = 1;
if (course.title.length < minCourseTitleLength) {
reject(`Title must be at least ${minCourseTitleLength} characters.`);
}
if (course.id) {
const existingCourseIndex = courses.findIndex(a => a.id == course.id);
courses.splice(existingCourseIndex, 1, course);
} else {
//Just simulating creation here.
//The server would generate ids and watchHref's for new courses in a real app.
//Cloning so copy returned is passed by value rather than by reference.
course.id = generateId(course);
course.watchHref = `http://www.pluralsight.com/courses/${course.id}`;
courses.push(course);
}
resolve(course);
}, delay);
});
}
static deleteCourse(courseId: any) {
return new Promise((resolve, reject) => {
setTimeout(() => {
const indexOfCourseToDelete = courses.findIndex(course =>
course.id == courseId
);
courses.splice(indexOfCourseToDelete, 1);
resolve();
}, delay);
});
}
}
export default CourseApi;发布于 2018-08-23 17:23:11
你的问题是你没有在你的Action Creator中返回承诺。
看看下面的redux-thunk示例:
https://github.com/reduxjs/redux-thunk
function makeASandwichWithSecretSauce(forPerson) {
// Invert control!
// Return a function that accepts `dispatch` so we can dispatch later.
// Thunk middleware knows how to turn thunk async actions into actions.
return function (dispatch) {
return fetchSecretSauce().then(
sauce => dispatch(makeASandwich(forPerson, sauce)),
error => dispatch(apologize('The Sandwich Shop', forPerson, error))
);
};
}他们返回由fetchSecretSauce生成的promise。
您需要类似地返回示例中的promise:
export const saveCourse = (course: Course) => {
return (dispatch: any, getState: any) => {
dispatch(beginAjaxCall());
return courseApi.saveCourse(course).then((savedCourse: Course) => {
course.id ? dispatch(updateCourseSuccess(savedCourse)) :
dispatch(createCourseSuccess(savedCourse));
}).catch(error => {
throw (error);
});
}
}发布于 2019-07-28 00:11:02
除了在Action Creator中返回promise之外,您可能还希望确保在mapDispatchToProps中,映射的相应函数应该声明为async。它可以在其中await分派语句。
我遇到了类似的问题,出现了完全相同的错误消息,但除了返回promise之外,这是我一开始没有注意到的事情。
https://stackoverflow.com/questions/51981388
复制相似问题