在React-Query中从父组件触发多个mutation的实现方法问询
解决方案:在React Query中实现单个/批量保存条目
方法一:提升mutation实例到父组件(推荐)
这种方式遵循React数据流设计,父组件统一管理所有条目的mutation实例,既能支持单个条目独立保存,也能批量触发所有保存操作,同时保留每个条目独立的状态反馈(加载、成功、失败)。
修改Form.js
import * as React from "react"; import { Person } from "./Person"; import { useMutation } from "react-query"; export const Form = () => { const people = [ { id: 1, name: "John Doe", age: 37 }, { id: 2, name: "Jack Johnson", age: 45 }, { id: 3, name: "Jimmie Jones", age: 23 } ]; // 为每个人员创建mutation实例并缓存 const personMutations = React.useMemo(() => { return people.map(person => ({ ...person, mutation: useMutation({ mutationKey: ["Create_Person", person.id], mutationFn: () => new Promise((resolve) => setTimeout(resolve, 3000)) }) })); }, [people]); const saveAll = () => { // 批量触发所有mutation personMutations.forEach(({ mutation }) => { mutation.mutate(); }); }; return ( <div> {personMutations.map((person) => ( <Person key={person.id} {...person} mutate={person.mutation.mutate} status={person.mutation.status} /> ))} <hr /> <button onClick={saveAll}>Save all</button> </div> ); };
修改Person.js
import * as React from "react"; export const Person = (props) => { const { mutate, status, name, age } = props; return ( <div> {status === "loading" && <span>Saving...</span>} {status === "success" && <span>Success</span>} {status === "error" && ( <button onClick={mutate} style={{ marginRight: 12 }}> Retry </button> )} {status === "idle" && ( <button onClick={mutate} style={{ marginRight: 12 }}> Create Person </button> )} <input value={name} disabled={status === "loading"} /> <input value={age} disabled={status === "loading"} /> </div> ); };
复用mutation配置(可选)
如果需要复用mutation逻辑,可以把配置抽成函数:
export const getPersonMutationConfig = (id) => ({ mutationKey: ["Create_Person", id], mutationFn: () => new Promise((resolve) => setTimeout(resolve, 3000)) });
在Form.js中使用:mutation: useMutation(getPersonMutationConfig(person.id))
方法二:通过MutationCache触发外部mutation
如果不想调整原有组件结构,可以借助React Query的MutationCache,通过mutationKey定位到子组件内的mutation实例并触发。
修改Form.js
import * as React from "react"; import { Person } from "./Person"; import { useQueryClient } from "react-query"; export const Form = () => { const people = [ { id: 1, name: "John Doe", age: 37 }, { id: 2, name: "Jack Johnson", age: 45 }, { id: 3, name: "Jimmie Jones", age: 23 } ]; const queryClient = useQueryClient(); const saveAll = () => { people.forEach(person => { // 通过mutationKey查找对应的mutation实例 const mutation = queryClient.getMutationCache().getMutation(["Create_Person", person.id]); if (mutation) { mutation.mutate(); } }); }; return ( <div> {people.map((person) => ( <Person key={person.id} {...person} /> ))} <hr /> <button onClick={saveAll}>Save all</button> </div> ); };
这种方式无需修改Person组件和原有的useCreatePersonMutation,但依赖React Query内部缓存机制,灵活性稍弱,适合组件结构不便大幅改动的场景。
额外优化建议
- 输入状态管理:当前输入框为只读状态,实际项目中需要将输入值存入组件状态,保存时传递给mutation:
// 在Person组件中(方法一场景) const [name, setName] = React.useState(props.name); const [age, setAge] = React.useState(props.age); // 调整mutationFn接收参数 mutationFn: (data) => new Promise(resolve => setTimeout(() => resolve(data), 3000)) // 触发时传递数据:mutate({ name, age, id: props.id }) - 批量保存全局状态:可以通过
Promise.all监听所有批量保存的完成状态,添加全局加载提示:const [isSavingAll, setIsSavingAll] = React.useState(false); const saveAll = async () => { setIsSavingAll(true); try { await Promise.all( personMutations.map(({ mutation }) => mutation.mutateAsync()) ); // 批量保存成功逻辑 } catch (error) { // 批量保存失败逻辑 } finally { setIsSavingAll(false); } };
内容的提问来源于stack exchange,提问作者Stephan Olsen
相关产品推荐
相关产品推荐

