当状态第一次更改时,从useEffect对回调进行无限调用



我有一个父组件,它将回调函数传递给子组件,这样每当子组件中数组的状态发生变化时,就会调用回调。出于某种原因,每当我第一次更改子组件中的状态时,就会导致一个无限循环,在这个循环中,回调将永远被调用。

下面是真实的代码。

我定义了一个突变,当用户在列表中添加新书时,设置相似书籍的列表。子组件跟踪列表。类似书籍的初始值由父组件提供。子组件有一个将图书添加到类似图书列表中的窗体。每当该列表的状态发生变化时,就会调用子组件中的useEffect,进而调用父函数提供的回调函数。回调函数执行setSimilarBooks突变。

一件有趣的事情是,如果我只是将ChangeSimilarBooks回调移到Child组件中,那么问题就不存在了。或者,如果我在parent中保留回调,但不调用setSimilarBooks突变,那么问题也会消失。

父组件:

const [setSimilarBooks, { data: mutationSimilarBooksData, 
loading: mutationSimilarBooksLoading, error: mutationSimilarBooksError }] 
= useMutation(setSimilarBooksMutation);
const onChangeSimilarBooks = (values) => {
console.log(values);
if (!mutationSimilarBooksLoading) {
setSimilarBooks({
variables: {
bookId: bookId,
similarBooksIds: values.map(value => value.id),
},
});
}
}

父组件有一个子组件:

<ChipsComponent
key="{bookDetails.book.name}_similarbooks"
initialValues={bookDetails.book.similarBooks}
suggestions={booksList.books}
allowNew={false}
onChangeCallback={onChangeSimilarBooks}
userFriendlyValue={userFriendlyValueOfBook}
/>

子组件:

const [values, setValues] = useState(initialValues);
useEffect(() => {
onChangeCallback(values);
}, [values]);
...

...
return (
<div className="container">
{values.map((book, index) => (
<div className="books" key={index}>
{userFriendlyValue(book)}
<button onClick={() => deleteTag(index)}>x</button>
</div>
))}
<div className="newTag">
<input
value={input}
placeholder="Enter a tag"
onKeyDown={onKeyDown}
onKeyUp={onKeyUp}
onChange={onChange}
/>
{suggestionsActive && <Autocomplete />}
</div>
</div>);

我希望每次状态真正改变时只调用一次回调。

对函数onChangeSimilarBook的引用在每次渲染时都会更改。你以某种方式通过引用使其稳定。您可以尝试使用useEvent

useevent.md

目前还不清楚为什么将回调和useMutation挂钩移动到子级并直接调用setSimilarBooks,或者将回调保留在父级而不调用setSimilarBooks会触发这种情况。我从代码中看到的唯一可能性是onChangeSimilarBooks回调不是一个稳定的引用。你可以把它包装在useCallback挂钩中来记忆它

示例:

const onChangeSimilarBooks = useCallback((values) => {
console.log(values);
if (!mutationSimilarBooksLoading) {
setSimilarBooks({
variables: {
bookId,
similarBooksIds: values.map(value => value.id),
},
});
}
}, [mutationSimilarBooksLoading, setSimilarBooks]);

最新更新