reduxjs / redux

A JS library for predictable global state management
https://redux.js.org
MIT License
60.93k stars 15.27k forks source link

Abort queries before unmount #4716

Closed DavidNguyen67 closed 4 months ago

DavidNguyen67 commented 4 months ago

userApi.slice.ts

export const userApi = createApi({
  baseQuery: axiosBaseQuery(),
  tagTypes: [QUERY_TAG.USER, QUERY_TAG.COUNT_USER],
  endpoints: (build) => ({
    getUsers: build.query<UserEntity[] | null, ListUserDto>({
      queryFn: async (payload, _queryApi, _extraOptions, baseQuery) => {
        try {
          const data = await userService.listUsers(payload, {});
          return { data };
        } catch (error) {
          return { error };
        }
      },
      providesTags: (result, error, arg) =>
        result && result?.length > 0
          ? [
              ...result.map(({ id }) => ({
                type: QUERY_TAG.USER as const,
                id,
              })),
              QUERY_TAG.USER,
            ]
          : [QUERY_TAG.USER],
    }),
    countUsers: build.query<number | null, undefined>({
      queryFn: async (_, _queryApi, _extraOptions, baseQuery) => {
        try {
          const data = await userService.countUser({});
          return { data };
        } catch (error) {
          return { error };
        }
      },
      providesTags: (result, error, arg) => [QUERY_TAG.COUNT_USER],
    }),
    registerUses: build.mutation<string | null, CreateUserDto>({
      queryFn: async (payload, _queryApi, _extraOptions, baseQuery) => {
        const { signal } = _queryApi;

        try {
          const data = await userService.generateUser(payload, { signal });
          return { data };
        } catch (error) {
          return { error };
        }
      },
      invalidatesTags: [QUERY_TAG.USER, QUERY_TAG.COUNT_USER],
    }),
  }),
});

Component.tsx

let promise: any;

const Home = () => {
  const { data } = useGetUsersQuery({
    offset: 0,
    limit: 30,
  });

  const { data: count } = useCountUsersQuery(undefined, {
    pollingInterval: API_TIME_POLLING,
  });

  // Define the columns for the table
  const columns: TableProps<UserEntity>['columns'] = useMemo(
    () => [
      {
        title: '#',
        dataIndex: 'index',
        render: (text, record, index) => index + 1,
        width: 15, // Thiết lập chiều rộng cho cột số thứ tự
        align: 'center',
        fixed: 'left',
      },
      {
        title: 'Email',
        dataIndex: 'email',
        width: 200, // Thiết lập chiều rộng cho cột email
      },
      {
        title: 'Name',
        dataIndex: 'name',
        render: (text, record) => `${record.firstName} ${record.lastName}`,
        width: 150, // Thiết lập chiều rộng cho cột tên
      },
    ],
    []
  );

  const [addUser, { isLoading, error }] = useRegisterUsesMutation();

  const handleGenerateAnUser = useCallback(async () => {
    try {
      const payload: CreateUserDto = {
        email: faker.internet.email(),
        firstName: faker.person.firstName(),
        id: faker.string.uuid(),
        lastName: faker.person.lastName(),
      };

      if (promise) {
        promise.abort();
        promise = null;
      }

      promise = addUser(payload);
      await promise.unwrap();

      console.log('User added:', promise);
    } catch (error) {
      console.error('Failed to add user:', error);
    }
  }, [addUser]);

  const handleAbortQuery = useCallback(() => {
    promise.abort();
    promise = null;
  }, []);

  useEffect(() => {
    return () => {
      if (promise) {
        promise.abort();
        promise = null;
      }
    };
  }, []);

  return (
    <>
      <Button
        type='primary'
        onClick={handleGenerateAnUser}
        // loading={isLoading}
      >
        Generate a user
      </Button>
      <Button
        danger
        disabled={!promise}
        onClick={handleAbortQuery}
      >
        Abort query
      </Button>
      {data && data?.length > 0 && (
        <>
          <Table
            columns={columns}
            dataSource={data}
            rowKey={'id'}
            loading={isLoading}
            size='small'
            sticky
            // pagination={{
            //   defaultPageSize: 5,
            //   pageSizeOptions: [10, 20, 50, 100],
            // }}
            bordered
          />
        </>
      )}
    </>
  );
};

export default Home;

anyone can help me? to optimize it ? like define type for var promise?

markerikson commented 4 months ago

The question is very unclear, and this appears to be A) about Redux Toolkit (not the Redux core library), and B) a usage question. Could you ask this in the "Discussions" section of https://github.com/reduxjs/redux-toolkit instead?

DavidNguyen67 commented 4 months ago

I want to proactively abort a query in a React component when necessary. At the same time, I want to use useEffect to ensure that the query will be canceled when the component is unmounted.

BTW, thank for show me where i can disscus