Laman web moden bersaing untuk mendapatkan perhatian dengan visual yang semakin hebat. Hero parallax meluas jauh ke dalam viewport. Karusel skrol tanpa henti. Video latar belakang dimainkan secara automatik di belakang borang pendaftaran. Corak ini kelihatan kemas dan menarik dalam portfolio reka bentuk. Bagi sebahagian daripada audiens anda, ia adalah pencetus fizikal.

Individu yang menghidap gangguan vestibular mengalami loya, pening, atau migrain apabila berhadapan dengan kawasan luas pergerakan berterusan. Untuk melindungi mereka, setiap sistem operasi utama kini menyertakan tetapan kebolehcapaian "Reduce Motion". Pelayar web mendedahkan pilihan tersebut melalui pertanyaan media prefers-reduced-motion. Pembangun React yang ingin mematuhinya dengan kemas boleh menggunakan hook useReducedMotion daripada @reactuses/core. Ia membaca pilihan OS ke dalam boolean, dikemas kini secara langsung jika pengguna menukar fikiran, dan mengendalikan rendering sebelah pelayan (server-side rendering) tanpa menyebabkan ralat.

Mengapa Penyelesaian Buatan Sendiri Bermasalah

Anda boleh membuat pertanyaan pilihan itu sendiri dengan window.matchMedia('(prefers-reduced-motion: reduce)'). Ramai pembangun melakukannya, dan ramai yang menghantar pepijat yang halus.

Pertama, anda boleh mudah terlupa pendengar perubahan (change listener). Pertanyaan awal dijalankan sekali apabila komponen dipasang (mounts). Jika pengguna membuka aplikasi anda, kemudian menukar tetapan Reduce Motion dalam tetapan sistem kerana karusel membuatkan mereka berasa mual, komponen anda tidak akan menerima kemas kini tersebut. Objek pertanyaan media menyokong addEventListener, tetapi menyambungkannya dengan betul, membuangnya semasa unmount, dan menyediakan polyfill untuk sintaks addListener lama adalah kod boilerplate yang mengundang ralat salin-tampal.

Kedua, window tidak wujud semasa SSR. Jika aplikasi anda dirender pada pelayan, panggilan matchMedia yang ringkas akan mencetuskan ralat rujukan (reference error) dan menghentikan render. Anda akhirnya membungkus semakan tersebut dalam pengawal typeof window !== 'undefined', meneka nilai lalai, dan berharap hidrasi klien (client hydrate) adalah sepadan.

Ketiga, mengulang logik tersebut dalam setiap komponen beranimasi akan menjadi hutang penyelenggaraan (maintenance debt). Seorang rakan sepasukan menulis pendengar dengan satu cara, seorang lagi mengabaikannya sepenuhnya, dan yang ketiga menetapkan nilai lalai secara keras (hard-codes) yang lebih mengutamakan pergerakan. Sebuah hook memusatkan kekacauan tersebut.

useReducedMotion menyelesaikan ketiga-tiga masalah ini. Ia mengembalikan boolean yang ringkas. Ia menjalankan operasi kosong (no-ops) dengan selamat pada pelayan. Ia menyambung dan membersihkan pendengar secara automatik.

Tiga Cara Untuk Menggunakannya

Sebaik sahaja anda mempunyai boolean tersebut, anda memerlukan strategi untuk bertindak mengenainya. Berikut adalah tiga corak yang boleh diskalakan daripada komponen tunggal kepada keseluruhan aplikasi.

1. Kawal Kelas CSS untuk Mengelakkan Kerja Sia-sia

Pendekatan yang paling langsung adalah dengan menghalang gelung animasi JavaScript yang berat daripada bermula. Bayangkan anda mempunyai komponen imej parallax yang biasanya mendengar acara skrol dan menterjemah lapisan di dalam gelung requestAnimationFrame. Daripada menjalankan logik tersebut dan kemudian menyekat hasil visual, semak useReducedMotion terlebih dahulu.

Jika hook mengembalikan true, render komponen dengan kelas varian statik dan langkau useEffect yang mengikat pendengar skrol. Pelayar melakukan kerja yang lebih sedikit. Pengguna dengan sensitiviti pergerakan melihat imej pegun. Orang lain pula mendapat lapisan yang bergerak. Oleh kerana kod animasi tidak pernah dimulakan, anda menjimatkan CPU dan bateri dalam proses tersebut.

2. Masukkan Terus ke dalam Pustaka Animasi

Jika anda menggunakan pustaka seperti Framer Motion, hook ini boleh disambungkan terus ke dalam definisi prop anda. Komponen Motion menerima objek konfigurasi untuk varian, peralihan (transitions), dan gerak isyarat (gestures). Anda boleh menggunakan boolean daripada useReducedMotion untuk menetapkan duration: 0 secara bersyarat pada peralihan, atau