في هذا الجزء من ترجمة دورة React التدريبية ، يُطلب منك إنشاء مولد ميمي.

→
الجزء 1: نظرة عامة على الدورة ، وأسباب شعبية React ، ReactDOM و JSX→
الجزء 2: المكونات الوظيفية→
الجزء 3: ملفات المكونات ، هيكل المشروع→
الجزء 4: مكونات الوالدين والطفل→
الجزء 5: بدء العمل في تطبيق TODO ، أساسيات التصميم→
الجزء 6: حول بعض ميزات الدورة ، JSX وجافا سكريبت→
الجزء 7: الأنماط المضمنة→
الجزء 8: مواصلة العمل على تطبيق TODO ، الإلمام بخصائص المكونات→
الجزء 9: خصائص المكون→
الجزء 10: ورشة عمل حول العمل مع خصائص المكون والتصميم→
الجزء 11: توليد العلامات الديناميكية وطريقة صفائف الخريطة→
الجزء 12: ورشة العمل ، المرحلة الثالثة من العمل على طلب TODO→
الجزء 13: المكونات القائمة على الفصل→
الجزء 14: ورشة عمل حول المكونات القائمة على الفصل ، وحالة المكون→
الجزء 15: ورش العمل الصحية المكونة→
الجزء 16: المرحلة الرابعة من العمل على طلب TODO ، التعامل مع الأحداث→
الجزء 17: المرحلة الخامسة من العمل على تطبيق TODO ، وتعديل حالة المكونات→
الجزء 18: المرحلة السادسة من العمل على طلب TODO→
الجزء 19: طرق دورة حياة المكونالجزء 20: الدرس الأول في التقديم الشرطي→
الجزء 21: الدرس الثاني وورشة العمل حول التقديم الشرطي→
الجزء 22: المرحلة السابعة من العمل على تطبيق TODO ، وتنزيل البيانات من مصادر خارجية→
الجزء 23: الدرس الأول حول العمل مع النماذج→
الجزء 24: نماذج الدرس الثاني→
الجزء 25: ورشة عمل حول العمل مع النماذج→
الجزء 26: بنية التطبيق ، نمط الحاوية / المكون→
الجزء 27: مشروع المقررالدرس 45. مشروع المقرر. ميمي مولد
→
الأصللذلك وصلنا إلى مشروع الدورة. دعونا إنشاء تطبيق من شأنه أن يولد الميمات. لنبدأ بمشروع إنشاء تطبيق رد فعل قياسي تم إنشاؤه باستخدام هذا الأمر:
npx create-react-app meme-generator
هنا يمكنك العثور على معلومات حول ميزات استخدامه.
أثناء العمل في هذا المشروع ، سيُطلب منك تنفيذ بعض أجزائه بنفسك ، ثم قراءة التفسيرات المتعلقة بها. يحتوي المشروع القياسي بالفعل على رمز
App.js
الموجود ، على وجه الخصوص ، في
App.js
index.js
و
App.js
يمكنك إزالة هذا الرمز تمامًا ومحاولة كتابته بنفسك من أجل اختبار نفسك في تنفيذ الآليات القياسية لتطبيقات React.
في هذا المشروع ، أنت مدعو لاستخدام الأنماط التالية:
* { box-sizing: border-box; } body { margin: 0; background-color: whitesmoke; } header { height: 100px; display: flex; align-items: center; background: #6441A5; background: -webkit-linear-gradient(to right, #2a0845, #6441A5); background: linear-gradient(to right, #2a0845, #6441A5); } header > img { height: 80%; margin-left: 10%; } header > p { font-family: VT323, monospace; color: whitesmoke; font-size: 50px; margin-left: 60px; } .meme { position: relative; width: 90%; margin: auto; } .meme > img { width: 100%; } .meme > h2 { position: absolute; width: 80%; text-align: center; left: 50%; transform: translateX(-50%); margin: 15px 0; padding: 0 5px; font-family: impact, sans-serif; font-size: 2em; text-transform: uppercase; color: white; letter-spacing: 1px; text-shadow: 2px 2px 0 #000, -2px -2px 0 #000, 2px -2px 0 #000, -2px 2px 0 #000, 0 2px 0 #000, 2px 0 0 #000, 0 -2px 0 #000, -2px 0 0 #000, 2px 2px 5px #000; } .meme > .bottom { bottom: 0; } .meme > .top { top: 0; } .meme-form { width: 90%; margin: 20px auto; display: flex; justify-content: space-between; } .meme-form > input { width: 45%; height: 40px; } .meme-form > button { border: none; font-family: VT323, monospace; font-size: 25px; letter-spacing: 1.5px; color: white; background: #6441A5; } .meme-form > input::-webkit-input-placeholder { font-family: VT323, monospace; font-size: 25px; text-align: cen } .meme-form > input::-moz-placeholder { font-family: VT323, monospace; font-size: 25px; text-align: cen } .meme-form > input:-ms-input-placeholder { font-family: VT323, monospace; font-size: 25px; text-align: cen } .meme-form > input:-moz-placeholder { font-family: VT323, monospace; font-size: 25px; text-align: cen }
يمكن تضمين هذه الأنماط في ملف
index.css
بالفعل في المشروع
index.css
في ملف
index.js
.
لذلك ، بناءً على افتراض أن ملفات
index.js
و
App.js
فارغة الآن ، فأنت بصفتك المهمة الأولى ، مدعوة لكتابة رمز
index.js
،
App.js
بإنشاء أبسط مكون في
App.js
إلى
index.js
.
إليك ما يجب أن يظهر في
index.js
:
import React from "react" import ReactDOM from "react-dom" import './index.css' import App from "./App" ReactDOM.render(<App />, document.getElementById("root"))
نحن هنا نستورد
ReactDOM
و
ReactDOM
،
ReactDOM
الأنماط من
index.css
App
. بعد ذلك ، باستخدام طريقة
ReactDOM.render()
، نقوم
ReactDOM.render()
ما
ReactDOM.render()
مكون
App
في عنصر صفحة
index.html
بمعرف
root
(
<div id="root"></div>
).
إليك ما قد يبدو
App.js
ملف
App.js
:
import React from "react" function App() { return ( <h1>Hello world!</h1> ) } export default App
هنا قدم الآن أبسط عنصر وظيفي.
في هذه المرحلة ، يبدو المشروع كما هو موضح أدناه.
تطبيق في المتصفحقم الآن بإنشاء مكونين جديدين ، في ملفين تتطابق أسماؤهما مع أسماء المكونات:
- مكون
Header
الذي سيتم استخدامه لعرض رأس التطبيق. - مكون
MemeGenerator
، والذي سيتم فيه حل المهام الرئيسية المخصصة للتطبيق. وهي ، سيتم إجراء مكالمات إلى API هنا. سيتم تخزين بيانات التطبيق هنا.
النظر في الوظائف التي يتم تعيينها لهذه المكونات ، والتفكير في ما ينبغي أن تكون.
فيما يلي محتويات ملف
Header.js
:
import React from "react" function Header() { return ( <h1>HEADER</h1> ) } export default Header
نظرًا لأن هذا المكون سيتم استخدامه فقط لعرض رأس التطبيق ، فقد قمنا بتصميمه كمكون وظيفي.
هنا هو رمز ملف
MemeGenerator.js
:
import React, {Component} from "react" class MemeGenerator extends Component { constructor() { super() this.state ={} } render() { return ( <h1>MEME GENERATOR SECTION</h1> ) } } export default MemeGenerator
هنا ، مع الأخذ في الاعتبار المهام التي من المفترض حلها عن طريق مكون
MemeGenerator
، سوف نستخدم مكونًا يعتمد على الفصل. يوجد مُنشئ هنا يمكننا من خلاله تهيئة الحالة بكائن فارغ.
بعد إنشاء هذه الملفات ،
App.js
في
App.js
الترميز من المكون الوظيفي
App.js
، والذي يستخدم مثيلات هذه المكونات ، دون أن ننسى أنه إذا قام المكون الوظيفي بإرجاع عدة عناصر ، فيجب أن يتم لفها في شيء ما. في حالتنا ، هذه هي
<div>
. هنا هو رمز
App.js
المحدث:
import React from "react" import Header from "./Header" import MemeGenerator from "./MemeGenerator" function App() { return ( <div> <Header /> <MemeGenerator /> </div> ) } export default App
تحقق من مظهر التطبيق.
تطبيق في المتصفحالآن دعونا نعمل على مكون
Header
. هنا سنستخدم العنصر الدلالية HTML5
<header>
. سوف تحتوي هذه العلامة على الصورة والنص. الآن
Header.js
رمز ملف
Header.js
كما يلي:
import React from "react" function Header() { return ( <header> <img src="http://www.pngall.com/wp-content/uploads/2016/05/Trollface.png" alt="Problem?" /> <p>Meme Generator</p> </header> ) } export default Header
إليك كيفية تغيير مظهر التطبيق.
تطبيق في المتصفحتم تصميم عنوان التطبيق وفقًا للأنماط
index.js
مسبقًا في
index.js
. اكتمل الآن العمل على مكون
Header
.
سوف نستمر في التعامل مع مكون
MemeGenerator
. تمت دعوتك الآن لتهيئة حالة هذا المكون بشكل مستقل عن طريق كتابة البيانات التالية عليه:
- النص المعروض في الجزء العلوي من ميمي (خاصية النص العلوي).
- النص المعروض في أسفل meme (خاصية
bottomText
). - صورة عشوائية (خاصية
randomImage
تحتاج إلى تهيئة مع الرابط http://i.imgflip.com/1bij.jpg ).
هذا هو ما سيكون رمز
MemeGenerator.js
بعد تهيئة الحالة:
import React, {Component} from "react" class MemeGenerator extends Component { constructor() { super() this.state = { topText: "", bottomText: "", randomImg: "http://i.imgflip.com/1bij.jpg" } } render() { return ( <h1>MEME GENERATOR SECTION</h1> ) } } export default MemeGenerator
الآن لن يتأثر مظهر التطبيق.
سوف نستخدم المكالمات إلى واجهة برمجة التطبيقات ، والتي تعرض مجموعة من الكائنات التي تحتوي على روابط للصور ، بناءً على الميمات التي يمكن إنشاؤها. في هذه المرحلة من العمل في المشروع ، فأنت مدعو لتنفيذ الوظيفة التالية في مكون
MemeGenerator
:
هنا ، لجعلها أكثر وضوحًا ، تم إرجاع جزء من بيانات JSON عند الوصول إلى واجهة برمجة التطبيقات هذه:
{ "success":true, "data":{ "memes":[ { "id":"112126428", "name":"Distracted Boyfriend", "url":"https:\/\/i.imgflip.com\/1ur9b0.jpg", "width":1200, "height":800, "box_count":3 }, { "id":"87743020", "name":"Two Buttons", "url":"https:\/\/i.imgflip.com\/1g8my4.jpg", "width":600, "height":908, "box_count":2 }, { "id":"129242436", "name":"Change My Mind", "url":"https:\/\/i.imgflip.com\/24y43o.jpg", "width":482, "height":361, "box_count":2 }, …. ] } }
لحل المشكلة المذكورة أعلاه ، من الضروري مراعاة حقيقة أننا نتحدث عن البيانات التي يحتاجها المكون في بداية التطبيق.
لذلك ، لتحميلها ، سوف نلجأ إلى دورة حياة
componentDidMount()
. نحن هنا ، باستخدام طريقة
fetch()
القياسية
fetch()
، نسمي API. يعود الوعد. بعد تحميل البيانات ، سيكون كائن الاستجابة متاحًا لنا ،
memes
مجموعة
memes
منه ونضعها في خاصية الحالة الجديدة
allMemeImgs
، التي تمت تهيئتها باستخدام صفيف فارغ. نظرًا لعدم استخدام هذه البيانات بعد لتكوين شيء معروض على الشاشة ، سنقوم بطباعة العنصر الأول للصفيف على وحدة التحكم للتحقق من التشغيل الصحيح لآلية تحميل البيانات.
هنا هو رمز مكون
MemeGenerator
في هذه المرحلة من العمل:
import React, {Component} from "react" class MemeGenerator extends Component { constructor() { super() this.state = { topText: "", bottomText: "", randomImg: "http://i.imgflip.com/1bij.jpg", allMemeImgs: [] } } componentDidMount() { fetch("https://api.imgflip.com/get_memes") .then(response => response.json()) .then(response => { const {memes} = response.data console.log(memes[0]) this.setState({ allMemeImgs: memes }) }) } render() { return ( <h1>MEME GENERATOR SECTION</h1> ) } } export default MemeGenerator
هذا هو ما يحصل على وحدة التحكم بعد تحميل البيانات بنجاح.
التطبيق في المتصفح ، الإخراج إلى وحدة التحكم للعنصر الأول من مجموعة تحميلهالاحظ أن الصورة موصوفة باستخدام العديد من الخصائص. سنستخدم خاصية
url
فقط ، والتي تتيح الوصول إلى الرابط لتنزيل الصورة.
في بداية الدورة ، تحدثنا عن كيفية ظهور هذا التطبيق.
ميمي مولدعلى وجه الخصوص ، تحتوي الواجهة على مجالين لإدخال النص ، والذي سيتم عرضه في الأجزاء العلوية والسفلية من الصورة. الآن أنت مدعو لاتخاذ ، استنادا إلى التعليمات البرمجية المحدثة لمكون
MemeGenerator
الموضح أدناه ، والذي يختلف عن الرمز أعلاه لهذا المكون في أن يضاف نموذج فارغ هنا ، لإنشاء اثنين من حقول النص ،
topText
و
bottomText
. ضع في اعتبارك أنه يجب إدارة هذه المكونات. أضف السمات الضرورية لهم. قم بإنشاء
onChange
أحداث
onChange
لهذه الحقول التي تحتاج فيها إلى تحديث خصائص الحالة المقابلة عند إدخال نص فيها.
import React, {Component} from "react" class MemeGenerator extends Component { constructor() { super() this.state = { topText: "", bottomText: "", randomImg: "http://i.imgflip.com/1bij.jpg", allMemeImgs: [] } } componentDidMount() { fetch("https://api.imgflip.com/get_memes") .then(response => response.json()) .then(response => { const {memes} = response.data this.setState({ allMemeImgs: memes }) }) } render() { return ( <div> <form className="meme-form"> { // } <button>Gen</button> </form> </div> ) } } export default MemeGenerator
بالمناسبة ، يجب الانتباه إلى أنه من أجل تضمين تعليق في الكود الذي تم إرجاعه بواسطة طريقة
render()
، قمنا بتضمينه بين قوسين مجعدين للإشارة إلى النظام بأنه يجب تفسير هذه القطعة على أنها كود JavaScript.
إليك ما يجب أن تحصل عليه في هذه المرحلة من العمل على التطبيق:
import React, {Component} from "react" class MemeGenerator extends Component { constructor() { super() this.state = { topText: "", bottomText: "", randomImg: "http://i.imgflip.com/1bij.jpg", allMemeImgs: [] } this.handleChange = this.handleChange.bind(this) } componentDidMount() { fetch("https://api.imgflip.com/get_memes") .then(response => response.json()) .then(response => { const {memes} = response.data this.setState({ allMemeImgs: memes }) }) } handleChange(event) { const {name, value} = event.target this.setState({ [name]: value }) } render() { return ( <div> <form className="meme-form"> <input type="text" name="topText" placeholder="Top Text" value={this.state.topText} onChange={this.handleChange} /> <input type="text" name="bottomText" placeholder="Bottom Text" value={this.state.bottomText} onChange={this.handleChange} /> <button>Gen</button> </form> </div> ) } } export default MemeGenerator
الآن ستظهر صفحة التطبيق كالصفحة الموضحة أدناه.
تطبيق في المتصفحبينما يتم عرض الحقول التي تحتوي على نص التعليمات فقط ، فإن إدخال البيانات فيها لا يؤدي إلى تغييرات في الواجهة. للتحقق من التشغيل الصحيح للآليات المطبقة هنا ، يمكنك استخدام الأمر
console.log()
.
الآن سنعمل على جزء التطبيق المسؤول عن عرض صورة meme. تذكر أنه لدينا الآن مجموعة تحتوي على معلومات حول الصور التي تم التخطيط لاستخدامها كأساس للميمات. يجب على التطبيق ، بالضغط على الزر
Gen
، تحديد صورة بشكل عشوائي من هذه المجموعة وتكوين ميمي.
هنا هو رمز محدث لمكون
MemeGenerator
. هنا ، في طريقة
render()
، أسفل رمز وصف النموذج ، يوجد عنصر
<div>
، يتضمن عنصر
<img>
يعرض صورة ، واثنين من عناصر
<h2>
تعرض الملصقات. تم تصميم عنصري
<div>
و
<h2>
باستخدام الأنماط التي أضفناها إلى المشروع في بداية العمل عليه.
import React, {Component} from "react" class MemeGenerator extends Component { constructor() { super() this.state = { topText: "", bottomText: "", randomImg: "http://i.imgflip.com/1bij.jpg", allMemeImgs: [] } this.handleChange = this.handleChange.bind(this) } componentDidMount() { fetch("https://api.imgflip.com/get_memes") .then(response => response.json()) .then(response => { const {memes} = response.data this.setState({ allMemeImgs: memes }) }) } handleChange(event) { const {name, value} = event.target this.setState({ [name]: value }) } render() { return ( <div> <form className="meme-form"> <input type="text" name="topText" placeholder="Top Text" value={this.state.topText} onChange={this.handleChange} /> <input type="text" name="bottomText" placeholder="Bottom Text" value={this.state.bottomText} onChange={this.handleChange} /> <button>Gen</button> </form> <div className="meme"> <img align="center" src={this.state.randomImg} alt="" /> <h2 className="top">{this.state.topText}</h2> <h2 className="bottom">{this.state.bottomText}</h2> </div> </div> ) } } export default MemeGenerator
إليك ما يبدو عليه التطبيق الآن.
تطبيق في المتصفحانتبه إلى حقيقة أن الصورة التي بدأت في تهيئة الحالة معروضة هنا. نحن لا نستخدم الصور المخزنة في خاصية حالة
allMemeImgs
. دعنا نحاول إدخال شيء في حقول النص.
تطبيق في المتصفحكما ترون ، فإن الأنظمة الفرعية للتطبيق المسؤولة عن العمل مع النص تعمل كما هو متوقع. يبقى الآن فقط التأكد من أنه بالضغط على الزر
Gen
، يتم اختيار صورة عشوائية من الصفيف مع بيانات الصورة وتحميلها في عنصر
<img>
، الموجود في الصفحة أسفل حقول إدخال النص.
لتجهيز التطبيق بهذه الميزة - قم بتنفيذ المهمة التالية. قم بإنشاء طريقة تشتعل عند النقر فوق الزر
Gen
يجب أن تحدد هذه الطريقة إحدى الصور التي يتم تخزين المعلومات حولها في خاصية الحالة
allMemeImgs
، ثم تقوم بتنفيذ الإجراءات التي تسمح لك بعرض هذه الصورة في عنصر
<img>
الموجود أسفل حقول إدخال النص.
allMemeImgs
في
allMemeImgs
أن
allMemeImgs
يخزن مجموعة من الكائنات التي تصف الصور ، وأن كل كائن من هذه الصفيف لديه خاصية
url
.
إليك الرمز الذي يوفر حلاً لهذه المشكلة:
import React, {Component} from "react" class MemeGenerator extends Component { constructor() { super() this.state = { topText: "", bottomText: "", randomImg: "http://i.imgflip.com/1bij.jpg", allMemeImgs: [] } this.handleChange = this.handleChange.bind(this) this.handleSubmit = this.handleSubmit.bind(this) } componentDidMount() { fetch("https://api.imgflip.com/get_memes") .then(response => response.json()) .then(response => { const {memes} = response.data this.setState({ allMemeImgs: memes }) }) } handleChange(event) { const {name, value} = event.target this.setState({ [name]: value }) } handleSubmit(event) { event.preventDefault() const randNum = Math.floor(Math.random() * this.state.allMemeImgs.length) const randMemeImg = this.state.allMemeImgs[randNum].url this.setState({ randomImg: randMemeImg }) } render() { return ( <div> <form className="meme-form" onSubmit={this.handleSubmit}> <input type="text" name="topText" placeholder="Top Text" value={this.state.topText} onChange={this.handleChange} /> <input type="text" name="bottomText" placeholder="Bottom Text" value={this.state.bottomText} onChange={this.handleChange} /> <button>Gen</button> </form> <div className="meme"> <img align="center" src={this.state.randomImg} alt="" /> <h2 className="top">{this.state.topText}</h2> <h2 className="bottom">{this.state.bottomText}</h2> </div> </div> ) } } export default MemeGenerator
يمكن تعيين الزر
Gen
معالج حدث يحدث عند النقر فوقه ، كما هو الحال مع أي أزرار أخرى. ومع ذلك ، نظرًا لحقيقة استخدام هذا الزر لإرسال النموذج ، سيكون من الأفضل استخدام
onSubmit
أحداث
onSubmit
للنموذج. في هذا المعالج ،
handleSubmit()
، ندعو طريقة
event.preventDefault()
تأتي فيها لإلغاء إجراءات
event.preventDefault()
النموذج القياسي التي يتم خلالها إعادة تحميل الصفحة. بعد ذلك ، نحصل على رقم عشوائي في النطاق من 0 إلى القيمة المطابقة لمؤشر العنصر الأخير من مجموعة
allMemeImgs
ونستخدم هذا الرقم للإشارة إلى العنصر ذي الفهرس المقابل. بالانتقال إلى العنصر الذي هو الكائن ، نحصل على خاصية
url
لهذا الكائن
randomImg
خاصية الحالة
randomImg
. بعد ذلك ، يتم إعادة تقديم المكون ويتغير مظهر الصفحة.
صفحة التطبيق في المتصفحاكتمل مشروع الدورة.
النتائج
في هذا الدرس ، قمت بإنشاء تطبيق يستخدم ما تعلمته أثناء إتقان React. في المرة القادمة سوف نتحدث عن تطوير تطبيقات React الحديثة ومناقشة أفكار المشروع ، والتنفيذ والتي يمكنك ممارسة العمل مع React.
أعزائي القراء! هل واجهت أي صعوبات أثناء إكمال هذا المشروع التدريبي؟