【问题标题】:What is the best way to mutate remote data fetched with useQuery改变使用 useQuery 获取的远程数据的最佳方法是什么
【发布时间】:2020-03-23 19:18:30
【问题描述】:

我对 graphQL 和 Apollo 还很陌生。我希望我能说清楚:

我正在使用 apollo/react-hook useQuery 获取数据。之后我用数据填充一个表单,以便客户端可以更改它。完成后,数据会使用useMutation 发送回服务器。

到目前为止,我使用onCompleted 将获取的数据存储在组件状态中。看起来像这样:

import React, { useState } from 'react';
import { TextField } from '@material-ui/core'; 
const Index = () => {
    const [state, setState] = useState(null)
    const {data, loading, error} = useQuery<typeof queryType>(query, {
        onCompleted: data => {
            // modify data slightly
            setState(data)
        }
    })

    return (
        <TextField value={state} onChange={() => setState(event.target.value)}/>
    )
}

表单使用存储在组件状态中的值,表单处理程序使用setState 改变它。

我现在的问题是,这是否是最佳做法以及是否需要将获取的数据存储在本地组件状态中。

【问题讨论】:

  • 您的代码对我来说看起来不错。这是必要的,因为起初state 为空。如果您不setState,您将无法更新视图,因此您的表单不会被更新。
  • 我确实需要一个本地状态,还是使用 apollos 本地状态也会触发重新渲染?在实际应用中,我有几个下拉菜单。
  • 对不起,我不熟悉阿波罗。但是既然你说 apollos 已经有相同数据的状态,你不应该创建自己的状态。对于一组数据,您应该只有一个状态。如果 apollos 处理状态,那么对你有好处!
  • 好吧,我用一个大大的问号说了出来。我认为它不像功能组件状态(?)。
  • Apollo 公开的data 属性是代表远程数据的全局状态。虽然有办法改变它,但在用户表单的上下文中这样做是没有意义的。即使它是基于其他状态初始化的,表单的状态也只代表用户的输入。如果我们只是渲染数据,那么使用组件状态将是多余的。但这里不是这样。

标签: reactjs graphql react-apollo


【解决方案1】:

因为您不想只获取和呈现数据——您希望能够在表单值更改时对其进行变异——我们不能按原样使用data。除非您使用 uncontrolled inputs 和 refs 来管理您的表单(您可能是 shouldn't do),否则您将需要使用一些组件状态。

我认为您目前的方法大部分都很好。最大的缺点是,如果查询需要一段时间(可能用户的互联网连接不稳定),他们有一个窗口可以开始填写表单,但一旦查询完成,他们的输入就会被覆盖。您必须明确禁用输入或隐藏表单,直到加载完成才能防止出现这种情况。

另一种方法是将组件分成两部分:

const Outer = () => {
  const {data, loading, error} = useQuery(query)

  if (!data) {
    return null // or a loading indicator, etc.
  }

  return <Inner data={data}/>
}

const Inner = ({ data }) => {
  const [value, setValue] = useState(data.someField)

  <TextField value={value} onChange={() => setValue(event.target.value)}/>
}

通过在加载完成之前不渲染内部组件,我们确保我们传递给它的初始道具具有来自查询的数据。然后我们可以使用这些道具来初始化我们的状态。

【讨论】:

  • 感谢您的回答。在我的实际应用程序中,我已经通过加载组件处理了这一点。
  • @MartinSchmelzer 加载组件实在是离题了。关键是您正在利用状态的初始化方式。对于单个组件(不使用useEffect),上述情况是不可能的,因为只有第一组道具用于初始化状态。
【解决方案2】:

好像useQuery 只有responseId 的状态:https://github.com/trojanowski/react-apollo-hooks/blob/master/src/useQuery.ts

但是你也可以从useQuery 获得一个refetch 函数。

 const { loading, error, data, refetch } = useQuery(...);

在您使用useMutation() 更新数据后,尝试调用refetch()。它不应该触发重新渲染。出于这个原因,您可能必须设置自己的状态。 可能是这样的:

const handleUpdate = () =>{
   setData(refetch());
}

或者您在使用useMutation 后获取数据,该状态也处于:https://github.com/trojanowski/react-apollo-hooks/blob/master/src/useMutation.ts

  const [update, { data }] = useMutation(UPDATE_DATA);

data 将始终是最新值,因此您也可以这样做:

useEffect(()=>{
 setData(data);
 // OR
 // setData(refetch());
}, [data])

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-25
    • 2010-09-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多