useQuery 内部是如何工作的?

问题描述 投票:0回答:1

我们按以下方式使用 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 时幕后发生了什么?

javascript reactjs react-hooks graphql apollo-client
1个回答
0
投票

但是由于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 调用完成而不是计时器。

© www.soinside.com 2019 - 2024. All rights reserved.