Integrando o frontend com Axios, Context e .env

Integre o frontend React com o backend Node.js usando Axios, Context API e variável de ambiente.
- #Curso de Frontend
- #Integração Frontend e Backend
- #React
- #Axios
- #Context
- #.env
- #Backend
O que vamos fazer
O frontend deixará de buscar em um JSON local e passará a consumir a rota GET http://localhost:3001/api/search?q=html.
Antes de mexer no React, deixe o backend funcionando e teste http://localhost:3001/api/search?q=html no navegador. A integração só deve começar depois que essa rota responder corretamente.
Instalando Axios e configurando .env
Abra o projeto React no VS Code. No terminal integrado, confirme que você está na pasta do frontend, no mesmo nível do package.json do projeto React, e instale Axios.
Depois, crie um arquivo chamado .env na raiz do projeto frontend. Esse .env fica no frontend, não no backend.
npm install axiosVariável VITE_API_URL
Dentro do .env do frontend, coloque a URL base da API. Como a rota do backend começa com /api, a variável deve terminar em /api.
Depois de criar ou alterar .env no Vite, pare o servidor do frontend e rode npm run dev novamente.
VITE_API_URL=http://localhost:3001/apiServiço de API
Dentro da pasta src do frontend, crie uma pasta chamada services se ela ainda não existir. Dentro dela, crie o arquivo api.js.
Cole o código abaixo em src/services/api.js. Esse arquivo cria uma instância configurada do Axios para evitar repetir a URL completa em todos os lugares.
Lendo o código: import axios carrega a biblioteca, import.meta.env.VITE_API_URL lê a variável do .env do Vite e axios.create cria uma versão configurada do Axios com baseURL e timeout.
Com baseURL igual a http://localhost:3001/api, uma chamada para api.get('/search') vira uma chamada para http://localhost:3001/api/search.
import axios from "axios";
const apiUrl = import.meta.env.VITE_API_URL;
export const api = axios.create({
baseURL: apiUrl,
timeout: 5000
});Context de busca
Dentro da pasta src do frontend, crie uma pasta chamada contexts se ela ainda não existir. Dentro dela, crie o arquivo SearchContext.jsx.
Esse Context centraliza termo, resultados, mensagem, carregamento e função de busca. Ele também trata erro do Axios, porque respostas 400 e 404 entram no catch.
Lendo os states: term guarda o texto digitado, results guarda os cards retornados, message guarda uma mensagem para a tela e loading indica se a busca ainda está acontecendo.
Lendo a função search: ela normaliza o termo, liga loading, chama a API, salva os resultados no sucesso, trata mensagens de erro no catch e sempre desliga loading no finally.
import { createContext, useContext, useState } from "react";
import { api } from "../services/api";
const SearchContext = createContext(null);
export function SearchProvider({ children }) {
const [term, setTerm] = useState("");
const [results, setResults] = useState([]);
const [message, setMessage] = useState("");
const [loading, setLoading] = useState(false);
async function search(searchTerm) {
const normalizedTerm = String(searchTerm || "").trim();
setTerm(normalizedTerm);
setLoading(true);
setMessage("");
try {
const response = await api.get("/search", {
params: {
q: normalizedTerm
}
});
setResults(response.data.data || []);
setMessage(response.data.message || "Resultados encontrados.");
} catch (error) {
const responseData = error.response?.data;
setResults(responseData?.data || []);
setMessage(responseData?.message || "Não foi possível buscar resultados.");
} finally {
setLoading(false);
}
}
return (
<SearchContext.Provider value={{ term, setTerm, results, message, loading, search }}>
{children}
</SearchContext.Provider>
);
}
export function useSearch() {
const context = useContext(SearchContext);
if (!context) {
throw new Error("useSearch precisa ser usado dentro de SearchProvider");
}
return context;
}Envolvendo a aplicação
Abra o arquivo principal do frontend, normalmente src/main.jsx em projetos Vite com React. Importe SearchProvider e coloque ele ao redor do App.
Se o seu projeto usa src/main.tsx, aplique a mesma ideia nesse arquivo.
Lendo o Provider: SearchProvider fica por fora de App para permitir que qualquer componente interno use useSearch. Sem esse envolvimento, o hook não consegue acessar os dados do Context.
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import { SearchProvider } from "./contexts/SearchContext";
ReactDOM.createRoot(document.getElementById("root")).render(
<React.StrictMode>
<SearchProvider>
<App />
</SearchProvider>
</React.StrictMode>
);Tela de busca
No componente da tela de busca, importe useSearch de src/contexts/SearchContext.jsx. Use term e setTerm no input, chame search no submit, mostre loading enquanto a requisição estiver em andamento, mostre message para sucesso ou erro e renderize results.
O exemplo abaixo mostra a estrutura mínima. Adapte os nomes das classes e do componente ao projeto que você já criou no frontend.
Lendo o componente: handleSubmit impede o recarregamento da página com event.preventDefault() e chama search(term). O map percorre results e cria um article para cada item retornado pelo backend.
import { useSearch } from "../contexts/SearchContext";
export function SearchPage() {
const { term, setTerm, results, message, loading, search } = useSearch();
function handleSubmit(event) {
event.preventDefault();
search(term);
}
return (
<section>
<form onSubmit={handleSubmit}>
<input
value={term}
onChange={(event) => setTerm(event.target.value)}
placeholder="Buscar por HTML, React ou Node"
/>
<button type="submit" disabled={loading}>
{loading ? "Buscando..." : "Buscar"}
</button>
</form>
{message ? <p>{message}</p> : null}
<div>
{results.map((item) => (
<article key={item.id}>
<h2>{item.title}</h2>
<p>{item.description}</p>
<a href={item.url} target="_blank" rel="noreferrer">
Abrir referência
</a>
</article>
))}
</div>
</section>
);
}Testando a integração
Rode o backend e o frontend ao mesmo tempo, cada um em seu próprio terminal. Deixe os dois terminais abertos.
No navegador, abra a URL do frontend mostrada pelo Vite, normalmente http://localhost:5173. Pesquise por html, react, node e sql para conferir o fluxo completo.
Se o backend responder no navegador, mas o frontend não mostrar dados, confira VITE_API_URL no .env do frontend, reinicie o Vite e veja se CORS_ORIGIN no .env do backend está apontando para a URL correta do frontend.
cd ~/Desktop/curso-frontend/backend-node
npm run dev
cd ~/Desktop/curso-frontend/projeto-react
npm run dev






