10 de março de 2026 • 4 minutos de leitura
Os princípios SOLID são muito conhecidos no desenvolvimento orientado a objetos, mas também podem ser aplicados no desenvolvimento frontend moderno.
Em aplicações construídas com React e Next.js, seguir esses princípios ajuda a organizar melhor componentes, separar responsabilidades e manter o código mais fácil de escalar e manter.
Os princípios foram popularizados por Robert C. Martin e continuam sendo extremamente relevantes mesmo em arquiteturas modernas baseadas em componentes.
Neste artigo veremos como aplicar SOLID na prática em projetos React e Next.js.
Conforme aplicações frontend crescem, é comum encontrar problemas como:
Aplicar princípios de arquitetura como SOLID ajuda a evitar esses problemas, criando aplicações mais organizadas e sustentáveis.
O Single Responsibility Principle diz que uma unidade de código deve ter apenas uma responsabilidade.
No React, isso significa evitar componentes que fazem muitas coisas ao mesmo tempo.
Um componente que busca dados, renderiza UI e também trata lógica de negócio.
function UserProfile() {
const [user, setUser] = React.useState(null)
React.useEffect(() => {
fetch("/api/user")
.then((res) => res.json())
.then((data) => setUser(data))
}, [])
function updateUser() {
console.log("Atualizando usuário")
}
if (!user) {
return <p>Carregando...</p>
}
return (
<div>
<h1>{user.name}</h1>
<button onClick={updateUser}>Atualizar</button>
</div>
)
}Esse componente possui múltiplas responsabilidades:
Separando responsabilidades.
Hook responsável pelos dados:
function useUser() {
const [user, setUser] = React.useState(null)
React.useEffect(() => {
fetch("/api/user")
.then((res) => res.json())
.then(setUser)
}, [])
return user
}Componente focado apenas na interface:
function UserProfile() {
const user = useUser()
if (!user) {
return <p>Carregando...</p>
}
return <UserView user={user} />
}Agora cada parte do sistema possui uma responsabilidade clara.
O Open/Closed Principle diz que devemos poder estender comportamento sem modificar código existente.
Isso é muito comum usando component composition.
function Button({ type }) {
if (type === "primary") {
return <button className="bg-blue-500">Primary</button>
}
if (type === "danger") {
return <button className="bg-red-500">Danger</button>
}
}Toda vez que surge um novo tipo precisamos alterar o componente.
function Button({ children, className }) {
return (
<button className={`px-4 py-2 ${className}`}>
{children}
</button>
)
}Uso:
<Button className="bg-blue-500">Primary</Button>
<Button className="bg-red-500">Danger</Button>
Agora podemos estender comportamento sem modificar o componente.
O Liskov Substitution Principle diz que componentes derivados devem poder substituir os originais sem quebrar comportamento.
function Button({ onClick }) {
return <button onClick={onClick}>Click</button>
}
function LinkButton() {
return <a href="/home">Home</a>
}Se trocarmos Button por LinkButton, o comportamento muda completamente.
function Button({ children, ...props }) {
return <button {...props}>{children}</button>
}
function LinkButton(props) {
return <Button as="a" {...props} />
}Agora ambos seguem o mesmo contrato de uso.
No frontend, esse princípio significa não criar props gigantes que poucos componentes usam.
function Card({ title, image, footer, sidebar, actions }) {
return (
<div>
<h2>{title}</h2>
<img src={image} />
{footer}
{sidebar}
{actions}
</div>
)
}Esse componente tenta resolver muitos cenários diferentes.
Criando componentes menores.
function Card({ children }) {
return <div className="card">{children}</div>
}
function CardHeader({ title }) {
return <h2>{title}</h2>
}
function CardFooter({ children }) {
return <footer>{children}</footer>
}Agora cada componente possui uma responsabilidade clara.
Esse princípio ajuda a evitar dependência direta de implementações.
async function getUsers() {
const response = await fetch("https://api.example.com/users")
return response.json()
}Aqui o código depende diretamente da API.
Criando uma abstração.
function createUserRepository(client) {
return {
async getUsers() {
return client.get("/users")
}
}
}Uso:
const repository = createUserRepository(apiClient)
repository.getUsers()
Agora podemos trocar facilmente:
Algumas práticas ajudam a manter projetos React organizados:
Essas práticas tornam o código mais fácil de entender e evoluir.
Embora os princípios SOLID tenham surgido no contexto da programação orientada a objetos, eles continuam extremamente úteis em aplicações modernas com React e Next.js.
Aplicá-los no frontend ajuda a:
Com o crescimento da aplicação, seguir esses princípios faz uma grande diferença na qualidade do código.