二十一、@reduxjs/toolkit/dist/query/react

郁子大约 13 分钟约 3863 字笔记React18ReduxRTKQ李立超

(一) Hello RTKQ

1. src/index.js

import ReactDOM from "react-dom/client";
import App from "./App";
import { Provider } from "react-redux";
import store from "./store";

const root = ReactDOM.createRoot(document.getElementById("root"));

root.render(
  <Provider store={store}>
    <App />
  </Provider>,
);

2. src/App.jsx

import React from "react";
import { useGetStudentsQuery } from "./store/studentApi";

const App = () => {
  // 调用Api钩子函数查询数据,返回一个对象,包括请求过程中相关数据
  const { data, isSuccess, isLoading } = useGetStudentsQuery();
  console.log(data);

  return (
    <div>
      {isLoading && <p>数据加载中...</p>}
      {isSuccess &&
        data.data.map((item) => {
          return (
            <p key={item.id}>
              {item.attributes.name}---
              {item.attributes.gender}---
              {item.attributes.age}---
              {item.attributes.address}
            </p>
          );
        })}
    </div>
  );
};

export default App;

3. src/store/index.js

import { configureStore } from "@reduxjs/toolkit";
import studentApi from "./studentApi";

const store = configureStore({
  reducer: {
    [studentApi.reducerPath]: studentApi.reducer,
  },
  // RTKQ会使用该中间件处理缓存
  middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(studentApi.middleware),
});

export default store;

4. src/store/studentApi.js

import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/dist/query/react";

const studentApi = createApi({
  reducerPath: "studentApi", // Api的标识,不能和其他Api或reducer重复
  baseQuery: fetchBaseQuery({
    baseUrl: "http://localhost:1337/api/",
  }), // 指定查询的基础信息,发送请求使用的工具
  endpoints: (build) => {
    // build是请求的构建器,通过build来设置请求的相关信息
    return {
      getStudents: build.query({
        query: () => {
          return "students";
        }, // 指定请求子路径,和baseUrl拼在一起
      }), // 查询
      updateStudent: build.mutation(), // 修改
    };
  }, // 指定Api中的各种功能,是一个方法,需要一个对象作为返回值
});

/*
  Api对象创建后,会根据各种方法自动生成对应的钩子函数
  钩子函数可用于向服务器发送请求
  命名规则:getStudents --> useGetStudentsQuery()
*/
export const { useGetStudentsQuery } = studentApi;

export default studentApi;

(二)使用 RTKQ 修改学生列表修改逻辑

1. src/index.js

import ReactDOM from "react-dom/client";
import App from "./App";
import { Provider } from "react-redux";
import store from "./store";

const root = ReactDOM.createRoot(document.getElementById("root"));

root.render(
  <Provider store={store}>
    <App />
  </Provider>,
);

2. src/App.jsx

import React from "react";
import StudentList from "./components/StudentList";
import { useGetStudentsQuery } from "./store/studentApi";
import "./App.css";

const App = () => {
  // 调用Api钩子函数查询数据,返回一个对象,包括请求过程中相关数据
  const { data: stu, isSuccess, isLoading } = useGetStudentsQuery();
  console.log(stu);

  return (
    <div className="app">
      {isLoading && <p>数据加载中...</p>}
      {isSuccess && <StudentList stu={stu} />}
    </div>
  );
};

export default App;

3. src/App.css

.app {
  margin: 10px auto;
  background-color: lightcoral;
  width: 90%;
  padding: 20px;
}
table {
  border-collapse: collapse;
  margin: 0 auto;
  width: 100%;
}
tr {
  border: 1px solid #eee;
}
td {
  color: #fff;
  border: 1px solid #eee;
  text-align: center;
  width: 200px;
}
button {
  cursor: pointer;
}

4. src/components/Student/index.js

import React, { useState } from "react";
import StudentForm from "../StudentForm";

const Student = ({
  stu: {
    id,
    attributes: { name, age, gender, address },
  },
  stu,
}) => {
  /*
    props = {
      stu: {
        id: xxx,
        attributes: {
          name,age,gender,address
        }
      }
    }
  */
  const [editing, setEditing] = useState(false);

  const deleteStudent = () => {};

  const cancelEdit = () => {
    setEditing(false);
  };

  return (
    <>
      {!editing && (
        <tr>
          <td>{name}</td>
          <td>{gender}</td>
          <td>{age}</td>
          <td>{address}</td>
          <td>
            <button onClick={deleteStudent}>删除</button>
            <button onClick={() => setEditing(true)}>修改</button>
          </td>
        </tr>
      )}

      {editing && <StudentForm stu={stu} stuId={id} onCancelEdit={cancelEdit} />}

      {/* {loading && (
        <tr>
          <td colSpan={5}>正在删除数据...</td>
        </tr>
      )}
      {error && (
        <tr>
          <td colSpan={5}>删除失败!</td>
        </tr>
      )} */}
    </>
  );
};

export default Student;

5. src/components/StudentForm/index.js

import React, { useEffect, useState } from "react";
import { useGetStudentsByIdQuery } from "../../store/studentApi";
import "./index.css";

const StudentForm = (props) => {
  // StudentForm一加载,自动获取最新的学生数据
  const { data: students, isSuccess } = useGetStudentsByIdQuery(props.stuId);
  console.log(props.stuId, students, isSuccess);

  // 修改逻辑,保证用户点击修改时获取到的表单数据是数据库最新的数据
  const [inputData, setInputData] = useState({
    name: "",
    gender: "男",
    age: 0,
    address: "",
  });
  const { name, gender, age, address } = inputData;

  useEffect(() => {
    if (isSuccess) setInputData(students.attributes);
  }, [isSuccess]);

  const nameChange = (e) => {
    setInputData((pre) => ({ ...pre, name: e.target.value }));
  };
  const genderChange = (e) => {
    setInputData((pre) => ({ ...pre, gender: e.target.value }));
  };
  const ageChange = (e) => {
    setInputData((pre) => ({ ...pre, age: +e.target.value }));
  };
  const addressChange = (e) => {
    setInputData((pre) => ({ ...pre, address: e.target.value }));
  };

  const onSubmitAdd = () => {};
  const onSubmitEdit = () => {};

  return (
    <>
      <tr className="student-form">
        <td>
          <input type="text" value={name} onChange={nameChange} />
        </td>
        <td>
          <select value={gender} onChange={genderChange}>
            <option value="男"></option>
            <option value="女"></option>
          </select>
        </td>
        <td>
          <input type="text" value={age} onChange={ageChange} />
        </td>
        <td>
          <input type="text" value={address} onChange={addressChange} />
        </td>
        <td>
          {props.stu && (
            <>
              <button onClick={() => props.onCancelEdit()}>取消</button>
              <button onClick={onSubmitEdit}>确认</button>
            </>
          )}
          {!props.stu && <button onClick={onSubmitAdd}>添加</button>}
        </td>
      </tr>
      {/* {loading && (
        <tr>
          <td colSpan={5}>添加中...</td>
        </tr>
      )}
      {error && (
        <tr>
          <td colSpan={5}>添加失败!</td>
        </tr>
      )} */}
    </>
  );
};

export default StudentForm;

6. src/components/StudentForm/index.css

.student-form input {
  width: 80px;
}

7. src/components/StudentList/index.js

import React from "react";
import Student from "../Student";
import StudentForm from "../StudentForm";

const StudentList = (props) => {
  return (
    <table>
      <caption>学生列表</caption>
      <thead>
        <tr>
          <th>姓名</th>
          <th>性别</th>
          <th>年龄</th>
          <th>地址</th>
          <th>操作</th>
        </tr>
      </thead>
      <tbody>
        {props.stu.map((stu) => {
          return <Student key={stu.id} stu={stu} />;
        })}
      </tbody>
      <tfoot>{/* <StudentForm /> */}</tfoot>
    </table>
  );
};

export default StudentList;

8. src/store/index.js

import { configureStore } from "@reduxjs/toolkit";
import studentApi from "./studentApi";

const store = configureStore({
  reducer: {
    [studentApi.reducerPath]: studentApi.reducer,
  },
  // RTKQ会使用该中间件处理缓存
  middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(studentApi.middleware),
});

export default store;

9. src/store/studentApi.js

import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/dist/query/react";

const studentApi = createApi({
  reducerPath: "studentApi", // Api的标识,不能喝其他Api或reducer重复
  baseQuery: fetchBaseQuery({
    baseUrl: "http://localhost:1337/api/",
  }), // 指定查询的基础信息,发送请求使用的工具
  endpoints: (build) => {
    // build是请求的构建器,通过build来设置请求的相关信息
    return {
      getStudents: build.query({
        query: () => {
          return "students";
        }, // 指定请求子路径,和baseUrl拼在一起
        transformResponse: (baseQueryReturnValue) => {
          return baseQueryReturnValue.data;
        }, // 转换响应数据的格式
      }), // 查询
      updateStudent: build.mutation(), // 修改
      getStudentsById: build.query({
        query: (id) => {
          return `students/${id}`;
        },
        transformResponse: (baseQueryReturnValue) => {
          return baseQueryReturnValue.data;
        },
      }),
    };
  }, // 指定Api中的各种功能,是一个方法,需要一个对象作为返回值
});

export const { useGetStudentsQuery, useGetStudentsByIdQuery } = studentApi;

export default studentApi;

(三)useQuery 的参数

1.useGetStudentsQuery(num)

1)currentData: undefined;

  • 当前参数的最新数据,大多数情况下 === data
  • 参数变化又没收到新 data 时为 undefined ,可以通过此判断是否显示 loading 动画

2)data: undefined;

  • 最新的数据

3)isError: false;

  • 布尔值,请求是否有错误

4)error: Error()

  • 对象,有错误时才存在

5)isFetching: true;

  • 布尔值,数据是否正在加载

6)isLoading: true;

  • 布尔值,数据是否第一次加载,调用 refetch 后不会变化

7)isSuccess: false;

  • 布尔值,请求是否成功

8)isUninitialized: false;

  • 布尔值,请求是否还没有开始发送

9)refetch: ƒ();

  • 函数,用来重新加载数据

10) status: "pending";

  • 字符串,请求的状态

2.useQuery 可以接收一个对象作为第二个参数,对请求进行配置

1)selectFromResult

  • 指定 useQuery 返回的结果

2)pollingInterval

  • 设置轮询的间隔,单位毫秒,为 0 表示不轮询
  • 隔段时间发个请求,适于数据时效性较强

3)skip

  • 是否跳过当前请求,默认为 false
  • 例: StudentForm 加载时获取数据

4)refetchOnMountOrArgChange

  • 设置是否每次都重新加载数据
    • 例: StudentForm 加载时获取数据
  • 布尔值:表示是否正常使用数据的缓存
  • 数值:表示数据缓存的有效期,单位秒
    • 组件卸载后 x 秒内如果新数据回来则无需重新加载,否则再发请求

5)refetchOnFocus

  • 是否在重新获取焦点时重载数据
  • 需要 store 设置 setupListener

6)refetchOnReconnect

  • 网络断开重连时是否重新加载数据

3. src/App.jsx

import React from "react";
import StudentList from "./components/StudentList";
import { useGetStudentsQuery } from "./store/studentApi";
import "./App.css";

let num = 0;

const App = () => {
  // const result = useGetStudentsQuery(num);
  // console.log(result, result.currentData === result.data);

  const result = useGetStudentsQuery(null, {
    // selectFromResult: (res) => {
    //   if (res.data) {
    //     res.data = res.data.filter((item) => item.attributes.age < 18);
    //   }
    //   return res;
    // },
    pollingInterval: 0,
    skip: false,
    refetchOnMountOrArgChange: 2,
    refetchOnFocus: true,
    refetchOnReconnect: true,
  });

  // 调用Api钩子函数查询数据,返回一个对象,包括请求过程中相关数据
  const { data: stu, isSuccess, isLoading, refetch } = result;
  // console.log(stu);

  return (
    <div className="app">
      <button onClick={() => refetch()}>刷新</button>
      <button onClick={() => num++}>修改num</button>
      {isLoading && <p>数据加载中...</p>}
      {isSuccess && <StudentList stu={stu} />}
    </div>
  );
};

export default App;

4. src/components/StudentForm/index.js

import React, { useEffect, useState } from "react";
import { useGetStudentsByIdQuery } from "../../store/studentApi";
import "./index.css";

const StudentForm = (props) => {
  // StudentForm一加载,自动获取最新的学生数据
  const { data: students, isSuccess } = useGetStudentsByIdQuery(props.stuId, {
    skip: !props.stuId,
    refetchOnMountOrArgChange: true,
  });
  console.log(props.stuId, students, isSuccess);

  // 修改逻辑,保证用户点击修改时获取到的表单数据是数据库最新的数据
  const [inputData, setInputData] = useState({
    name: "",
    gender: "男",
    age: 0,
    address: "",
  });
  const { name, gender, age, address } = inputData;

  useEffect(() => {
    if (isSuccess) setInputData(students.attributes);
  }, [isSuccess]);

  const nameChange = (e) => {
    setInputData((pre) => ({ ...pre, name: e.target.value }));
  };
  const genderChange = (e) => {
    setInputData((pre) => ({ ...pre, gender: e.target.value }));
  };
  const ageChange = (e) => {
    setInputData((pre) => ({ ...pre, age: +e.target.value }));
  };
  const addressChange = (e) => {
    setInputData((pre) => ({ ...pre, address: e.target.value }));
  };

  const onSubmitAdd = () => {};
  const onSubmitEdit = () => {};

  return (
    <>
      <tr className="student-form">
        <td>
          <input type="text" value={name} onChange={nameChange} />
        </td>
        <td>
          <select value={gender} onChange={genderChange}>
            <option value="男"></option>
            <option value="女"></option>
          </select>
        </td>
        <td>
          <input type="text" value={age} onChange={ageChange} />
        </td>
        <td>
          <input type="text" value={address} onChange={addressChange} />
        </td>
        <td>
          {props.stu && (
            <>
              <button onClick={() => props.onCancelEdit()}>取消</button>
              <button onClick={onSubmitEdit}>确认</button>
            </>
          )}
          {!props.stu && <button onClick={onSubmitAdd}>添加</button>}
        </td>
      </tr>
      {/* {loading && (
        <tr>
          <td colSpan={5}>添加中...</td>
        </tr>
      )}
      {error && (
        <tr>
          <td colSpan={5}>添加失败!</td>
        </tr>
      )} */}
    </>
  );
};

export default StudentForm;

5. src/store/index.js

import { configureStore } from "@reduxjs/toolkit";
import { setupListeners } from "@reduxjs/toolkit/query";
import studentApi from "./studentApi";

const store = configureStore({
  reducer: {
    [studentApi.reducerPath]: studentApi.reducer,
  },
  // RTKQ会使用该中间件处理缓存
  middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(studentApi.middleware),
});

// 设置后,RTKQ将会支持设置refetchOnFocus和refetchOnReconnect属性
setupListeners(store.dispatch);

export default store;

6. src/store/studentApi.js

import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/dist/query/react";

const studentApi = createApi({
  reducerPath: "studentApi", // Api的标识,不能喝其他Api或reducer重复
  baseQuery: fetchBaseQuery({
    baseUrl: "http://localhost:1337/api/",
  }), // 指定查询的基础信息,发送请求使用的工具
  endpoints: (build) => {
    // build是请求的构建器,通过build来设置请求的相关信息
    return {
      getStudents: build.query({
        query: () => {
          return "students";
        }, // 指定请求子路径,和baseUrl拼在一起
        transformResponse: (baseQueryReturnValue) => {
          return baseQueryReturnValue.data;
        }, // 转换响应数据的格式
      }), // 查询
      updateStudent: build.mutation(), // 修改
      getStudentsById: build.query({
        query: (id) => {
          return `students/${id}`;
        },
        transformResponse: (baseQueryReturnValue) => {
          return baseQueryReturnValue.data;
        },
        keepUnusedDataFor: 60, //设置数据缓存的时间,单位秒,默认60
      }),
    };
  }, // 指定Api中的各种功能,是一个方法,需要一个对象作为返回值
});

export const { useGetStudentsQuery, useGetStudentsByIdQuery } = studentApi;

export default studentApi;

(四)删除数据

1. src/App.jsx

import React from "react";
import StudentList from "./components/StudentList";
import { useGetStudentsQuery } from "./store/studentApi";
import "./App.css";

const App = () => {
  // 调用Api钩子函数查询数据,返回一个对象,包括请求过程中相关数据
  const { data: stu, isSuccess, isLoading, refetch } = useGetStudentsQuery();
  // console.log(stu);

  return (
    <div className="app">
      {isLoading && <p>数据加载中...</p>}
      {isSuccess && <StudentList stu={stu} />}
    </div>
  );
};

export default App;

2. src/store/studentApi.js

import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/dist/query/react";

/*
  https://www.lilichao.com/index.php/2022/05/27/rtk-query/
  createApi() 创建Api对象
    RTK Query的所有功能都需要通过该对象来进行
    需要一个配置对象作为参数
*/
const studentApi = createApi({
  reducerPath: "studentApi", // Api的标识,不能喝其他Api或reducer重复
  baseQuery: fetchBaseQuery({
    baseUrl: "http://localhost:1337/api/",
  }), // 指定查询的基础信息,发送请求使用的工具
  endpoints: (build) => {
    // build是请求的构建器,通过build来设置请求的相关信息
    return {
      getStudents: build.query({
        query: () => {
          return "students";
        }, // 指定请求子路径,和baseUrl拼在一起
        transformResponse: (baseQueryReturnValue) => {
          return baseQueryReturnValue.data;
        }, // 转换响应数据的格式
      }), // 查询
      getStudentsById: build.query({
        query: (id) => {
          return `students/${id}`;
        },
        transformResponse: (baseQueryReturnValue) => {
          return baseQueryReturnValue.data;
        },
        keepUnusedDataFor: 60, //设置数据缓存的时间,单位秒,默认60
      }),
      deleteStudent: build.mutation({
        query: (id) => {
          // 如果发送的不是get请求,需要返回一个对象来设置请求信息
          return {
            url: `students/${id}`,
            method: "delete",
          };
        },
      }), // 修改
    };
  }, // 指定Api中的各种功能,是一个方法,需要一个对象作为返回值
});

/*
  Api对象创建后,会根据各种方法自动生成对应的钩子函数
  钩子函数可用于向服务器发送请求
  命名规则:getStudents --> useGetStudentsQuery()
*/
export const { useGetStudentsQuery, useGetStudentsByIdQuery, useDeleteStudentMutation } = studentApi;

export default studentApi;

3. src/components/Student/index.js

import React, { useState } from "react";
import { useDeleteStudentMutation } from "../../store/studentApi";
import StudentForm from "../StudentForm";

const Student = ({
  stu: {
    id,
    attributes: { name, age, gender, address },
  },
  stu,
}) => {
  /*
    props = {
      stu: {
        id: xxx,
        attributes: {
          name,age,gender,address
        }
      }
    }
  */
  const [editing, setEditing] = useState(false);

  /*
    获取删除的钩子,useMutation的钩子返回的是一个数组
    参数1:操作的触发器
    参数2:结果集
  */
  const [delStudent, { isSuccess }] = useDeleteStudentMutation();
  console.log(isSuccess);
  const deleteStudent = () => {
    delStudent(id);
  };

  const cancelEdit = () => {
    setEditing(false);
  };

  return (
    <>
      {!editing && !isSuccess && (
        <tr>
          <td>{name}</td>
          <td>{gender}</td>
          <td>{age}</td>
          <td>{address}</td>
          <td>
            <button onClick={deleteStudent}>删除</button>
            <button onClick={() => setEditing(true)}>修改</button>
          </td>
        </tr>
      )}

      {isSuccess && (
        <tr>
          <td colSpan={5}>数据已删除!</td>
        </tr>
      )}

      {editing && <StudentForm stu={stu} stuId={id} onCancelEdit={cancelEdit} />}

      {/* {loading && (
        <tr>
          <td colSpan={5}>正在删除数据...</td>
        </tr>
      )}
      {error && (
        <tr>
          <td colSpan={5}>删除失败!</td>
        </tr>
      )} */}
    </>
  );
};

export default Student;

(五)添加和修改数据

1. src/store/studentApi.js

import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/dist/query/react";

/*
  https://www.lilichao.com/index.php/2022/05/27/rtk-query/
  createApi() 创建Api对象
    RTK Query的所有功能都需要通过该对象来进行
    需要一个配置对象作为参数
*/
const studentApi = createApi({
  reducerPath: "studentApi", // Api的标识,不能喝其他Api或reducer重复
  baseQuery: fetchBaseQuery({
    baseUrl: "http://localhost:1337/api/",
  }), // 指定查询的基础信息,发送请求使用的工具
  endpoints: (build) => {
    // build是请求的构建器,通过build来设置请求的相关信息
    return {
      getStudents: build.query({
        query: () => {
          return "students";
        }, // 指定请求子路径,和baseUrl拼在一起
        transformResponse: (baseQueryReturnValue) => {
          return baseQueryReturnValue.data;
        }, // 转换响应数据的格式
      }), // 查询
      getStudentsById: build.query({
        query: (id) => {
          return `students/${id}`;
        },
        transformResponse: (baseQueryReturnValue) => {
          return baseQueryReturnValue.data;
        },
        keepUnusedDataFor: 60, //设置数据缓存的时间,单位秒,默认60
      }),
      deleteStudent: build.mutation({
        query: (id) => {
          // 如果发送的不是get请求,需要返回一个对象来设置请求信息
          return {
            url: `students/${id}`,
            method: "delete",
          };
        },
      }), // 修改
      addStudents: build.mutation({
        query: (stu) => {
          return {
            url: "students",
            method: "post",
            body: {
              data: stu,
            },
          };
        },
      }),
      updateStudent: build.mutation({
        query: (stu) => {
          return {
            url: `students/${stu.id}`,
            method: "put",
            body: {
              data: stu.attributes,
            },
          };
        },
      }),
    };
  }, // 指定Api中的各种功能,是一个方法,需要一个对象作为返回值
});

/*
  Api对象创建后,会根据各种方法自动生成对应的钩子函数
  钩子函数可用于向服务器发送请求
  命名规则:getStudents --> useGetStudentsQuery()
*/
export const { useGetStudentsQuery, useGetStudentsByIdQuery, useDeleteStudentMutation, useAddStudentsMutation, useUpdateStudentMutation } =
  studentApi;

export default studentApi;

2. src/components/StudentForm/index.js

import React, { useEffect, useState } from "react";
import { useAddStudentsMutation, useGetStudentsByIdQuery, useUpdateStudentMutation } from "../../store/studentApi";
import "./index.css";

const StudentForm = (props) => {
  // StudentForm一加载,自动获取最新的学生数据
  const { data: students, isSuccess: isGetSuccess } = useGetStudentsByIdQuery(props.stuId, {
    skip: !props.stuId,
    refetchOnMountOrArgChange: true,
  });
  useEffect(() => {
    if (isGetSuccess) setInputData(students.attributes);
  }, [isGetSuccess]);

  // 修改逻辑,保证用户点击修改时获取到的表单数据是数据库最新的数据
  const [inputData, setInputData] = useState({
    name: "",
    gender: "男",
    age: 0,
    address: "",
  });
  const { name, gender, age, address } = inputData;
  const nameChange = (e) => {
    setInputData((pre) => ({ ...pre, name: e.target.value }));
  };
  const genderChange = (e) => {
    setInputData((pre) => ({ ...pre, gender: e.target.value }));
  };
  const ageChange = (e) => {
    setInputData((pre) => ({ ...pre, age: +e.target.value }));
  };
  const addressChange = (e) => {
    setInputData((pre) => ({ ...pre, address: e.target.value }));
  };

  const [addStudent, { isSuccess: isAddSuccess }] = useAddStudentsMutation();
  const onSubmitAdd = () => {
    addStudent(inputData);
    setInputData({
      name: "",
      gender: "男",
      age: 0,
      address: "",
    });
  };

  const [editStudent, { isSuccess: isEditSuccess }] = useUpdateStudentMutation();
  const onSubmitEdit = () => {
    editStudent({
      id: props.stuId,
      attributes: inputData,
    });
    props.onCancelEdit();
  };

  return (
    <>
      <tr className="student-form">
        <td>
          <input type="text" value={name} onChange={nameChange} />
        </td>
        <td>
          <select value={gender} onChange={genderChange}>
            <option value="男"></option>
            <option value="女"></option>
          </select>
        </td>
        <td>
          <input type="text" value={age} onChange={ageChange} />
        </td>
        <td>
          <input type="text" value={address} onChange={addressChange} />
        </td>
        <td>
          {props.stu && (
            <>
              <button onClick={() => props.onCancelEdit()}>取消</button>
              <button onClick={onSubmitEdit}>确认</button>
            </>
          )}
          {!props.stu && <button onClick={onSubmitAdd}>添加</button>}
        </td>
      </tr>
      {/* {loading && (
        <tr>
          <td colSpan={5}>添加中...</td>
        </tr>
      )}
      {error && (
        <tr>
          <td colSpan={5}>添加失败!</td>
        </tr>
      )} */}
    </>
  );
};

export default StudentForm;

(六)数据标签

1. src/store/studentApi.js

import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/dist/query/react";

/*
  https://www.lilichao.com/index.php/2022/05/27/rtk-query/
  createApi() 创建Api对象
    RTK Query的所有功能都需要通过该对象来进行
    需要一个配置对象作为参数
*/
const studentApi = createApi({
  reducerPath: "studentApi", // Api的标识,不能喝其他Api或reducer重复
  baseQuery: fetchBaseQuery({
    baseUrl: "http://localhost:1337/api/",
  }), // 指定查询的基础信息,发送请求使用的工具
  tagTypes: ["student"], // 指定Api中的标签类型
  endpoints: (build) => {
    // build是请求的构建器,通过build来设置请求的相关信息
    return {
      getStudents: build.query({
        query: () => {
          return "students";
        }, // 指定请求子路径,和baseUrl拼在一起
        transformResponse: (baseQueryReturnValue) => {
          return baseQueryReturnValue.data;
        }, // 转换响应数据的格式
        // providesTags: ["student"], // 为当前方法打标签,当标签失效时会重新执行当前方法
        providesTags: [
          {
            type: "student",
            id: "LIST",
          },
        ],
      }), // 查询
      getStudentsById: build.query({
        query: (id) => {
          return `students/${id}`;
        },
        transformResponse: (baseQueryReturnValue) => {
          return baseQueryReturnValue.data;
        },
        keepUnusedDataFor: 60, //设置数据缓存的时间,单位秒,默认60
        providesTags: (result, error, id) => [
          {
            type: "student",
            id,
          },
        ], // 只有当前id变化时才打标签
      }),
      deleteStudent: build.mutation({
        query: (id) => {
          // 如果发送的不是get请求,需要返回一个对象来设置请求信息
          return {
            url: `students/${id}`,
            method: "delete",
          };
        },
        invalidatesTags: ["student"], // 令标签失效
      }), // 修改
      addStudents: build.mutation({
        query: (stu) => {
          return {
            url: "students",
            method: "post",
            body: {
              data: stu,
            },
          };
        },
        // invalidatesTags: ["student"], // 令标签失效【全部该标签都失效】
        invalidatesTags: [
          {
            type: "student",
            id: "LIST",
          },
        ], // 只有id为LIST的student标签失效,重新执行带有id为LIST的student标签的方法
      }),
      updateStudent: build.mutation({
        query: (stu) => {
          return {
            url: `students/${stu.id}`,
            method: "put",
            body: {
              data: stu.attributes,
            },
          };
        },
        invalidatesTags: (result, error, stu) => [
          {
            type: "student",
            id: stu.id,
          },
          {
            type: "student",
            id: "LIST",
          },
        ], // 令标签失效
      }),
    };
  }, // 指定Api中的各种功能,是一个方法,需要一个对象作为返回值
});

/*
  Api对象创建后,会根据各种方法自动生成对应的钩子函数
  钩子函数可用于向服务器发送请求
  命名规则:getStudents --> useGetStudentsQuery()
*/
export const { useGetStudentsQuery, useGetStudentsByIdQuery, useDeleteStudentMutation, useAddStudentsMutation, useUpdateStudentMutation } =
  studentApi;

export default studentApi;
上次编辑于: