Os sites modernos competem pela atenção com visuais cada vez mais grandiosos. Seções hero com parallax estendem-se profundamente na viewport. Carrosséis rolam indefinidamente. Vídeos de fundo reproduzem automaticamente atrás de formulários de inscrição. Esses padrões parecem polidos e envolventes em um portfólio de design. Para uma parcela do seu público, eles são um gatilho físico.
Pessoas que vivem com distúrbios vestibulares sentem náuseas, tonturas ou enxaquecas ao serem confrontadas com grandes áreas de movimento contínuo. Para protegê-las, todos os principais sistemas operacionais agora incluem uma configuração de acessibilidade "Reduzir Movimento". Os navegadores web expõem essa preferência por meio da media query prefers-reduced-motion. Desenvolvedores React que desejam respeitá-la de forma limpa podem utilizar o hook useReducedMotion do @reactuses/core. Ele lê a preferência do SO em um booleano, atualiza em tempo real se o usuário mudar de ideia e lida com a renderização no lado do servidor (SSR) sem causar erros.
Por que soluções manuais falham
Você mesmo poderia consultar a preferência com window.matchMedia('(prefers-reduced-motion: reduce)'). Muitos desenvolvedores o fazem, e muitos acabam enviando bugs sutis.
Primeiro, você pode facilmente esquecer o listener de mudança. A consulta inicial é executada uma vez quando o componente é montado. Se um usuário abrir seu app e depois alternar "Reduzir Movimento" nas configurações do sistema porque um carrossel o está deixando enjoado, seu componente nunca receberá a atualização. O objeto da media query suporta addEventListener, mas configurá-lo corretamente, removê-lo no unmount e fazer o polyfill da sintaxe legada addListener é um boilerplate que convida a erros de copiar e colar.
Segundo, o window não existe durante o SSR. Se o seu app for renderizado no servidor, uma chamada ingênua de matchMedia lançará um erro de referência e interromperá a renderização. Você acaba envolvendo a verificação em proteções typeof window !== 'undefined', tentando adivinhar o padrão e esperando que a hidratação do cliente coincida.
Terceiro, repetir essa lógica em cada componente animado transforma-se em dívida de manutenção. Um colega escreve o listener de um jeito, outro o ignora completamente e um terceiro define um padrão fixo que favorece o movimento. Um hook centraliza essa bagunça.
useReducedMotion resolve todos os três problemas. Ele retorna um booleano simples. Ele executa um no-op de forma segura no servidor. Ele anexa e limpa o listener automaticamente.
Três maneiras de colocá-lo em prática
Uma vez que você tenha o booleano, precisará de uma estratégia para agir sobre ele. Aqui estão três padrões que escalam de um único componente para uma aplicação inteira.
1. Controle classes CSS para evitar trabalho desnecessário
A abordagem mais direta é impedir que loops de animação pesados em JavaScript sequer comecem. Imagine que você tem um componente de imagem parallax que normalmente escuta eventos de scroll e traduz camadas dentro de um loop requestAnimationFrame. Em vez de executar essa lógica e depois suprimir o resultado visual, verifique o useReducedMotion primeiro.
Se o hook retornar true, renderize o componente com uma classe de variante estática e pule o useEffect que vincula os listeners de scroll. O navegador faz menos trabalho. Usuários com sensibilidade ao movimento veem uma imagem fixa. Todos os outros recebem as camadas em movimento. Como o código de animação nunca é inicializado, você economiza CPU e bateria ao longo do caminho.
2. Alimente-o diretamente em bibliotecas de animação
Se você usa uma biblioteca como o Framer Motion, o hook se encaixa diretamente em suas definições de props. Componentes de movimento aceitam objetos de configuração para variantes, transições e gestos. Você pode usar o booleano do useReducedMotion para definir condicionalmente duration: 0 em transições, ou
