fix: resolve infinite loop in useEffect/useCallback hooks
- useProdutos: replaced useCallback([currentPage]) with useRef + useCallback([]) - useEntregas: same fix for listarEntregas - produtos/page: removed unstable listarProdutos from useEffect deps - entregas/page: removed unstable listarEntregas from useEffect deps Root cause: useCallback depended on currentPage but setCurrentPage inside caused circular dependency.
This commit is contained in:
parent
11c93ae584
commit
b0ffceefa8
4 changed files with 32 additions and 17 deletions
|
|
@ -32,6 +32,7 @@ const statusIcons = {
|
||||||
};
|
};
|
||||||
|
|
||||||
function EntregasContent() {
|
function EntregasContent() {
|
||||||
|
console.log('[ENTREGAS] 🔄 Component render');
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const [user, setUser] = useState<any>(null);
|
const [user, setUser] = useState<any>(null);
|
||||||
const [filtroStatus, setFiltroStatus] = useState<string>("todos");
|
const [filtroStatus, setFiltroStatus] = useState<string>("todos");
|
||||||
|
|
@ -55,6 +56,7 @@ function EntregasContent() {
|
||||||
|
|
||||||
// Verificação de autenticação
|
// Verificação de autenticação
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
console.log('[ENTREGAS] 🔑 Auth useEffect triggered');
|
||||||
const checkAuth = async () => {
|
const checkAuth = async () => {
|
||||||
try {
|
try {
|
||||||
const storedToken = localStorage.getItem('access_token');
|
const storedToken = localStorage.getItem('access_token');
|
||||||
|
|
@ -96,7 +98,9 @@ function EntregasContent() {
|
||||||
|
|
||||||
// Carregar entregas quando usuário for autenticado
|
// Carregar entregas quando usuário for autenticado
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
console.log('[ENTREGAS] 📦 Data fetch useEffect triggered', { user: !!user, userLoading });
|
||||||
if (user && !userLoading) {
|
if (user && !userLoading) {
|
||||||
|
console.log('[ENTREGAS] 📦 Calling listarEntregas...');
|
||||||
listarEntregas({
|
listarEntregas({
|
||||||
page: 1,
|
page: 1,
|
||||||
search: termoBusca.trim() || undefined,
|
search: termoBusca.trim() || undefined,
|
||||||
|
|
@ -106,7 +110,8 @@ function EntregasContent() {
|
||||||
console.error("❌ Erro ao carregar entregas:", error);
|
console.error("❌ Erro ao carregar entregas:", error);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [user, userLoading, listarEntregas]);
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [user, userLoading]);
|
||||||
|
|
||||||
const handleSearch = async () => {
|
const handleSearch = async () => {
|
||||||
limparErro();
|
limparErro();
|
||||||
|
|
@ -697,6 +702,9 @@ function EntregasContent() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function EntregasPage() {
|
const EntregasPage = () => {
|
||||||
|
console.log('[ENTREGAS] 🔄 Component render');
|
||||||
return <EntregasContent />;
|
return <EntregasContent />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default EntregasPage;
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import ProdutoList from '@/components/ProdutoList';
|
||||||
import { useProdutos, ProdutoFormData } from '@/hooks/useProdutos';
|
import { useProdutos, ProdutoFormData } from '@/hooks/useProdutos';
|
||||||
|
|
||||||
const GestaoProdutos = () => {
|
const GestaoProdutos = () => {
|
||||||
|
console.log('[PRODUTOS] 🔄 Component render');
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const [user, setUser] = useState<Models.User<Models.Preferences> | null>(null);
|
const [user, setUser] = useState<Models.User<Models.Preferences> | null>(null);
|
||||||
const [editing, setEditing] = useState<Models.Document | null>(null);
|
const [editing, setEditing] = useState<Models.Document | null>(null);
|
||||||
|
|
@ -45,7 +46,8 @@ const GestaoProdutos = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
initializeUser();
|
initializeUser();
|
||||||
}, [activeTab, router, listarProdutos]);
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [activeTab]);
|
||||||
|
|
||||||
const handleFormSubmit = async (formData: ProdutoFormData): Promise<boolean> => {
|
const handleFormSubmit = async (formData: ProdutoFormData): Promise<boolean> => {
|
||||||
if (editing) {
|
if (editing) {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { useState, useCallback } from 'react';
|
import { useState, useCallback, useRef } from 'react';
|
||||||
import { entregasApiService, EntregaBff, EntregasBffParams } from '@/services/entregasApiService';
|
import { entregasApiService, EntregaBff, EntregasBffParams } from '@/services/entregasApiService';
|
||||||
|
|
||||||
export interface UseEntregasReturn {
|
export interface UseEntregasReturn {
|
||||||
|
|
@ -32,6 +32,8 @@ export const useEntregas = (): UseEntregasReturn => {
|
||||||
const [totalEntregas, setTotalEntregas] = useState(0);
|
const [totalEntregas, setTotalEntregas] = useState(0);
|
||||||
const [currentPage, setCurrentPage] = useState(1);
|
const [currentPage, setCurrentPage] = useState(1);
|
||||||
const [totalPages, setTotalPages] = useState(0);
|
const [totalPages, setTotalPages] = useState(0);
|
||||||
|
const currentPageRef = useRef(currentPage);
|
||||||
|
currentPageRef.current = currentPage;
|
||||||
|
|
||||||
const listarEntregas = useCallback(async (params: EntregasBffParams = {}) => {
|
const listarEntregas = useCallback(async (params: EntregasBffParams = {}) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
|
@ -40,7 +42,7 @@ export const useEntregas = (): UseEntregasReturn => {
|
||||||
try {
|
try {
|
||||||
// Usar parâmetros fornecidos ou valores padrão
|
// Usar parâmetros fornecidos ou valores padrão
|
||||||
const requestParams = {
|
const requestParams = {
|
||||||
page: params.page || currentPage,
|
page: params.page || currentPageRef.current,
|
||||||
limit: params.limit || DEFAULT_PAGE_SIZE,
|
limit: params.limit || DEFAULT_PAGE_SIZE,
|
||||||
search: params.search,
|
search: params.search,
|
||||||
status: params.status,
|
status: params.status,
|
||||||
|
|
@ -67,7 +69,7 @@ export const useEntregas = (): UseEntregasReturn => {
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
}, [currentPage]);
|
}, []);
|
||||||
|
|
||||||
const buscarEntregaPorId = useCallback(async (id: string): Promise<EntregaBff | null> => {
|
const buscarEntregaPorId = useCallback(async (id: string): Promise<EntregaBff | null> => {
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { useState, useCallback } from 'react';
|
import { useState, useCallback, useRef } from 'react';
|
||||||
import { Models } from 'appwrite';
|
import { Models } from 'appwrite';
|
||||||
import { produtoService, ProdutoData } from '@/services/produtoService';
|
import { produtoService, ProdutoData } from '@/services/produtoService';
|
||||||
|
|
||||||
|
|
@ -30,18 +30,21 @@ export const useProdutos = (): UseProdutosReturn => {
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
const [totalProdutos, setTotalProdutos] = useState(0);
|
const [totalProdutos, setTotalProdutos] = useState(0);
|
||||||
const [currentPage, setCurrentPage] = useState(1);
|
const [currentPage, setCurrentPage] = useState(1);
|
||||||
|
const currentPageRef = useRef(currentPage);
|
||||||
|
currentPageRef.current = currentPage;
|
||||||
|
|
||||||
const listarProdutos = useCallback(async (page = currentPage) => {
|
const listarProdutos = useCallback(async (page?: number) => {
|
||||||
|
const targetPage = page ?? currentPageRef.current;
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
setError(null);
|
setError(null);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await produtoService.listar(page, PAGE_SIZE);
|
const response = await produtoService.listar(targetPage, PAGE_SIZE);
|
||||||
|
|
||||||
if (response.success) {
|
if (response.success) {
|
||||||
setProdutos(response.documents || []);
|
setProdutos(response.documents || []);
|
||||||
setTotalProdutos(response.total || 0);
|
setTotalProdutos(response.total || 0);
|
||||||
setCurrentPage(page);
|
setCurrentPage(targetPage);
|
||||||
} else {
|
} else {
|
||||||
setError(response.error || 'Erro ao carregar produtos');
|
setError(response.error || 'Erro ao carregar produtos');
|
||||||
}
|
}
|
||||||
|
|
@ -50,7 +53,7 @@ export const useProdutos = (): UseProdutosReturn => {
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
}, [currentPage]);
|
}, []);
|
||||||
|
|
||||||
const cadastrarProduto = useCallback(async (formData: ProdutoFormData): Promise<boolean> => {
|
const cadastrarProduto = useCallback(async (formData: ProdutoFormData): Promise<boolean> => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
|
@ -60,7 +63,7 @@ export const useProdutos = (): UseProdutosReturn => {
|
||||||
const response = await produtoService.criar(formData);
|
const response = await produtoService.criar(formData);
|
||||||
|
|
||||||
if (response.success) {
|
if (response.success) {
|
||||||
await listarProdutos(currentPage);
|
await listarProdutos(currentPageRef.current);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
setError(response.error || 'Erro ao cadastrar produto');
|
setError(response.error || 'Erro ao cadastrar produto');
|
||||||
|
|
@ -72,7 +75,7 @@ export const useProdutos = (): UseProdutosReturn => {
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
}, [currentPage, listarProdutos]);
|
}, [listarProdutos]);
|
||||||
|
|
||||||
const atualizarProduto = useCallback(async (id: string, formData: ProdutoFormData): Promise<boolean> => {
|
const atualizarProduto = useCallback(async (id: string, formData: ProdutoFormData): Promise<boolean> => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
|
@ -82,7 +85,7 @@ export const useProdutos = (): UseProdutosReturn => {
|
||||||
const response = await produtoService.atualizar(id, formData);
|
const response = await produtoService.atualizar(id, formData);
|
||||||
|
|
||||||
if (response.success) {
|
if (response.success) {
|
||||||
await listarProdutos(currentPage);
|
await listarProdutos(currentPageRef.current);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
setError(response.error || 'Erro ao atualizar produto');
|
setError(response.error || 'Erro ao atualizar produto');
|
||||||
|
|
@ -94,7 +97,7 @@ export const useProdutos = (): UseProdutosReturn => {
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
}, [currentPage, listarProdutos]);
|
}, [listarProdutos]);
|
||||||
|
|
||||||
const deletarProduto = useCallback(async (id: string): Promise<boolean> => {
|
const deletarProduto = useCallback(async (id: string): Promise<boolean> => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
|
@ -104,7 +107,7 @@ export const useProdutos = (): UseProdutosReturn => {
|
||||||
const response = await produtoService.deletar(id);
|
const response = await produtoService.deletar(id);
|
||||||
|
|
||||||
if (response.success) {
|
if (response.success) {
|
||||||
await listarProdutos(currentPage);
|
await listarProdutos(currentPageRef.current);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
setError(response.error || 'Erro ao deletar produto');
|
setError(response.error || 'Erro ao deletar produto');
|
||||||
|
|
@ -116,7 +119,7 @@ export const useProdutos = (): UseProdutosReturn => {
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
}, [currentPage, listarProdutos]);
|
}, [listarProdutos]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
produtos,
|
produtos,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue