我们按以下方式使用 useQuery 钩子
function Dogs({ onDogSelected }) {
const { loading, error, data } = useQuery(GET_DOGS);
if (loading) return 'Loading...';
if (error) return `Error! ${error.message}`;
return (
<select name='dog' onChange={onDogSelected}>
{data.dogs.map((dog) => (
<option key={dog.id} value={dog.breed}>
{dog.breed}
</option>
))}
</select>
);
}
这里我们使用解构赋值语法并定义一个const变量loading并将其分配给useQuery结果对象的loading属性。但是由于loading是boolean类型的,所以这个变量是按照传值方式来赋值的,那么这个变量怎么变成了false,一开始是true呢。由于变量是const,所以这个值不应该改变。我无法理解使用 useQuery 时幕后发生了什么?
但是由于loading是boolean类型,所以这个变量是按照传值方式赋值的,那么这个变量怎么变成了false,一开始是true。
事实并非如此。在第一次调用组件函数期间获得的
loading
const 永远不会改变。但稍后,当 ajax 调用完成时,useQuery
会更新一个状态成员,这使得 React 再次调用你的组件函数来重新渲染。在该调用中, useQuery
返回特定于该函数调用的新 loading
const 的 new值。这就像
useState
一样,总是返回最新的状态值。
在 useState 中,我们将状态显式设置为新值,它会触发组件的重新渲染,但这里除了调用一次之外,我们没有做任何事情,那么它是如何触发重新渲染的呢?
发生这种情况是因为
useQuery
在其代码中使用和更新状态成员,您只能通过其返回值间接看到这些成员。由于您在组件函数的渲染调用期间调用它,因此这些状态成员存储在组件实例的状态数据中,因此更新它们会使您的组件重新渲染。
让我们用我们自己的
useQuery
替代品来模拟它,它只需等待一会儿,然后返回一个随机数,这样我们就可以看到代码正在执行“隐藏”在 useQuery
中的代码正在执行的操作(实际上并不是这样)隐藏的,它是开源的,但是...):
const { useState, useEffect } = React;
function useDelayedRandom() {
console.log(`useDelayedRandom: called`);
const [rand, setRand] = useState(null);
useEffect(() => {
console.log(`useDelayedRandom: scheduling timer`);
const timer = setTimeout(() => {
const rand = Math.floor(Math.random() * 10000);
console.log(`useDelayedRandom: setting rand = ${rand}`);
setRand(rand);
}, 1000);
return () => clearTimeout(timer);
}, []);
return rand
}
const Example = () => {
console.log(`Example: called`);
const rand = useDelayedRandom();
console.log(`Example: rand = ${rand}`);
return (
<div>rand = { rand }</div>
);
};
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<Example />);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.development.js"></script>
useDelayedRandom
钩子等待一秒钟,然后生成一个随机数并进行状态更新 (setRand(rand)
)。该状态保存在您的组件实例中(在 React 内部的幕后),因此更新它会安排重新渲染。
useQuery
的作用大致相同,但更新是响应 ajax 调用完成而不是计时器。