reactjs - 以编程方式下载文件,同时使用 Redux 向用户提供反馈

标签 reactjs react-redux redux-toolkit

我有一个返回要下载的文件的后端。

目前,当用户执行某些操作时,会调度一个操作,该操作运行 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;

现在您可以使用选择器和调度操作。

您可以在这里找到一个实例:

Edit goofy-thompson-8bbfc

关于reactjs - 以编程方式下载文件,同时使用 Redux 向用户提供反馈,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70622675/

相关文章:

javascript - React JS 异步重计算

reactjs - Redux 工具包查询变异乐观更新

javascript - 弹出窗口未显示在表行内的按钮中

reactjs - Material-ui 的 Switch 组件 onChange 处理程序未触发

javascript - ReactJS路由器不渲染组件

javascript - 切换状态在 react 中采用先前的值?

Typescript 找不到 redux

javascript - 如何在TypeScript定义中定义ReactFunctionalComponent的返回类型

reactjs - React - 可重用的 Redux hook 切片问题(Redux Toolkit、Typescript)

reactjs - React Redux 工具包 : TypeError: Cannot read property 'value' of undefined