useLazyQuery变量滞后一步问题排查求助
useLazyQuery 变量值滞后一步的问题解决
问题现象
使用useLazyQuery以ID作为变量获取数据时,出现变量值滞后一步的异常:首次调用无变量传入,第二次调用传入的是首次应传的值,以此类推。比如点击按钮'One'本应获取ID为1的文章数据,点击'Two'却获取到ID为1的数据,始终滞后一个操作。
原因分析
React的状态更新是异步的,useLazyQuery返回的data和variables属于组件状态变量。当你await loadChartData()后,虽然请求已经完成,但组件还没来得及重新渲染更新状态,当前事件回调的闭包里拿到的还是旧的data和variables值,直到下一次组件渲染才会更新为最新值。
解决方案
以下两种方式可解决该问题:
方式一:直接获取loadChartData的返回结果
loadChartData调用后会返回一个Promise,这个Promise会resolve当前请求的响应数据,你可以直接从这个Promise的结果里拿到最新数据,无需依赖组件状态里的data。
修改后的按钮点击逻辑示例:
<button onClick={async () => { console.log("Clicked: ", 1); const response = await loadChartData({ variables: {"index": 1 } }); console.log("data: ", response.data, response.variables); }} > One </button>
方式二:用useEffect监听状态变化
如果需要在数据更新后执行后续逻辑,可以使用useEffect监听data或variables的变化,当它们更新时触发对应处理:
import './App.css' import { gql, useLazyQuery } from "@apollo/client"; import { useEffect } from 'react'; const App = () => { const GET_DATA = gql` query GetData($index: ID!) { post(id: $index) { id title body } } `; const [loadChartData, { data, variables }] = useLazyQuery(GET_DATA, { fetchPolicy: "network-only" }); useEffect(() => { if (data) { console.log("最新数据: ", data, variables); // 在这里处理数据更新后的逻辑 } }, [data, variables]); return ( <div className="App"> <button onClick={() => { console.log("Clicked: ", 1); loadChartData({ variables: {"index": 1 } }); }} > One </button> <button onClick={() => { console.log("Clicked: ", 2); loadChartData({ variables: {"index": 2 } }); }} > Two </button> <button onClick={() => { console.log("Clicked: ", 3); loadChartData({ variables: {"index": 3 } }); }} > Three </button> </div> ); }; export default App;
原复现代码
App.js
import './App.css' import { gql, useLazyQuery } from "@apollo/client"; const App = () => { const GET_DATA = gql` query GetData($index: ID!) { post(id: $index) { id title body } } `; const [loadChartData, { data, variables }] = useLazyQuery(GET_DATA, { fetchPolicy: "network-only" }); return ( <div className="App"> <button onClick={async () => { console.log("Clicked: ", 1); await loadChartData({ variables: {"index": 1 } }); console.log("data: ", data, variables); }} > One </button> <button onClick={async () => { console.log("Clicked: ", 2); await loadChartData({ variables: {"index": 2 } }); console.log("data: ", data, variables); }} > Two </button> <button onClick={async () => { console.log("Clicked: ", 3); await loadChartData({ variables: {"index": 3 } }); console.log("data: ", data, variables); }} > Three </button> </div> ); }; export default App;
index.js
import React from 'react'; import ReactDOM from 'react-dom/client'; import './index.css'; import App from './App'; import { ApolloClient, InMemoryCache, ApolloProvider, HttpLink, } from "@apollo/client"; const client = new ApolloClient({ link: new HttpLink({ uri: 'https://graphqlzero.almansi.me/api', headers: { "Content-Type": "application/json" } }), cache: new InMemoryCache(), }); const root = ReactDOM.createRoot(document.getElementById('root')); root.render( <ApolloProvider client={client}> <App /> </ApolloProvider> );
内容的提问来源于stack exchange,提问作者Amit R
相关产品推荐
相关产品推荐

