使用 RTKQ 启用单个变异元素按钮的加载状态

问题描述 投票:0回答:1

我有一个简单的 redux-toolkit 查询实践项目。

我正在名为

apiSlice.js

的文件中处理四个查询
  1. 获取数据“待办事项的对象数组”
  2. 创建数据“todo”
  3. 更新数据
  4. 删除数据“删除待办事项”

目的:我试图在单击删除按钮时处理单个目标待办事项的加载状态,如果我单击待办事项的删除按钮,则该按钮的文本将从“删除”更改为“正在加载...”。

可用的解决方案: *没有给我我想要的

首先:我尝试从

isLoading
解构
useGetTodosQuery()
,但它只适用于获取数据,而不是突变

第二:我在这个link中从redux-toolkit文档中找到了一个解决方案,它解释了如何从突变查询的HOOK中解构

isLoading
,例如删除
useDeleteTodoMutation()
等...... 加载工作高效,但它启用了整个按钮的加载状态

RTKQ 源代码

apiSlice.js

import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'

const API = 'http://localhost:3500'

export const apiSlice = createApi({
  tagTypes: ['Todos'],
  reducerPath: 'todos',
  baseQuery: fetchBaseQuery({ baseUrl: API }),
  endpoints: (builder) =>
  ({
    getTodos: builder.query({
      query: () => '/todos',
      transformResponse: res => res.sort((a, b) => b.id - a.id),
      providesTags: ['Todos']
    }),
    addTodo: builder.mutation({
      query: (todo) => ({
        url: '/todos',
        method: 'POST',
        body: todo
      }),
      invalidatesTags: ['Todos']
    }),
    updateTodo: builder.mutation({
      query: (todo) => ({
        url: `/todos/${todo.id}`,
        method: 'PATCH',
        body: todo
      }),
      invalidatesTags: ['Todos']
    }),
    deleteTodo: builder.mutation({
      query: ({ id }) => ({
        url: `/todos/${id}`,
        method: 'DELETE',
        body: id
      }),
      invalidatesTags: ['Todos']
    })
  })
})

export const { useGetTodosQuery, useAddTodoMutation, useUpdateTodoMutation, useDeleteTodoMutation } = apiSlice

=> 的源代码

TodoList.js

// add imports
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faTrash, faUpload } from '@fortawesome/free-solid-svg-icons'
import { useState } from "react"
import { useAddTodoMutation, useDeleteTodoMutation, useGetTodosQuery, useUpdateTodoMutation } from '../api/apiSlice'
import { nanoid } from '@reduxjs/toolkit'

const TodoList = () => {
    const [newTodo, setNewTodo] = useState('')

    const handleSubmit = (e) => {
        e.preventDefault();
        //addTodo
        addTodo({ id: nanoid, title: newTodo, completed: false })
        setNewTodo('')

    }
    const [load, setLoad] = useState(false)
    const handleDeleting = (e, todo) => {
        deleteTodo(todo)
        console.log(e)
        if (e.target.id == todo.id) setLoad(true)
    }
    console.log('loading', load)
    const { data: todos, isLoading, isSuccess, isError, error } = useGetTodosQuery()
    const [addTodo] = useAddTodoMutation()
    const [updateTodo] = useUpdateTodoMutation()
    const [deleteTodo, { isLoading: isDeleting }] = useDeleteTodoMutation()

    console.log(isDeleting)

    const newItemSection =
        <form onSubmit={handleSubmit}>
            <label htmlFor="new-todo">Enter a new todo item</label>
            <div className="new-todo">
                <input
                    type="text"
                    id="new-todo"
                    value={newTodo}
                    onChange={(e) => setNewTodo(e.target.value)}
                    placeholder="Enter new todo"
                />
            </div>
            <button className="submit">
                <FontAwesomeIcon icon={faUpload} />
            </button>
        </form>


    let content;
    // Define conditional content
    content = JSON.stringify(todos)

    if (isLoading) {
        content = <mark>Loading...</mark>
    } else if (isSuccess) {
        content = todos.map((todo) => (
            <article key={todo?.id}>
                <input type='checkbox' onChange={() => updateTodo({ ...todo, completed: !todo?.completed })} checked={todo?.completed} id={todo?.id} />
                <label htmlFor={todo?.id} >{todo?.title}</label>
                <button id={todo.id} style={{ minWidth: '81.16px' }} onClick={(e) => handleDeleting(e, todo)}>{isDeleting ? 'loading...' : 'delete'}</button>
            </article>
        ))
    }

    return (
        <main>
            <h1>Todo List</h1>
            {newItemSection}
            {content}
        </main>
    )
}
export default TodoList

项目图片

用户界面图像 在此输入图片描述

我的负载 在此输入图片描述

我想要的加载=>我正在删除的绿色,我只想加载状态对其起作用。我没有点击红色,并且我不想在其上启用加载状态 在此输入图片描述

我正在尝试仅为目标待办事项启用加载状态,而不是其他待办事项

注意 我使用

Microsoft's Copilot AI

找到了如下所示的解决方案
import { useDeleteTodoMutation } from '../services/todoService';

function TodoList({ todos }) {
  const [deleteTodo, { isLoading }] = useDeleteTodoMutation();
  const [deletingTodoId, setDeletingTodoId] = useState(null);

  const handleDelete = async (id) => {
    setDeletingTodoId(id);
    if (window.confirm('Are you sure you want to delete this todo?')) {
      try {
        await deleteTodo(id).unwrap();
      } catch (error) {
        console.error('Failed to delete the todo: ', error);
      } finally {
        setDeletingTodoId(null);
      }
    }
  };

  return (
    <div>
      {todos.map((todo) => (
        <div key={todo.id}>
          <p>{todo.text}</p>
          <button 
            onClick={() => handleDelete(todo.id)} 
            disabled={isLoading && deletingTodoId === todo.id}
          >
            {isLoading && deletingTodoId === todo.id ? 'Deleting...' : 'Delete'}
          </button>
        </div>
      ))}
    </div>
  );
}

提前致谢

javascript reactjs redux-toolkit rtk-query
1个回答
0
投票

您可以使用 event.currentTarget.id 获取目标数据 id 或将目标按钮 id 保存在状态中,因此您可以将其与 .map 数据中的 id 进行比较,如果它等于目标按钮的 id 则启用加载,否则不执行任何操作

© www.soinside.com 2019 - 2024. All rights reserved.