【发布时间】:2021-10-09 06:52:44
【问题描述】:
我的 React 应用程序中有一个自定义钩子,它使用 GET 请求从 MongoDB 数据库中获取一些数据。在我的一个组件中,我重复使用了钩子两次,每次都使用不同的函数来进行异步 API 调用。
当我查看数据库日志时,我意识到我的每个 GET 请求都被调用了两次而不是一次。例如,我的每个钩子都被调用了两次,使得 API 调用的数量变为四个而不是两个。我不确定为什么会这样。我猜异步调用会导致重新渲染不是并发的,或者我的组件中有某个地方导致重新渲染;不确定。
这是我加载组件时 MongoDB 日志中显示的内容:
我尝试传递一个空数组来限制它运行的时间,但这会阻止在重新加载时获取。有没有办法调整自定义钩子,让每个钩子的 API 调用只运行一次?
这是我正在使用的自定义钩子:
const useFetchMongoField = (user, id, fetchFunction) => {
const [hasFetched, setHasFetched] = useState(false);
const [data, setData] = useState(null);
const [error, setError] = useState(null);
useEffect(() => {
const fetchData = async () => {
if (!user) return;
try {
let result = await fetchFunction(user.email, id);
setData(result);
setHasFetched(true);
} catch (error) {
setError(error.message);
}
};
if (data === null) {
fetchData();
}
}, [user, id, fetchFunction, data]);
return { data, hasFetched, error };
};
这是我重复使用自定义挂钩两次的组件之一。在此示例中,getPercentageRead 和 getNotes 是在 MongoDB 上被调用两次的函数(两次 getPercentageRead 调用和两次 getNotes 调用),尽管我倾向于使用它们中的每一个。
const Book = ({ location }) => {
const { user } = useAuth0();
const isbn = queryString.parse(location.search).id;
const { data: book, hasFetched: fetchedBook } = useFetchGoogleBook(isbn);
const { data: read, hasFetched: fetchedPercentageRead } = useFetchMongoField(
user,
isbn,
getPercentageRead
);
const { data: notes, hasFetched: fetchedNotes } = useFetchMongoField(
user,
isbn,
getNotes
);
if (isbn === null) {
return <RedirectHome />;
}
return (
<Layout>
<Header header="Book" subheader="In your library" />
{fetchedBook && fetchedPercentageRead && (
<BookContainer
cover={book.cover}
title={book.title}
author={book.author}
date={book.date}
desc={book.desc}
category={book.category}
length={book.length}
avgRating={book.avgRating}
ratings={book.ratings}
language={book.language}
isbn={book.isbn}
username={user.email}
deleteButton={true}
redirectAfterDelete={"/"}
>
<ReadingProgress
percentage={read}
isbn={book.isbn}
user={user.email}
/>
</BookContainer>
)}
{!fetchedBook && (
<Wrapper minHeight="50vh">
<Loading
minHeight="30vh"
src={LoadingIcon}
alt="Loading icon"
className="rotating"
/>
</Wrapper>
)}
<Header header="Notes" subheader="All your notes on this book">
<AddNoteButton
to="/add-note"
state={{
isbn: isbn,
user: user,
}}
>
<AddIcon color="#6b6b6b" />
Add Note
</AddNoteButton>
</Header>
{fetchedNotes && (
<NoteContainer>
{notes.map((note) => {
return (
<NoteBlock
title={note.noteTitle}
date={note.date}
key={note._noteID}
noteID={note._noteID}
bookID={isbn}
/>
);
})}
{notes.length === 0 && (
<NoNotesMessage>
You don't have any notes for this book yet.
</NoNotesMessage>
)}
</NoteContainer>
)}
</Layout>
);
};
【问题讨论】:
-
GET 被调用了两次,因为你使用了钩子 2 次。删除 1 个钩子,您将看到 GET 调用一次。
-
@GiovanniEsposito OP 意识到了这一点,并询问如何使钩子中的 fetch 只运行一次,尽管钩子被多次使用
-
useEffect的依赖数组决定了传递给它的函数何时被调用。如果任何引用的元素发生变化,该函数将再次运行。删除data和fetchFunction。 -
是的,这就是重点……
-
@GiovanniEsposito OP 的问题完全合理
标签: javascript reactjs use-effect