I have a parent component that passes a callback function to child component so that whenever the state of an array changes in child component, the callback will be called. For some reason, whenever the first time I change the state in child component, it leads to an infinite loop where the callback keeps getting called forever.
Here is the real code below.
I have defined a mutation to set the list of similarBooks when user adds a new book in the list. Child component keeps track of the list. Initial value of similarBooks is provided by parent component. Child component has a form to add books into the similarBooks list. Whenever the state of that list changes, useEffect in child component gets called which in turn calls the callback function provided by the parent function. The callback function executes the setSimilarBooks mutation.
One interesting thing is that if I just move onChangeSimilarBooks callback into the Child component, then the issue doesn't exist anymore. Or if I keep the callback in parent, but don't call the setSimilarBooks mutation, then also issue disappears.
Parent component:
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),
},
});
}
}
Parent has a child component:
<ChipsComponent
key="{bookDetails.book.name}_similarbooks"
initialValues={bookDetails.book.similarBooks}
suggestions={booksList.books}
allowNew={false}
onChangeCallback={onChangeSimilarBooks}
userFriendlyValue={userFriendlyValueOfBook}
/>
Child Component:
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>);
I would like for the callback to get called only once every time the state really changes.