我有一个返回要下载的文件的后端。
目前,当用户执行某些操作时,会调度一个操作,该操作运行 reducer export
并执行下载文件的常用技巧。我正在使用 redux-toolkit。
const mySlice = createSlice({
name: "my",
initialState,
reducers: {
export: (state) => {
const link = document.createElement("a")
link.href = '...'
document.body.appendChild(link)
link.click()
link.parentNode?.removeChild(link)
},
}
})
这有效。但是,我想在下载时向用户提供反馈,即模式对话框。因此,我在状态中定义了一个 isExporting
属性,并且有一个组件根据此属性显示对话框。
但是,这样编写的 reducer 不起作用:
export: (state) => {
state.isExporting = true
const link = document.createElement("a")
link.href = '...'
document.body.appendChild(link)
link.click()
link.parentNode?.removeChild(link)
state.isExporting = false
},
因为我相信我引入了副作用,而且状态将在 reducer 执行后设置,而不是在执行之间设置。
正确的做法是什么?
最佳答案
创建一个异步操作createAsyncThunk
并使用cases定义一个extraReducer:
For this example i create async function download
const fakeDownload = async () =>
new Promise((resolve) =>
setTimeout(() => {
const link = document.createElement("a");
link.href = "...";
document.body.appendChild(link);
link.click();
link.parentNode?.removeChild(link);
resolve();
}, 1000) // I set a timeout to emulate a request.
);
创建异步操作:
export const downloadFile = createAsyncThunk(
"download/file",
async (_, thunkApi) => {
try {
return fakeDownload();
} catch (e) {
return thunkApi.rejectWithValue("Impossible to download");
}
}
);
reducer :
const initialState = {
isExporting: false
};
export const appSlice = createSlice({
name: "app",
initialState,
reducers: {},
extraReducers: (builder) => {
builder.addCase(downloadFile.pending, (state) => {
state.isExporting = true;
});
builder.addCase(downloadFile.fulfilled, (state) => {
state.isExporting = false;
});
builder.addCase(downloadFile.rejected, (state) => {
// Do something with error
state.isExporting = false;
});
}
});
export const isExportingSelector = (state) => state.app.isExporting;
export default appSlice.reducer;
现在您可以使用选择器和调度操作。
您可以在这里找到一个实例:
关于reactjs - 以编程方式下载文件,同时使用 Redux 向用户提供反馈,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70622675/