如何使用Apollo的useMutation实现带动态ID的表单数据更新
问题描述
我有一个GraphQL查询,用于获取表单展示所需的全部输入项,需要在输入框触发onChange事件时,通过同一个mutation来修改数据库。
已经完成查询逻辑并成功渲染所有输入框,现在遇到两个问题:
- 输入数据时,如何重新发送携带新值的mutation?
- 需要传递特定的id,让后端识别出是修改现有文章而非创建新文章。
现有代码文件
form.service.tsx
export const FORM = gql` mutation form($article: ArticleInput!) { form(annonce: $annonce) { article{ id } formContent } } `; export const FormData = ({ children }) => { const [form, { data, loading, error }] = useMutation( form, { variables: { annonce: { idtype: 2, id: 0, // I need this to be dynamic }, }, }, ); useEffect(() => { form().then((res) => { if (res.data) { res.data.form.formContent = JSON.parse( res.data.form.formContent, ); } }); }, [form]); return children(data, loading, error); };
form.tsx
<FormData> {(data, loading) => { if (loading) return <>loading...</>; return ( <> <Section3 dataToDisplay={data.groups} />
section3.tsx
const Section3 = ({ data }) => { const [typeDeBienSelected, setTypeDeBienSelected] = useState<Group>( data.find((item) => item.selected) ?? data[0], ); return ( <div className="hk-flex hk-flex-col hk-gap-8"> <MyInputComponent list={typeDeBien ?? []} value={typeDeBienSelected} setValue={(e) => setTypeDeBienSelected(e)} /> ); }; export default Section3;
解决方案
1. 传递动态文章ID
通过给FormData组件传入articleId props,替换硬编码的id:0,让后端识别要修改的现有文章。
2. 输入变化时触发mutation
将mutation的触发逻辑封装成可复用的函数,传递给子组件,在输入框onChange时调用该函数,携带最新的表单值发送请求。
修改后的代码
form.service.tsx
export const FORM = gql` mutation form($article: ArticleInput!) { form(article: $article) { # 修正变量名与定义一致 article{ id } formContent } } `; export const FormData = ({ articleId, children }) => { const [formMutation, { loading, error }] = useMutation(FORM); const [formState, setFormState] = useState(null); // 初始化加载表单数据 useEffect(() => { const fetchInitialForm = async () => { const res = await formMutation({ variables: { article: { idtype: 2, id: articleId, // 使用传入的动态ID }, }, }); if (res.data) { const parsedContent = JSON.parse(res.data.form.formContent); setFormState(parsedContent); } }; fetchInitialForm(); }, [formMutation, articleId]); // 封装表单更新函数,供子组件调用 const updateForm = async (updatedFields) => { const newFormState = { ...formState, ...updatedFields }; // 发送携带最新值的mutation const res = await formMutation({ variables: { article: { idtype: 2, id: articleId, ...newFormState, }, }, }); // 更新本地状态保持与后端同步 if (res.data) { const parsedContent = JSON.parse(res.data.form.formContent); setFormState(parsedContent); } }; return children({ formData: formState, loading, error, updateForm }); };
form.tsx
<FormData articleId={yourActualArticleId}> {/* 替换为实际的文章ID,比如从路由/父组件传入 */} {({ formData, loading, updateForm }) => { if (loading) return <>loading...</>; return ( <> <Section3 dataToDisplay={formData.groups} updateForm={updateForm} /> </> ); }} </FormData>
section3.tsx
const Section3 = ({ dataToDisplay, updateForm }) => { const [typeDeBienSelected, setTypeDeBienSelected] = useState<Group>( dataToDisplay.find((item) => item.selected) ?? dataToDisplay[0], ); const handleSelectionChange = (selectedItem) => { setTypeDeBienSelected(selectedItem); // 触发mutation更新,字段名根据实际业务调整 updateForm({ typeDeBien: selectedItem }); }; return ( <div className="hk-flex hk-flex-col hk-gap-8"> <MyInputComponent list={dataToDisplay ?? []} value={typeDeBienSelected} setValue={handleSelectionChange} /> </div> ); }; export default Section3;
关键说明
- 动态ID:通过
articleIdprops传入具体的文章ID,mutation调用时携带该ID,后端即可识别是修改操作而非创建。 - 触发时机:在输入框值变化时,先更新本地状态保证UI响应,再调用
updateForm发送mutation,携带最新的表单字段值,同时根据后端返回结果更新本地状态,保持数据一致性。 - 变量名修正:原mutation定义的变量是
$article,调用时对应的参数名需统一为article,避免GraphQL变量不匹配错误。
内容的提问来源于stack exchange,提问作者Johan
相关产品推荐
相关产品推荐

