تنفيذ الوضع المظلم في React Apps باستخدام مكونات مصممة
نشرت: 2022-03-10يعد الوضع المظلم (أو الوضع الليلي ، كما يسميه الآخرون) من أكثر ميزات البرامج المطلوبة شيوعًا. نرى الوضع المظلم في التطبيقات التي نستخدمها كل يوم. من تطبيقات الجوال إلى تطبيقات الويب ، أصبح الوضع المظلم أمرًا حيويًا للشركات التي ترغب في الاهتمام بأعين مستخدميها.
الوضع الداكن هو ميزة تكميلية تعرض معظم الأسطح المظلمة في واجهة المستخدم. اعتمدت معظم الشركات الكبرى (مثل YouTube و Twitter و Netflix) الوضع المظلم في تطبيقات الأجهزة المحمولة والويب.
على الرغم من أننا لن نتعمق في React والمكونات المصممة ، إلا أن المعرفة الأساسية بـ React و CSS والمكونات المصممة ستكون في متناول اليد. سيفيد هذا البرنامج التعليمي أولئك الذين يتطلعون إلى تحسين تطبيقات الويب الخاصة بهم من خلال تلبية احتياجات أولئك الذين يحبون الوضع المظلم.

قبل أيام قليلة من كتابة هذه المقالة ، أعلنت StackOverflow عن إطلاقها للوضع المظلم ، مما يمنح المستخدمين فرصة للتبديل بين الوضعين.
يقلل الوضع الداكن من إجهاد العين ويساعد عند العمل لفترة طويلة على جهاز كمبيوتر أو هاتف محمول.
ما هو الوضع الداكن؟
الوضع الداكن هو مخطط الألوان لأي واجهة تعرض نصًا فاتحًا وعناصر واجهة على خلفية داكنة ، مما يجعل الشاشة أسهل قليلاً في النظر إلى الهواتف المحمولة والأجهزة اللوحية وأجهزة الكمبيوتر. يعمل الوضع الداكن على تقليل الضوء المنبعث من الشاشة ، مع الحفاظ على الحد الأدنى من نسب تباين الألوان المطلوبة لسهولة القراءة.
لماذا يجب أن تهتم بالوضع المظلم؟
يعمل الوضع الداكن على تحسين بيئة العمل البصرية من خلال تقليل إجهاد العين ، وتعديل الشاشة على ظروف الإضاءة الحالية ، وتوفير سهولة الاستخدام في الليل أو في البيئات المظلمة.
قبل تطبيق الوضع المظلم في تطبيقنا ، دعونا نلقي نظرة على فوائده.
توفير البطارية
يمكن أن يطيل الوضع الداكن في تطبيقات الويب والجوّال من عمر بطارية الجهاز. أكدت Google أن الوضع المظلم على شاشات OLED كان بمثابة مساعدة كبيرة لعمر البطارية.
على سبيل المثال ، عند السطوع بنسبة 50٪ ، يوفر الوضع الداكن في تطبيق YouTube حوالي 15٪ من طاقة الشاشة أكثر من الخلفية البيضاء المسطحة. عند سطوع الشاشة بنسبة 100٪ ، توفر الواجهة المظلمة 60٪ من طاقة الشاشة.
الوضع المظلم جميل
الوضع الداكن جميل ، ويمكن أن يعزز بشكل كبير من جاذبية الشاشة.
بينما تتجه معظم المنتجات إلى هذا المظهر الأبيض اللطيف المماثل ، يقدم الوضع الداكن شيئًا مختلفًا يبدو غامضًا وجديدًا.
كما يوفر فرصًا رائعة لتقديم محتوى رسومي مثل لوحات المعلومات والصور والصور بطريقة جديدة.

الآن بعد أن عرفت لماذا يجب عليك تنفيذ الوضع المظلم في تطبيق الويب التالي ، دعنا نتعمق في المكونات المصممة ، والتي تعد المورد المحدد لهذا البرنامج التعليمي.
الوضع الداكن هو مخطط ألوان أي واجهة تعرض نصًا فاتحًا وعناصر واجهة على خلفية داكنة ، مما يجعل النظر إليها أسهل قليلاً على الهواتف المحمولة والأجهزة اللوحية وأجهزة الكمبيوتر.
"
ما هي المكونات المصممة؟
خلال هذه المقالة ، سنستخدم مكتبة المكونات المصممة كثيرًا. لطالما كانت هناك طرق عديدة لتصميم تطبيق ويب حديث. هناك الطريقة التقليدية للتنسيق على مستوى المستند ، والتي تتضمن إنشاء ملف index.css
وربطه بـ HTML أو التصميم داخل ملف HTML.
لقد تغير الكثير في طرق تصميم تطبيقات الويب مؤخرًا ، منذ تقديم CSS-in-JS.
يشير CSS-in-JS إلى نمط يتكون فيه CSS باستخدام JavaScript. إنه يستخدم القوالب الحرفية ذات العلامات المميزة لتصميم المكونات في ملف JavaScript.
لمعرفة المزيد حول CSS-in-JS ، راجع مقالة Anna Monus حول هذا الموضوع.
مكوّنات النمط هي مكتبة CSS-in-JS تتيح لك استخدام جميع ميزات CSS التي تحبها ، بما في ذلك استعلامات الوسائط والمحددات الزائفة والتداخل.
لماذا المكونات المصممة؟
تم إنشاء المكونات المصممة للأسباب التالية:
- لا اسم فئة الجحيم
بدلاً من أن تخدش رأسك للعثور على اسم فئة لعنصر ما ، تُنشئ المكونات المصممة أسماء فئات فريدة لأنماطك. لن تقلق أبدًا بشأن الأخطاء الإملائية أو استخدام أسماء فئات ليس لها معنى. - استخدام الدعائم
تسمح لنا مكوّنات النمط بتوسيع خصائص التصميم باستخدام معلمةprops
، وهي شائعة الاستخدام في React - وبالتالي ، تؤثر ديناميكيًا على إحساس المكون عبر حالة التطبيق. - يدعم بناء جملة Sass
من الممكن كتابة بنية Sass خارج الصندوق دون الحاجة إلى إعداد أي معالجات أولية أو أدوات بناء إضافية باستخدام المكونات المصممة. في تعريفات النمط الخاصة بك ، يمكنك استخدام الحرف&
لاستهداف المكون الحالي ، واستخدام المحددات الزائفة ، وتجربة التداخل. - تصميم
تتمتع المكونات ذات الأنماط بدعم كامل عن طريق تصدير مكون غلافThemeProvider
. يوفر هذا المكون سمة لجميع مكونات React داخل نفسها عبر واجهة برمجة تطبيقات السياق. في شجرة العرض ، ستتمتع جميع المكونات المصممة بإمكانية الوصول إلى السمة المقدمة ، حتى عندما تكون متعددة المستويات في العمق. مع استمرارنا في هذا البرنامج التعليمي ، سننظر بشكل أعمق في ميزات السمات للمكونات المصممة.
لمعرفة المزيد من مزايا المكونات المصممة ، راجع مقالة Kris Guzman.
تنفيذ الوضع الداكن
في هذه المقالة ، سنقوم بتنفيذ الوضع المظلم على صفحة ويب بسيطة تشبه YouTube.
للمتابعة ، تأكد من استنساخ المستودع الأصلي من فرع starter
.
اعداد
دعنا نثبت كل التبعيات في ملف package.json
الخاص بنا. من المحطة ، قم بتشغيل الأمر التالي:
npm install
عند التثبيت الناجح ، قم بتشغيل npm start
. هذا ما تبدو عليه صفحة الويب بدون تطبيق الوضع المظلم عليها.

لتثبيت styled-components
، قم بتشغيل npm install styled-components
في جهازك.
تطبيق
لتنفيذ الوضع المظلم ، نحتاج إلى إنشاء أربعة مكونات مختلفة.
-
Theme
يحتوي هذا على خصائص الألوان الخاصة بسماتنا الفاتحة والداكنة. -
GlobalStyles
يحتوي هذا على الأنماط العامة للمستند بأكمله. -
Toggler
هذا يحمل عنصر الزر الذي يبدل الوظيفة. -
useDarkMode
يتعامل هذا الخطاف المخصص مع المنطق الكامن وراء تغيير السمة واستمرار موضوعنا في التخزين المحلي.
مكون الموضوع
في مجلد src
، سترى المكونات في مجلد components
. قم بإنشاء ملف Themes.js
وأضف التعليمات البرمجية التالية إليه.
export const lightTheme = { body: '#FFF', text: '#363537', toggleBorder: '#FFF', background: '#363537', } export const darkTheme = { body: '#363537', text: '#FAFAFA', toggleBorder: '#6B8096', background: '#999', }
هنا ، قمنا بتعريف وتصدير كائنات lightTheme
و darkTheme
ذات متغيرات لونية مميزة. لا تتردد في تجربة المتغيرات وتخصيصها لتناسبك.
مكون globalStyles
بالبقاء في مجلد components
، قم بإنشاء ملف globalStyles.js
، وأضف الكود التالي:
import { createGlobalStyle} from "styled-components" export const GlobalStyles = createGlobalStyle` body { background: ${({ theme }) => theme.body}; color: ${({ theme }) => theme.text}; font-family: Tahoma, Helvetica, Arial, Roboto, sans-serif; transition: all 0.50s linear; } `
لقد قمنا باستيراد createGlobalStyle
من مكونات مصممة. تحل طريقة createGlobalStyle
محل طريقة injectionGlobal التي تم إهمالها الآن من نسخة مكونة من نمط 3. تنشئ هذه الطريقة مكون React ، والذي عند إضافته إلى شجرة المكونات الخاصة بك ، سيضخ أنماطًا عامة في المستند ، في حالتنا ، App.js
قمنا بتعريف مكون GlobalStyle
بتعيين خصائص background
color
للقيم من كائن السمة. وبالتالي ، في كل مرة نقوم فيها بتبديل مفتاح التبديل ، ستتغير القيم اعتمادًا على السمة الداكنة أو كائنات السمة الفاتحة التي نمررها إلى ThemeProvider
(والتي سيتم إنشاؤها لاحقًا ، مع تقدمنا).
تتيح خاصية الانتقال البالغة 0.50s
هذا التغيير بشكل أكثر سلاسة ، بحيث يمكننا أثناء التبديل ذهابًا وإيابًا رؤية التغييرات تحدث.
إنشاء وظيفة تبديل السمة
لتنفيذ وظيفة تبديل السمة ، نحتاج إلى إضافة بضعة أسطر فقط من التعليمات البرمجية. في ملف App.js
، أضف الكود التالي (لاحظ أن الكود المميز هو ما يجب عليك إضافته):
import React, { useState, useEffect } from "react";
import {ThemeProvider} from "styled-components"; import { GlobalStyles } from "./components/Globalstyle"; import { lightTheme, darkTheme } from "./components/Themes"
import "./App.css"; import dummyData from "./data"; import CardList from "./components/CardList"; const App = () => { const [videos, setVideos] = useState([]);
const [theme, setTheme] = useState('light'); const themeToggler = () => { theme === 'light' ? setTheme('dark') : setTheme('light') }
useEffect(() => { const timer = setTimeout(() => { setVideos(dummyData); }, 1000); return () => clearTimeout(timer); }, []); return (
<ThemeProvider theme={theme === 'light' ? lightTheme : darkTheme}> <> <GlobalStyles/>
<div className="App">
<button onClick={themeToggler}>Switch Theme</button>
{ videos.map((list, index) => { return ( <section key={index}> <h2 className="section-title">{list.section}</h2> <CardList list={list} /> <hr /> </section> ); })} </div>
</> </ThemeProvider>
); }; export default App;
الرمز المميز هو الرمز الذي تمت إضافته مؤخرًا إلى App.js
لقد قمنا باستيراد ThemeProvider
من styled-components
. يعد ThemeProvider
مكونًا مساعدًا في مكتبة المكونات المصممة يوفر دعمًا لها. يقوم هذا المكون المساعد بحقن سمة في كل مكونات React الموجودة أسفل نفسه عبر واجهة برمجة تطبيقات السياق.
في شجرة العرض ، ستتمتع جميع المكونات المصممة بإمكانية الوصول إلى السمة المقدمة ، حتى عندما تكون متعددة المستويات في العمق. تحقق من قسم “Theming”.
بعد ذلك ، نستورد غلاف GlobalStyle
من ./components/Globalstyle
. أخيرًا ، من الأعلى ، نقوم باستيراد كائنات lightTheme
و darkTheme
من ./components/Themes
.

لكي نتمكن من إنشاء طريقة تبديل ، نحتاج إلى حالة تحمل قيمة اللون الأولية لموضوعنا. لذلك ، ننشئ حالة theme
، ونضبط الحالة الأولية على light
، باستخدام خطاف useState
.
الآن ، لوظيفة التبديل.
تستخدم طريقة themeToggler
عاملاً ثلاثيًا للتحقق من حالة theme
، وتقوم بالتبديل بين الظلام أو الفاتح بناءً على قيمة الشرط.
ThemeProvider
، مكون مساعد على غرار المكونات ، يلف كل شيء في بيان return
ويحقن أي مكونات تحته. تذكر أن GlobalStyles
بنا تضخ أنماطًا عالمية في مكوناتنا ؛ ومن ثم ، يتم استدعاؤه داخل مكون غلاف ThemeProvider
.
أخيرًا ، أنشأنا زرًا بحدث onClick
الذي يعين طريقة themeToggler
بنا إليه.
دعونا نرى النتيجة حتى الآن.

يحتاج ملف App.js
إلى إعادة هيكلة ؛ الكثير من كودها ليس جافًا. (DRY تعني "لا تكرر نفسك" ، وهو مبدأ أساسي لتطوير البرامج يهدف إلى تقليل التكرار.) يبدو أن كل المنطق موجود في App.js
؛ إنها ممارسة جيدة لفصل منطقنا من أجل الوضوح. لذلك ، سننشئ مكونًا يتعامل مع وظيفة التبديل.
تبديل المكون
لا يزال داخل مجلد components
، قم بإنشاء ملف Toggler.js
، وأضف الكود التالي إليه:
import React from 'react' import { func, string } from 'prop-types'; import styled from "styled-components" const Button = styled.button` background: ${({ theme }) => theme.background}; border: 2px solid ${({ theme }) => theme.toggleBorder}; color: ${({ theme }) => theme.text}; border-radius: 30px; cursor: pointer; font-size:0.8rem; padding: 0.6rem; } \`; const Toggle = ({theme, toggleTheme }) => { return ( <Button onClick={toggleTheme} > Switch Theme </Button> ); }; Toggle.propTypes = { theme: string.isRequired, toggleTheme: func.isRequired, } export default Toggle;
للحفاظ على ترتيب الأشياء ، قمنا بتصميم زر التبديل الخاص بنا في مكون Toggle
، باستخدام الوظيفة styled
من المكونات المصممة.
هذا محض للعرض. يمكنك تصميم الزر كما تراه مناسبًا.
داخل مكون Toggle
، نقوم بتمرير خاصيتين:
- يوفر
theme
الموضوع الحالي (فاتح أو غامق) ؛ - سيتم استخدام وظيفة
toggleTheme
للتبديل بين السمات.
بعد ذلك ، نعيد مكون Button
ونخصص وظيفة toggleTheme
لحدث onClick
.
أخيرًا ، نستخدم propTypes
لتحديد أنواعنا ، مما يضمن أن theme
عبارة عن string
isRequired
، في حين أن موضوعنا toggleTheme
هو func
و isRequired
.
استخدام الخطافات المخصصة ( useDarkMode
)
عند إنشاء تطبيق ، تعد قابلية التوسع أمرًا بالغ الأهمية ، مما يعني أن منطق العمل لدينا يجب أن يكون قابلاً لإعادة الاستخدام ، حتى نتمكن من استخدامه في العديد من الأماكن وحتى في مشاريع مختلفة.
هذا هو السبب في أنه سيكون من الرائع نقل وظيفة التبديل الخاصة بنا إلى مكون منفصل. لذلك ، سنقوم بإنشاء خطاف مخصص خاص بنا.
دعنا ننشئ ملفًا جديدًا باسم useDarkMode.js
في مجلد components
، وننقل منطقنا إلى هذا الملف ، مع بعض التعديلات. أضف الكود التالي إلى الملف:
import { useEffect, useState } from 'react'; export const useDarkMode = () => { const [theme, setTheme] = useState('light'); const setMode = mode => { window.localStorage.setItem('theme', mode) setTheme(mode) }; const themeToggler = () => { theme === 'light' ? setMode('dark') : setMode('light') }; useEffect(() => { const localTheme = window.localStorage.getItem('theme'); localTheme && setTheme(localTheme) }, []); return [theme, themeToggler] };
لقد أضفنا بعض الأشياء هنا.
-
setMode
نستخدمlocalStorage
بين الجلسات في المتصفح. لذلك ، إذا اختار المستخدم المظهر الداكن أو الفاتح ، فهذا ما سيحصل عليه عند زيارته التالية للتطبيق أو إذا أعاد تحميل الصفحة. ومن ثم ، تحدد هذه الوظيفة حالتنا وتمريرtheme
إلىlocalStorage
. -
themeToggler
تستخدم هذه الوظيفة عامل تشغيل ثلاثي للتحقق من حالة الموضوع والتبديل بين الظلام أو الضوء بناءً على حقيقة الحالة. -
useEffect
لقد قمنا بتنفيذ الخطافuseEffect
للتحقق من تثبيت المكون. إذا كان المستخدم قد اختار سمة مسبقًا ، فسنمررها إلى وظيفةsetTheme
بنا. في النهاية ، سنعودtheme
، الذي يحتوي علىtheme
المختارة ووظيفةthemeToggler
للتبديل بين الأوضاع.
أعتقد أنك ستوافق على أن مكون الوضع المظلم الخاص بنا يبدو أنيقًا.
دعنا ننتقل إلى App.js
لمعرفة اللمسات الأخيرة.
import React, { useState, useEffect } from "react"; import {ThemeProvider} from "styled-components";
import {useDarkMode} from "./components/useDarkMode"
import { GlobalStyles } from "./components/Globalstyle"; import { lightTheme, darkTheme } from "./components/Themes" import Toggle from "./components/Toggler" import "./App.css"; import dummyData from "./data"; import CardList from "./components/CardList"; const App = () => { const [videos, setVideos] = useState([]);
const [theme, themeToggler] = useDarkMode(); const themeMode = theme === 'light' ? lightTheme : darkTheme;
useEffect(() => { const timer = setTimeout(() => { setVideos(dummyData); }, 1000); return () => clearTimeout(timer); }, []); return (
<ThemeProvider theme={themeMode}>
<> <GlobalStyles/> <div className="App">
<Toggle theme={theme} toggleTheme={themeToggler} />
{ videos.map((list, index) => { return ( <section key={index}> <h2 className="section-title">{list.section}</h2> <CardList list={list} /> <hr /> </section> ); })} </div> </> </ThemeProvider> ); }; export default App;
تمت إضافة الرمز المميز حديثًا إلى App.js
أولاً ، نقوم باستيراد الخطاف المخصص الخاص بنا ، وندمر theme
ودعائم themeToggler
، ونقوم بتعيينها باستخدام وظيفة useDarkMode
.
لاحظ أن طريقة useDarkMode
تحل محل حالة theme
الخاصة بنا ، والتي كانت في البداية في App.js
نعلن عن متغير themeMode
، والذي يعرض إما سمة فاتحة أو داكنة بناءً على حالة وضع theme
في ذلك الوقت.
الآن ، تم تعيين مكون غلاف ThemeProvider
بنا لمتغير themeMode
الذي تم إنشاؤه مؤخرًا إلى خاصية theme
.
وأخيرًا ، بدلاً من الزر العادي ، نمرر في مكون Toggle
.
تذكر أنه في مكون Toggle
الخاص بنا ، قمنا بتعريف زر وتصميمه وقمنا بتمرير كل من theme
و toggleTheme
إليهم كدعامات. لذا ، كل ما يتعين علينا القيام به هو تمرير هذه الدعائم بشكل مناسب إلى مكون Toggle
، والذي سيكون بمثابة زرنا في App.js
نعم! يتم تعيين الوضع المظلم لدينا ، ويستمر ، ولا يتغير اللون عند تحديث الصفحة أو زيارتها في علامة تبويب جديدة.
دعونا نرى النتيجة قيد التنفيذ:

كل شيء تقريبًا يعمل بشكل جيد ، ولكن هناك شيء واحد صغير يمكننا القيام به لجعل تجربتنا رائعة. قم بالتبديل إلى النسق الداكن ثم أعد تحميل الصفحة. هل ترى أن اللون الأزرق في الزر يتم تحميله قبل اللون الرمادي للحظة وجيزة؟ يحدث ذلك لأن خطاف useState
بنا يبدأ موضوع light
في البداية. بعد ذلك ، يتم تشغيل useEffect
، والتحقق من localStorage
، وبعد ذلك فقط يضبط theme
على dark
. دعنا ننتقل إلى الخطاف المخصص useDarkMode.js
ونضيف القليل من التعليمات البرمجية:
import { useEffect, useState } from 'react'; export const useDarkMode = () => { const [theme, setTheme] = useState('light');
const [mountedComponent, setMountedComponent] = useState(false)
const setMode = mode => { window.localStorage.setItem('theme', mode) setTheme(mode) }; const themeToggler = () => { theme === 'light' ? setMode('dark') : setMode('light') }; useEffect(() => { const localTheme = window.localStorage.getItem('theme'); localTheme ? setTheme(localTheme) : setMode('light')
setMountedComponent(true)
}, []); return [theme, themeToggler,
}, []); return [theme, themeToggler,
mountedComponent
]
};
الكود المميز هو الرمز الوحيد المضاف إلى useDarkMode.js
. لقد أنشأنا حالة أخرى باسم mountedComponent
بتعيين القيمة الافتراضية على false
باستخدام الخطاف useState
. بعد ذلك ، داخل خطاف useEffect
، قمنا بضبط الحالة mountedComponent
على true
باستخدام setMountedComponent
. أخيرًا ، في مصفوفة return
، نقوم بتضمين الحالة mountedComponent
.
أخيرًا ، دعنا نضيف القليل من التعليمات البرمجية في App.js
لجعل كل شيء يعمل.
import React, { useState, useEffect } from "react"; import {ThemeProvider} from "styled-components"; import {useDarkMode} from "./components/useDarkMode" import { GlobalStyles } from "./components/Globalstyle"; import { lightTheme, darkTheme } from "./components/Themes" import Toggle from "./components/Toggler" import "./App.css"; import dummyData from "./data"; import CardList from "./components/CardList"; const App = () => { const [videos, setVideos] = useState([]);
const [theme, themeToggler, mountedComponent] = useDarkMode();
const themeMode = theme === 'light' ? lightTheme : darkTheme; useEffect(() => { const timer = setTimeout(() => { setVideos(dummyData); }, 1000); return () => clearTimeout(timer); }, []);
if(!mountedComponent) return <div/>
return ( <ThemeProvider theme={themeMode}> <> <GlobalStyles/> <div className="App"> <Toggle theme={theme} toggleTheme={themeToggler} /> { videos.map((list, index) => { return ( <section key={index}> <h2 className="section-title">{list.section}</h2> <CardList list={list} /> <hr /> </section> ); })} </div> </> </ThemeProvider> ); }; export default App;
لقد أضفنا الحالة mountedComponent
بنا كدعم في خطاف useDarkMode
بنا ، وقمنا بفحص ما إذا كان المكون الخاص بنا قد تم تركيبه ، لأن هذا ما يحدث في خطاف useEffect
. إذا لم يحدث ذلك بعد ، فسنعرض div
فارغًا.
دعونا نرى نتيجة صفحة الويب ذات الوضع المظلم.

الآن ، ستلاحظ أنه أثناء وجودك في الوضع المظلم ، عند إعادة تحميل الصفحة ، لا يتغير لون الزر.
خاتمة
أصبح الوضع الداكن على نحو متزايد من تفضيلات المستخدم ، وأصبح تنفيذه في تطبيق ويب React أسهل كثيرًا عند استخدام ThemeProvider
في المكونات المصممة. انطلق واختبر المكونات المصممة أثناء تنفيذ الوضع المظلم ؛ يمكنك إضافة رموز بدلاً من زر.
يرجى مشاركة ملاحظاتك وتجربتك مع ميزة السمات في المكونات المصممة في قسم التعليقات أدناه. أحب أن أرى ما توصلت إليه!
المستودع الداعم لهذه المقالة متاح على GitHub. تحقق أيضًا من ذلك على CodeSandbox.
مراجع
- "الوثائق" ، على غرار المكونات
- "أنشئ وضعًا داكنًا لتطبيقك باستخدام Styled Components" ، Tom Nolan ، Medium