React 18 + Vite otimizacao de performance para o Nexus-Arqui. Re-renders, bundle, Context, hooks. NAO e Next.js.
Stack real: React 18 + Vite 6 + TypeScript strict + TailwindCSS v3 + IndexedDB Não é Next.js. Server Components, SSR,
next/image,dynamic()NÃO se aplicam.
🐌 Slow initial load?
→ Code split: React.lazy + Suspense
→ Bundle: vite-bundle-visualizer
🔄 Excessive re-renders?
→ Context decomposition
→ useMemo / useCallback / React.memo
🏗️ Data fetching issues?
→ Move to service layer (src/services/)
→ useEffect → custom hook
📦 Large bundle?
→ Dynamic imports: React.lazy(() => import('./Feature'))
→ Tree-shaking: named imports
// ❌ ERRADO — Context "God Object" causa todos os consumers re-renderizarem
const AppContext = createContext({ projects, clients, proposals, financeiro, ... });
// ✅ CORRETO — Contextos separados por domínio
const ProjectContext = createContext<ProjectContextType | null>(null);
const ClientContext = createContext<ClientContextType | null>(null);
// ❌ ERRADO — allData pattern
const allData = useMemo(() => ({ ...projects, ...clients }), [projects, clients]);
// ✅ CORRETO — consume somente o necessário
const { projects } = useProjectContext();
// ❌ ERRADO — importação estática de módulo pesado
import { RelatoriosPage } from './pages/RelatoriosPage';
// ✅ CORRETO — lazy loading por rota
const RelatoriosPage = React.lazy(() => import('./pages/RelatoriosPage'));
// No router:
<Suspense fallback={<PageSpinner />}>
<Route path="/relatorios" element={<RelatoriosPage />} />
</Suspense>
// ✅ USE useMemo — cálculo financeiro pesado
const totalRevenue = useMemo(
() => proposals.filter(p => p.status === 'won').reduce((sum, p) => sum + p.value, 0),
[proposals]
);
// ❌ NÃO USE — operações triviais (mais custo que benefício)
const count = useMemo(() => items.length, [items]); // ERRADO — apenas items.length
// ✅ USE useCallback — callbacks passadas para componentes memorizados
const handleSave = useCallback(
(project: Project) => saveProject(project),
[saveProject]
);
// ✅ USE React.memo — componentes puros que recebem props estáveis
const ProjectCard = React.memo(function ProjectCard({ project }: Props) { ... });
// ❌ ERRADO — derivar state de outro state via useEffect
const [total, setTotal] = useState(0);
useEffect(() => {
setTotal(items.reduce((s, i) => s + i.value, 0));
}, [items]);
// ✅ CORRETO — derive diretamente no render
const total = items.reduce((s, i) => s + i.value, 0);
// ❌ ERRADO — dep array incompleto
useEffect(() => {
fetchData(projectId);
}, []); // projectId missing
// ✅ CORRETO — todas as deps presentes
useEffect(() => {
fetchData(projectId);
}, [projectId]);
// ❌ ERRADO — import de biblioteca inteira
import * as _ from 'lodash';
import { format } from 'date-fns'; // Ok se usarem poucos
// ✅ CORRETO — import específico
import { debounce } from 'lodash/debounce';
// Analyze bundle:
// npx vite-bundle-visualizer
// src/services/ é a única camada que acessa IndexedDB
// ❌ ERRADO — acesso direto em componente
const data = await indexedDB.open('nexus');
// ✅ CORRETO — via service
const projects = await projectService.getAll();
Crítico:
Alto:
allData patternMédio:
| ❌ Não | ✅ Faça |
|---|---|
| God Context com todos os domínios | Contexto por domínio |
allData pattern | Consume somente o necessário |
| Acesso a IndexedDB em componente | Via src/services/ |
| React.FC para componentes | Função normal tipada |
| useEffect para derivar state | useMemo ou cálculo direto |
| Import estático de página pesada | React.lazy + Suspense |
[SYSTEM_INSTRUCTIONS] Language Context: The user will interact with you in Brazilian Portuguese (PT-BR).
Execution Pipeline: