使用GraphQL查询更新反应状态

时间:2020-01-06 00:44:58

标签: reactjs graphql react-hooks apollo react-apollo

我正在尝试使用从GraphQL查询收集的数据更新状态。 我已经尝试过与https://www.apollographql.com/docs/react/data/queries/上的官方教程类似,标题为“手动执行查询”。

export default function SearchField() {
    const [
        searchInput,
        setSearchInput
    ] = useState('');
    const [
        drinks,
        setDrinks
    ] = useState(null);

    const handleSubmit = (e) => {
        e.preventDefault();
        getDrinks({ variables: { cocktailName: searchInput } });
    };

    const [
        getDrinks,
        { loading, data }
    ] = useLazyQuery(MULTIPLE_COCKTAILS_BY_NAME_QUERY);

    if (loading)
        return (
            <div className="justify-content-center">
                <p>Loading ...</p>
            </div>
        );

    if (data && data.multipleCocktailsByName) {
        setDrinks(data.multipleCocktailsByName);
    }

    return (...)

返回前的最后一部分使组件崩溃,并显示“错误:重新渲染太多。React限制了渲染次数以防止无限循环。”如果我改为尝试像这样更新handleSubmit中的状态:

const handleSubmit = (e) => {
        e.preventDefault();
        getDrinks({ variables: { cocktailName: searchInput } });
        setDrinks(data.multipleCocktailsByName);
    };

然后出现错误“无法读取未定义的属性'multipleCocktailsByName'”。我仍然设法从查询中有条件地呈现数据,但是处理状态很麻烦。我真的很感谢帮助此工作。

2 个答案:

答案 0 :(得分:0)

在:

 if (data && data.multipleCocktailsByName) {
        setDrinks(data.multipleCocktailsByName);
 }

成功运行查询并填充数据后,您将陷入无限循环,将酒水设定为该值。

您可以仅将数据用作组件状态(不用喝酒),然后执行以下操作:

if (loading) { ... } // render loading UI
if (error) { ... } // I suggest adding this so you can better debug.
if (data) { ... } // do what you intended to do with drinks but calling data.multipleCocktailsByName.

或者,您可以在“数据”上使用useEffect钩子来设置饮料状态,但这似乎是不必要的。

我应该补充,您的第二个示例失败,因为调用是异步的,因此调用后数据不会立即达到预期。这就是为什么,如果您想拥有一种饮料状态,则可以使用诸如以下的使用效果钩子:

useEffect(() => {
   if (data && data.multipleCocktailsByName) {
   setDrinks(data.multipleCocktailsByName
   }
},[data, setDrinks])

然后仅在数据更改并包含一个值时设置饮料。

答案 1 :(得分:-1)

当前组件的问题是if语句(在return之前)将满足条件并更新每个渲染器的状态(一旦提交表单并{{1} }已执行-如useQuery中现在有值)。

由于无论如何都是延迟加载数据,因此在提交表单时只需要更新组件的状态。将data语句移至if函数应该可以解决您的问题,并且不需要任何副作用(handleSubmit)。

我在useEffect函数上使用了async/await,以确保查询在状态更新之前已经完成。

handleSubmit

有些事情需要考虑,您是否真的需要export default function SearchField() { const [ searchInput, setSearchInput ] = useState(''); const [ drinks, setDrinks ] = useState(null); const [ getDrinks, { loading, data } ] = useLazyQuery(MULTIPLE_COCKTAILS_BY_NAME_QUERY); const handleSubmit = async (e) => { e.preventDefault(); await getDrinks({ variables: { cocktailName: searchInput } }); if (data && data.multipleCocktailsByName) { setDrinks(data.multipleCocktailsByName); } }; if (loading) return ( <div className="justify-content-center"> <p>Loading ...</p> </div> ); return (...) 状态变量?如果您查看Apollo的drinksuseQuery示例,您会注意到它们通常只在return语句的JSX中直接使用useLazyQuery变量。

通常这涉及一些条件渲染,尽管这在react组件中很常见。如果您没有在return语句之外的任何地方都未使用data,请考虑进行重构以进行drinks调用,并保存一两个重新渲染。