Can you guys help me to solve why am i having a infinite re-render loop when I call a function of my Context that fetches API data? (Sorry about the mistakes and bad practices I may have used in my code, i'm a fresh starter on IT and Development.)
This is my Component:
export const LinkIdeasModal: React.FC<LinkIdeasProps> = ({
idea,
isOpen,
onRequestClose,
}): JSX.Element => {
const { colors } = useTheme();
const { linkIdeas, unLinkIdeas, listLinkedIdeas, linkedIdeas } = useContext(ApprovalFunnelContext);
const { getIdeasForLink, ideasForLink } = useContext(IdeaContext);
const [isAddingIdea, setIsAddingIdea] = useState(false);
const [isSearchingIdea, setIsSearchingIdea] = useState(false);
const [searchState, setSearchState] = useState('');
const handleListLinkedIdeas = useCallback(async (): Promise<void> => {
await listLinkedIdeas(idea.id);
}, [listLinkedIdeas, idea]) ;
const handleLinkIdea = useCallback(async (ideaToLink: string) => {
await linkIdeas(idea.id, ideaToLink);
console.log(`idea primária: ${idea.id}`);
console.log(`idea secundária: ${ideaToLink}`);
}, [linkIdeas, idea]);
const handleUnlinkidea = useCallback(async (secondaryIdeaId) => {
await unLinkIdeas({
params1: idea.id,
params2: secondaryIdeaId,
});
}, [idea.id, unLinkIdeas])
const handleClose = useCallback(() => {
setIsAddingIdea(false);
onRequestClose();
}, [setIsAddingIdea, onRequestClose])
const handleSearching = useCallback(() => {
setIsSearchingIdea(true);
}, [])
const handleNotSearching = useCallback(() => {
setIsSearchingIdea(false)
}, [])
const buildIdeaTitle = (name: string): string => {
const maxWidth = 250;
return getTextWidth(name) > maxWidth
? getStringWith3Dots(name, maxWidth)
: name;
};
useEffect(() => {
(async () => {
await getIdeasForLink({
search: searchState,
});
console.log(linkedIdeas)
})()
handleListLinkedIdeas()
}, []);
return (
<Modal
isOpen={isOpen}
onRequestClose={handleClose}
className="react-modal-idea-links"
overlayClassName="react-modal-overlay"
>
<Container>
<ModalHeader>
<LinkTitleWrapper>
<HiOutlineLink size={25} />
<Title>Vínculos</Title>
</LinkTitleWrapper>
<IoMdClose onClick={handleClose} size={20} />
</ModalHeader>
<Subtitle>
<p><i>Ao vincular ideias, os comentários serão unificados. A ideia que você iniciou o vínculo é a principal.</i></p>
</Subtitle>
<LinkedIdeasContainer>
<div>Ideias complementares</div>
<p><i>Adicione ideias que possuem um nível de semelhança com a principal mas que não são totalmente dependentes. Você pode desfazer o vínculo a qualquer momento</i></p>
<LinkedIdeasWrraper>
{linkedIdeas.length > 0 ? linkedIdeas.map((linkedIdea) =>
<LinkedIdeaCard key={linkedIdea.id}>
<IdeaTitleWrapper>
<BsCircleFill size={8} />
<p>{linkedIdea.title}</p>
</IdeaTitleWrapper>
<IdAndCloseWrapper>
<p>ID #{getSequenceNumber(linkedIdea.sequence)}</p>
<IoMdClose onClick={handleUnlinkidea} size={15} style={{ cursor: "pointer" }} />
</IdAndCloseWrapper>
</LinkedIdeaCard>
) : null}
</LinkedIdeasWrraper>
<AddIdeaWrapper isAdding={isAddingIdea} onClick={() => setIsAddingIdea(true)}>
<HiOutlinePlus size={16} />
<p>Adicionar ideia</p>
</AddIdeaWrapper>
<SearchIdeasWrapper isAdding={isAddingIdea}>
<WapperInput>
<div id="icon">
<AiOutlineSearch color={colors.font} size={20} />
</div>
<InputSearch
placeholder="Buscar por título, ID ou palavra-chave"
value={searchState}
onChange={e => setSearchState(e.target.value)}
onFocus={handleSearching}
// onBlur={handleNotSearching}
/>
</WapperInput>
</SearchIdeasWrapper>
<ResultSearcIdeasContainer isSearchingIdea={isSearchingIdea}>
{ideasForLink.length > 0 ? ideasForLink.map((idea) =>
<PossibleLinkIdeaCard key={idea.id} onClick={() => handleLinkIdea(idea.id)}>
<IdeaTitleWrapper>
<BsCircleFill size={8} />
<p>{buildIdeaTitle(idea.title)}</p>
</IdeaTitleWrapper>
<IdAndCloseWrapper>
<p>ID #{getSequenceNumber(idea.sequence)}</p>
</IdAndCloseWrapper>
</PossibleLinkIdeaCard>
): null}
</ResultSearcIdeasContainer>
</LinkedIdeasContainer>
</Container>
</Modal>
);
};
And this is my function on Context (ApprovalFunnelContext):
const listLinkedIdeas = useCallback(async (ideaId: string) => {
try {
dispatch({ type: 'SET_LOADING', loading: true });
const {
data: {
linkedIdeas
}
} = await api.get(`/idea-links/${ideaId}`);
dispatch({ type: 'SET_LINKED_IDEAS', linkedIdeas });
dispatch({ type: 'SET_LOADING', loading: false });
} catch (err) {
toast.error(err?.response?.data?.message || 'Erro ao buscar ideias vinculadas');
}
}, []);
I can't understand why the handleListLinkedIdeas
function on useEffect is causing the loop. When i comment this function, the re-render loop stops (but i dont get the data i need)...
I've already tried to use a State and to put all sort of variables on the array second argument of useEffect.