为什么 useQuery 调用会导致我的组件重新呈现?
Why does useQuery call cause a re-render in my component?
正如我们所知,当 props 或 state 发生变化时,React 组件会被重新渲染。
现在我正在使用 react-apollo
包中的 useQuery
,如下所示:
import { gql, useQuery } from '@apollo/client';
const getBookQuery = gql`
{
books {
name
}
}
`;
function BookList() {
const { loading, error, data} = useQuery(getBookQuery);
if(loading) return <p>Loading....</p>
if(error) return <p>Ops! Something went wrong</p>
return (
<>
<ul>
{data.books.map(book => (
<li key={book.name}>{book.name}</li>
))}
</ul>
</>
)
}
export default BookList;
当我 运行 上面的代码时,我们首先在 DOM 中得到 Loading...
然后更新为包含查询数据的列表(一旦它到达)。但是一旦从查询中接收到数据,反应如何知道重新渲染我的组件。
这些 data
、loading
和 error
属性是否已映射到组件属性并且它们正在更新?如果是这样,为什么 chrome 开发工具不显示此 BookList
组件的任何道具?
有人可以解释一下这个 useQuery
自定义挂钩在这里如何工作吗?
挂钩可以有自己的状态,更改时可以触发重新渲染。例如加载、错误、数据。
我在这个沙盒中创建了 apollo 的 useQuery 挂钩的示例实现 https://codesandbox.io/s/determined-wave-dd1wd?file=/src/BookList2.js
在伪造的实现中,可以看到挂钩具有状态,并且只要状态发生变化,组件就会重新呈现。
还创建了另一个组件 BookList2,我没有使用钩子,而是在组件中粘贴了钩子的假实现 - 这样可能会更清楚如何触发重新渲染
TLDR:检查 https://codesandbox.io/s/determined-wave-dd1wd?file=/src/BookList2.js - 看到钩子可以有状态,当改变时会导致重新渲染
(粗略地)弄清楚 useQuery
中发生的事情的一个好方法是考虑您自己如何做,例如
const MyComponent = () => {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
useEffect(async () => {
try {
setLoading(true);
const data = await GraphQL.request(getBookQuery);
setData(data);
} catch (ex) {
setError(ex);
} finally {
setLoading(false);
}
}, []);
if(loading) return <p>Loading....</p>
if(error) return <p>Ops! Something went wrong</p>
return (
<>
<ul>
{data.books.map(book => (
<li key={book.name}>{book.name}</li>
))}
</ul>
</>
);
};
在上面你可以看到你的组件有 state(不是 props)data
, loading
和 error
这会导致你的组件重新渲染。
然后您可以想象这个逻辑包含在您自己的 useQuery
钩子中:
const useQuery = (query, variables) => {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
useEffect(async () => {
try {
setLoading(true);
const data = await GraphQL.request(query, variables);
setData(data);
} catch (ex) {
setError(ex);
} finally {
setLoading(false);
}
}, []);
return { data, loading, error };
}
const MyComponent = () => {
const { data, loading, error } = useQuery(getBookQuery);
if(loading) return <p>Loading....</p>
if(error) return <p>Ops! Something went wrong</p>
return (
<>
<ul>
{data.books.map(book => (
<li key={book.name}>{book.name}</li>
))}
</ul>
</>
);
};
所以最终你的组件会重新渲染,因为它确实有 data
、loading
和 error
保持在 MyComponent
状态,它只是被抽象掉了。
正如我们所知,当 props 或 state 发生变化时,React 组件会被重新渲染。
现在我正在使用 react-apollo
包中的 useQuery
,如下所示:
import { gql, useQuery } from '@apollo/client';
const getBookQuery = gql`
{
books {
name
}
}
`;
function BookList() {
const { loading, error, data} = useQuery(getBookQuery);
if(loading) return <p>Loading....</p>
if(error) return <p>Ops! Something went wrong</p>
return (
<>
<ul>
{data.books.map(book => (
<li key={book.name}>{book.name}</li>
))}
</ul>
</>
)
}
export default BookList;
当我 运行 上面的代码时,我们首先在 DOM 中得到 Loading...
然后更新为包含查询数据的列表(一旦它到达)。但是一旦从查询中接收到数据,反应如何知道重新渲染我的组件。
这些 data
、loading
和 error
属性是否已映射到组件属性并且它们正在更新?如果是这样,为什么 chrome 开发工具不显示此 BookList
组件的任何道具?
有人可以解释一下这个 useQuery
自定义挂钩在这里如何工作吗?
挂钩可以有自己的状态,更改时可以触发重新渲染。例如加载、错误、数据。
我在这个沙盒中创建了 apollo 的 useQuery 挂钩的示例实现 https://codesandbox.io/s/determined-wave-dd1wd?file=/src/BookList2.js
在伪造的实现中,可以看到挂钩具有状态,并且只要状态发生变化,组件就会重新呈现。
还创建了另一个组件 BookList2,我没有使用钩子,而是在组件中粘贴了钩子的假实现 - 这样可能会更清楚如何触发重新渲染
TLDR:检查 https://codesandbox.io/s/determined-wave-dd1wd?file=/src/BookList2.js - 看到钩子可以有状态,当改变时会导致重新渲染
(粗略地)弄清楚 useQuery
中发生的事情的一个好方法是考虑您自己如何做,例如
const MyComponent = () => {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
useEffect(async () => {
try {
setLoading(true);
const data = await GraphQL.request(getBookQuery);
setData(data);
} catch (ex) {
setError(ex);
} finally {
setLoading(false);
}
}, []);
if(loading) return <p>Loading....</p>
if(error) return <p>Ops! Something went wrong</p>
return (
<>
<ul>
{data.books.map(book => (
<li key={book.name}>{book.name}</li>
))}
</ul>
</>
);
};
在上面你可以看到你的组件有 state(不是 props)data
, loading
和 error
这会导致你的组件重新渲染。
然后您可以想象这个逻辑包含在您自己的 useQuery
钩子中:
const useQuery = (query, variables) => {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
useEffect(async () => {
try {
setLoading(true);
const data = await GraphQL.request(query, variables);
setData(data);
} catch (ex) {
setError(ex);
} finally {
setLoading(false);
}
}, []);
return { data, loading, error };
}
const MyComponent = () => {
const { data, loading, error } = useQuery(getBookQuery);
if(loading) return <p>Loading....</p>
if(error) return <p>Ops! Something went wrong</p>
return (
<>
<ul>
{data.books.map(book => (
<li key={book.name}>{book.name}</li>
))}
</ul>
</>
);
};
所以最终你的组件会重新渲染,因为它确实有 data
、loading
和 error
保持在 MyComponent
状态,它只是被抽象掉了。