是否可以防止在组件状态更改/重新呈现时重新获取“useLazyQuery”查询?
Is it possible to prevent `useLazyQuery` queries from being re-fetched on component state change / re-render?
目前我有一个 useLazyQuery
钩子,它在按下按钮(搜索表单的一部分)时触发。
挂钩正常运行,仅在按下按钮时触发。但是,一旦我触发它一次,它就会在每次组件重新呈现时触发(通常是由于状态更改)。
因此,如果我搜索一次,然后编辑搜索字段,结果会立即出现,我不必再次点击搜索按钮。
不是我想要的 UI,如果您完全删除搜索文本(因为它试图使用 null
作为变量进行搜索),它会导致错误,有什么方法可以防止useLazyQuery
在重新渲染时被重新获取?
这可以通过使用 useQuery
解决,具体取决于 'searching' 状态,当我单击按钮时该状态会打开。但是我宁愿看看我是否可以避免增加组件的复杂性。
const AddCardSidebar = props => {
const [searching, toggleSearching] = useState(false);
const [searchParams, setSearchParams] = useState({
name: ''
});
const [searchResults, setSearchResults] = useState([]);
const [selectedCard, setSelectedCard] = useState();
const [searchCardsQuery, searchCardsQueryResponse] = useLazyQuery(SEARCH_CARDS, {
variables: { searchParams },
onCompleted() {
setSearchResults(searchCardsQueryResponse.data.searchCards.cards);
}
});
...
return (
<div>
<h1>AddCardSidebar</h1>
<div>
{searchResults.length !== 0 &&
searchResults.map(result => {
return (
<img
key={result.scryfall_id}
src={result.image_uris.small}
alt={result.name}
onClick={() => setSelectedCard(result.scryfall_id)}
/>
);
})}
</div>
<form>
...
<button type='button' onClick={() => searchCardsQuery()}>
Search
</button>
</form>
...
</div>
);
};
react-apollo
文档没有提到 useLazyQuery
是否应该在变量更改时继续触发查询,但是他们确实建议在您想要手动触发时使用 useApolloClient
挂钩一个问题。他们 have an example 匹配此用例(单击按钮触发查询)。
function DelayedQuery() {
const [dog, setDog] = useState(null);
const client = useApolloClient();
return (
<div>
{dog && <img src={dog.displayImage} />}
<button
onClick={async () => {
const { data } = await client.query({
query: GET_DOG_PHOTO,
variables: { breed: 'bulldog' },
});
setDog(data.dog);
}}
>
Click me!
</button>
</div>
);
}
您不必将 async
与 apollo 客户端一起使用(您可以,它有效)。但是如果你想使用 useLazyQuery
你只需要在 onClick
上传递变量而不是直接在 useLazyQuery 调用上传递变量。
对于上面的例子,解决方案是:
function DelayedQuery() {
const [dog, setDog] = useState(null);
const [getDogPhoto] = useLazyQuery(GET_DOG_PHOTO, {
onCompleted: data => setDog(data.dog)
})
return (
<div>
{dog && <img src={dog.displayImage} />}
<button
onClick={() => getDogPhoto({ variables: { breed: 'bulldog' }})}
>
Click me!
</button>
</div>
);
}
Apollo Client 文档对此没有明确说明,但 useLazyQuery 与 useQuery 一样,首先从缓存中获取。如果查询之间没有变化,则不会使用网络调用重新获取。为了每次都进行网络呼叫,您可以根据您的使用情况将 fetchPolicy
更改为 network-only
或 cache-and-network
(documentation link to the fetchPolicy options)。因此,在您的示例中将 fetchPolicy 更改为 network-only
,它看起来像这样:
const AddCardSidebar = props => {
const [searching, toggleSearching] = useState(false);
const [searchParams, setSearchParams] = useState({
name: ''
});
const [searchResults, setSearchResults] = useState([]);
const [selectedCard, setSelectedCard] = useState();
const [searchCardsQuery, searchCardsQueryResponse] =
useLazyQuery(SEARCH_CARDS, {
variables: { searchParams },
fetchPolicy: 'network-only', //<-- only makes network requests
onCompleted() {
setSearchResults(searchCardsQueryResponse.data.searchCards.cards);
}
});
...
return (
<div>
<h1>AddCardSidebar</h1>
<div>
{searchResults.length !== 0 &&
searchResults.map(result => {
return (
<img
key={result.scryfall_id}
src={result.image_uris.small}
alt={result.name}
onClick={() => setSelectedCard(result.scryfall_id)}
/>
);
})}
</div>
<form>
...
<button type='button' onClick={() => searchCardsQuery()}>
Search
</button>
</form>
...
</div>
);
};
使用useLazyQuery
时,可以将nextFetchPolicy
设置为"standby"
。这将防止查询在第一次获取后再次触发。例如,我在购物车上下文中使用钩子在初始加载时从 E-Commerce 后端获取购物车。之后,所有更新都来自购物车的突变。
目前我有一个 useLazyQuery
钩子,它在按下按钮(搜索表单的一部分)时触发。
挂钩正常运行,仅在按下按钮时触发。但是,一旦我触发它一次,它就会在每次组件重新呈现时触发(通常是由于状态更改)。
因此,如果我搜索一次,然后编辑搜索字段,结果会立即出现,我不必再次点击搜索按钮。
不是我想要的 UI,如果您完全删除搜索文本(因为它试图使用 null
作为变量进行搜索),它会导致错误,有什么方法可以防止useLazyQuery
在重新渲染时被重新获取?
这可以通过使用 useQuery
解决,具体取决于 'searching' 状态,当我单击按钮时该状态会打开。但是我宁愿看看我是否可以避免增加组件的复杂性。
const AddCardSidebar = props => {
const [searching, toggleSearching] = useState(false);
const [searchParams, setSearchParams] = useState({
name: ''
});
const [searchResults, setSearchResults] = useState([]);
const [selectedCard, setSelectedCard] = useState();
const [searchCardsQuery, searchCardsQueryResponse] = useLazyQuery(SEARCH_CARDS, {
variables: { searchParams },
onCompleted() {
setSearchResults(searchCardsQueryResponse.data.searchCards.cards);
}
});
...
return (
<div>
<h1>AddCardSidebar</h1>
<div>
{searchResults.length !== 0 &&
searchResults.map(result => {
return (
<img
key={result.scryfall_id}
src={result.image_uris.small}
alt={result.name}
onClick={() => setSelectedCard(result.scryfall_id)}
/>
);
})}
</div>
<form>
...
<button type='button' onClick={() => searchCardsQuery()}>
Search
</button>
</form>
...
</div>
);
};
react-apollo
文档没有提到 useLazyQuery
是否应该在变量更改时继续触发查询,但是他们确实建议在您想要手动触发时使用 useApolloClient
挂钩一个问题。他们 have an example 匹配此用例(单击按钮触发查询)。
function DelayedQuery() {
const [dog, setDog] = useState(null);
const client = useApolloClient();
return (
<div>
{dog && <img src={dog.displayImage} />}
<button
onClick={async () => {
const { data } = await client.query({
query: GET_DOG_PHOTO,
variables: { breed: 'bulldog' },
});
setDog(data.dog);
}}
>
Click me!
</button>
</div>
);
}
您不必将 async
与 apollo 客户端一起使用(您可以,它有效)。但是如果你想使用 useLazyQuery
你只需要在 onClick
上传递变量而不是直接在 useLazyQuery 调用上传递变量。
对于上面的例子,解决方案是:
function DelayedQuery() {
const [dog, setDog] = useState(null);
const [getDogPhoto] = useLazyQuery(GET_DOG_PHOTO, {
onCompleted: data => setDog(data.dog)
})
return (
<div>
{dog && <img src={dog.displayImage} />}
<button
onClick={() => getDogPhoto({ variables: { breed: 'bulldog' }})}
>
Click me!
</button>
</div>
);
}
Apollo Client 文档对此没有明确说明,但 useLazyQuery 与 useQuery 一样,首先从缓存中获取。如果查询之间没有变化,则不会使用网络调用重新获取。为了每次都进行网络呼叫,您可以根据您的使用情况将 fetchPolicy
更改为 network-only
或 cache-and-network
(documentation link to the fetchPolicy options)。因此,在您的示例中将 fetchPolicy 更改为 network-only
,它看起来像这样:
const AddCardSidebar = props => {
const [searching, toggleSearching] = useState(false);
const [searchParams, setSearchParams] = useState({
name: ''
});
const [searchResults, setSearchResults] = useState([]);
const [selectedCard, setSelectedCard] = useState();
const [searchCardsQuery, searchCardsQueryResponse] =
useLazyQuery(SEARCH_CARDS, {
variables: { searchParams },
fetchPolicy: 'network-only', //<-- only makes network requests
onCompleted() {
setSearchResults(searchCardsQueryResponse.data.searchCards.cards);
}
});
...
return (
<div>
<h1>AddCardSidebar</h1>
<div>
{searchResults.length !== 0 &&
searchResults.map(result => {
return (
<img
key={result.scryfall_id}
src={result.image_uris.small}
alt={result.name}
onClick={() => setSelectedCard(result.scryfall_id)}
/>
);
})}
</div>
<form>
...
<button type='button' onClick={() => searchCardsQuery()}>
Search
</button>
</form>
...
</div>
);
};
使用useLazyQuery
时,可以将nextFetchPolicy
设置为"standby"
。这将防止查询在第一次获取后再次触发。例如,我在购物车上下文中使用钩子在初始加载时从 E-Commerce 后端获取购物车。之后,所有更新都来自购物车的突变。