Javascript 如何使React-Redux异步操作返回承诺?
我有一个redux操作函数,它返回一个承诺。在该函数体中,还有另一个异步函数,它在完成调用时返回回调。然后我在另一个地方调用这个函数,并用Javascript 如何使React-Redux异步操作返回承诺?,javascript,reactjs,redux,es6-promise,redux-thunk,Javascript,Reactjs,Redux,Es6 Promise,Redux Thunk,我有一个redux操作函数,它返回一个承诺。在该函数体中,还有另一个异步函数,它在完成调用时返回回调。然后我在另一个地方调用这个函数,并用链接它。然后(),但是当在浏览器中使用断点调试它时,promise函数在前两行代码之后存在 return new Promise((resolve, reject) => { return (dispatch, getState) => { 是因为第二个return语句吗?这是react/redux代码,因此我必须为异步Thunk-red
链接它。然后()
,但是当在浏览器中使用断点调试它时,promise函数在前两行代码之后存在
return new Promise((resolve, reject) => {
return (dispatch, getState) => {
是因为第二个return语句吗?这是react/redux
代码,因此我必须为异步Thunk-redux操作提供第二条返回语句。我怎样才能做到这一点?这样我就可以在另一个redux操作中调用它,并将它与handleProfileImageUploadToS3()链接起来。然后(()=>{…})
全功能机构:
export const handleProfileImageUploadToS3 = () => {
return new Promise((resolve, reject) => {
return (dispatch, getState) => {
const settingsState = getState().BusinessSettings
const userState = getState().User
const imageUpload = true
if (!settingsState.get('logoImage') || settingsState.get('logoImage') === null) {
reject('no image selected')
return
}
Utilities.uploadFileToS3(
imageUpload,
settingsState.get('logoImage'),
'apiurl',
`profiles/${userState.get('id')}`,
(error, url) => {
if (error) {
dispatch(uploadProfileSettingsImageError(error))
return
}
dispatch(updateProfileImageUrlAfterUpload(url))
resolve(url)
}
)
}
})
}
经过进一步研究,我发现在返回
newpromise
之前,必须从初始Promise函数返回另一个函数,才能访问Reduxdispatch
和getState
方法,而不是在newpromise()中作为匿名函数返回
代码块,然后它将退出函数执行。以下是完整的代码:
export const handleProfileImageUploadToS3 = () => (dispatch, getState) => {
return new Promise((resolve, reject) => {
const settingsState = getState().BusinessSettings
const userState = getState().User
const imageUpload = true
if (!settingsState.get('logoImage') || settingsState.get('logoImage') === null) {
reject('no image selected')
return
}
Utilities.uploadFileToS3(
imageUpload,
settingsState.get('logoImage'),
'apiurl',
`profiles/${userState.get('id')}`,
(error, url) => {
if (error) {
dispatch(uploadProfileSettingsImageError(error))
return
}
dispatch(updateProfileImageUrlAfterUpload(url))
resolve(url)
}
)
})
}
我没有看到您的整个代码库,但是这个函数中有一些我关心的危险信号
- 状态的
和BusinessSettings
属性似乎是带有User
方法的对象get()
- 如果S3上传出现错误,则您
和发送
,但您从未返回
或解决
承诺拒绝
的拒绝不太可能在任何地方被捕获reject('no image selected')
- 似乎一个未上传的图像应该存储在UI状态中,并作为参数传递,而不是存储在Redux中。您可能希望在上传后存储URL。这也消除了拒绝的必要性
您在该功能中解决了两个不同的问题,我建议您将这两个问题分开 首先,您有一个函数
Utilities.uploadFileToS3
,它使用成功/失败回调,您希望将其转换为异步函数(返回承诺的函数)
我将创建一个助手,它只接受变化的参数,而忽略不变的参数(如'apirl'
)
既然你已经解决了这一部分,你就可以用一种更典型的方式来写thunk了。您可以通过.then()
链接或使函数异步
并使用try
/catch
块返回承诺。到目前为止,我们不需要将整个过程包装在新承诺中,因为我们已经在asyncUploadFileToS3
函数中处理过了
您可以从thunk返回一个结果并将其链接,但我不确定这里什么是最有意义的
export const handleProfileImageUploadToS3 = (image) =>
async ( dispatch, getState ) => {
const userId = getState().user.id;
try {
const url = await asyncUploadFileToS3(image, userId);
dispatch(updateProfileImageUrlAfterUpload(url));
return "this is the result";
} catch (error) {
dispatch(uploadProfileSettingsImageError(error));
return "there was an error";
}
};
导出默认函数App(){
const dispatch=usedpatch();
const avatar=useSelector((state)=>state.user.imageUrl);
const onClick=()=>{
const image=new Blob();
发送(handleProfileImageUploadToS3(图像)),然后(
//记录“这是结果”或“出现错误”
(返回)=>console.log(“完成”,返回)
);
};
返回(
上传
{化身?化身URL:{化身}:无化身}
);
}
如果(错误)
,您是否需要解决或拒绝?看起来它可能永远挂在那里。如果是我个人,我会分别处理这两个问题。这些问题是:1)您需要围绕实用程序.uploadFileToS3
函数创建一个Promise
包装器,因为它不是异步的;2)您需要创建一个使用该函数的thunk分派。当您在此处拒绝“未选择图像”时,是否在任何地方捕获?settingsState
是您的Redux状态的一部分,但您正在调用settingsState.get('logoImage')
,这对我来说非常奇怪,因为您的Redux状态应该是原始的可序列化数据。它不应该有get()
方法。(与userState.get('id')
)相同。@LindaPaiste它没有挂在Utilities.uploadFileToS3()
回调中,通过使用断点,我发现函数正在执行第二行代码,返回(dispatch,getState)=>{}
,但我仍然不确定原因。uploadFileToS3()本身是一个异步函数,但它使用回调而不是承诺。如果它失败,我应该在它的回调中使用reject吗?“2)您需要创建一个使用该函数的thunk分派”-现在使用它与将其作为自己的操作分派有什么区别?它现在运行得很好。@LindaPaiste关于redux商店调用,我不确定,我们在整个项目中都是这样做的,我最近才被介绍到这个项目中,所以我不确定redux的好做法是什么。这就是减速机的外观:const getInitialState=()=>{return Map({logoImage:'',brandName:'',website:'',countryCode:'',currency:'',vat:'',})
使用映射不是一个好主意。只需存储该对象,而不在其周围添加贴图
。谢谢你的全面回答。有很多东西需要吸收。“似乎一个未上传的图像应该存储在您的UI状态中,并作为参数传递,而不是存储在Redux中。”我确实这样做了。我将图像blob存储在本地状态,并仅在单击“保存”按钮时将其保存到redux存储。我将文件对象保存在redux存储中,我使用它上传到S3,获取url,将存储从文件对象更新为S3生成的url,然后调用另一个操作将该url保存到数据库。
export const handleProfileImageUploadToS3 = (image) =>
async ( dispatch, getState ) => {
const userId = getState().user.id;
try {
const url = await asyncUploadFileToS3(image, userId);
dispatch(updateProfileImageUrlAfterUpload(url));
return "this is the result";
} catch (error) {
dispatch(uploadProfileSettingsImageError(error));
return "there was an error";
}
};
export default function App() {
const dispatch = useDispatch();
const avatar = useSelector((state) => state.user.imageUrl);
const onClick = () => {
const image = new Blob();
dispatch(handleProfileImageUploadToS3(image)).then(
// logs "this is the result" or "there was an error"
(returned) => console.log("finished", returned)
);
};
return (
<div>
<button onClick={onClick}>Upload</button>
{avatar ? <div>Avatar URL: {avatar}</div> : <div>No Avatar</div>}
</div>
);
}