تعلم التفاعل عن طريق بناء مولد ميمي
الميمات رائعة - إنها طريقة ممتعة لوصف الأفكار والآراء. لذلك ليس من قبيل المصادفة أنني اخترت تطبيق مولد meme كمشروع تتويجا في دورة React المجانية على Scrimba. يعمل التطبيق عن طريق سحب صورة meme عشوائية من واجهة برمجة تطبيقات ووضع النص فوقها لإنشاء ميمي خاص بك ومخصص.
لذلك في هذه المقالة ، سأقدم لك دليلًا تفصيليًا لإنشاء التطبيق. إذا شعرت بالارتباك ، يمكنك أيضًا اتباع هذه الخطوات في دورة Scrimba ، بدءًا من هذه المحاضرة.
ثم إذا كنت تحب أسلوبي التدريسي وكنت في حالة مزاجية لتحدي أكثر صرامة بعد إكمال هذا البرنامج التعليمي ، فيرجى مراجعة الدورة التدريبية المتقدمة القادمة على Scrimba.
ملاحظة: يجب أن تكون بالفعل على دراية ببعض المفاهيم الأساسية لـ React ، مثل المكونات والحالة والدواعي وطرق دورة الحياة. أيضًا ، لا يستخدم هذا البرنامج التعليمي الخطافات ، ولكن في الدورة التدريبية القادمة سنغطي الخطافات بعمق ونحصل على الكثير من التدريبات على استخدامها.
1. إنشاء النموذج المعياري وعرض أحد مكونات التطبيق
أول شيء يتعين علينا القيام به هو إنشاء الكود المعياري للتطبيق. للقيام بذلك، ونحن استيراد React
و ReactDOM
واستخدام ReactDOM
لتقديم مكون يسمى App
، وهو ما سيخلق لاحقا. ثم نضع App
المكون في "الجذر". نقوم أيضًا بالاستيراد App
من ملفه "./App"
، والذي سننشئه قريبًا.
// index.js import React from 'react'; import ReactDOM from 'react-dom'; import App from './App'; ReactDOM.render(, document.getElementById('root'));
ثم نقوم بإنشاء App.js
ملفنا. في ذلك ، نقوم بإنشاء مكون وظيفي يسمى App
، في الوقت الحالي ، يقوم بإرجاع بسيط
. ثم نقوم بتصديره. ال
يتيح لنا التحقق من عرض التطبيق بشكل صحيح على الشاشة.
import React from 'react'; function App() { return Hello world!
; } export default App;
الناتج الناتج هو هذا:
2. إنشاء مكونات Header و MemeGenerator
بعد ذلك ، نقوم بإنشاء مكونات Header و MemeGenerator. سيعرض الرأس العناصر فقط ، بينما سيتصل MemeGenerator بواجهة برمجة التطبيقات ويحتفظ بالبيانات في الحالة.
لنبدأ بإنشاء Header.js
الملف. نظرًا لأن Header هو مكون يُستخدم فقط للعرض ، فيجب أن يكون مكونًا وظيفيًا. في الوقت الحالي ، يجب أن يُرجع المكون ملف
. بعد إنشائه ، نقوم بتصدير Header.
import React from 'react'; function Header() { return HEADER
; } export default Header;
بعد ذلك ، نقوم بإنشاء MemeGenerator.js
الملف. نظرًا لأن MemeGenerator
المكون سيحتفظ بالبيانات وإجراء مكالمات إلى واجهة برمجة التطبيقات ، فيجب أن يكون مكون فئة. ما زلنا بحاجة إلى استيراد React ، وبما أنه سيكون مكونًا لفئة ، فسنقوم أيضًا بالاستيراد Component
(وهو استيراد مسمى).
يحتاج MemeGenerator إلى constructor()
أي مكالمات ولأنه super()
سيكون في حالة تعليق ، فإننا نضيف بعض الحالة الفارغة إليه الآن. كما هو الحال في مكون الرأس ، نقدم ملفًا بسيطًا
لتبدأ. ثم نقوم بتصدير MemeGenerator.
import React, { Component } from 'react'; class MemeGenerator extends Component { constructor() { super(); this.state = {}; //empty state } render() { return MEME GENERATOR SECTION
; } } export default MemeGenerator;
الآن ، نقوم باستيراد كل من Header و MemeGenerator App.js
وإنشاء مثيل لكل منهما في مكون التطبيق الخاص بنا. من أجل عرض المكونات بشكل صحيح ، نقوم بلفها في ملف .
import React from 'react'; import Header from './Header'; import MemeGenerator from './MemeGenerator'; function App() { return ( ); } export default App;
3. استكمال مكون الرأس.
To complete the component, we add a trollface image by inserting an
tag and setting the src to the image's URL. We then add a
tag with the name of our app and wrap them both in the semantic HTML5 tag.
function Header() { return ( ![Problem?]()
Meme Generator
); }
As styling is outside the scope of this course, the CSS styles have already been created and applied to the tag. The result is this:
That said, learners can always play around with the styling and hone their CSS skills by themselves. With the now complete, the rest of the challenge will take place in
4. Initializing state
We now have to initialize state so that it saves a top text, a bottom text and a random image, which is already supplied.
To do this, we build up the empty object we placed in the when we originally built it. We initialize
topText
and bottomText
as empty strings and randomImg
as the provided URL.
class MemeGenerator extends Component { constructor() { super(); this.state = { topText: '', bottomText: '', randomImg: '//i.imgflip.com/1bij.jpg' }; } }
5. Making the API call
Next, we make an API call to the provided URL and save the data returned (which is an array found in response.data.memes
) to a new state property called allMemeImgs
.
When we need to load data from an endpoint to use in our component, a good place to make the request is the componentDidMount()
lifecycle method. As soon as the component mounts, we use the native fetch()
function to call to the provided URL.
componentDidMount() { fetch("//api.imgflip.com/get_memes") }
This returns a promise which we turn into a Javascript object with the .json()
method.
componentDidMount() { fetch("//api.imgflip.com/get_memes") .then(response => response.json()) }
Then we get the response which is useful to us by pulling the memes array from response.data
.
componentDidMount() { fetch("//api.imgflip.com/get_memes") .then(response => response.json()) .then(response => { const { memes } = response.data }) }
Now, we save the results to a new state property called allMemeImgs
. To do this, we initialize allMemeImgs
as an empty array.
this.state = { topText: '', bottomText: '', randomImg: '//i.imgflip.com/1bij.jpg', allMemeImgs: [] };
Now, back in componentDidMount()
, we set state. As we are not interested in what the previous state was, we set allMemeImgs
to memes.
componentDidMount() { fetch("//api.imgflip.com/get_memes") .then(response => response.json()) .then(response => { const { memes } = response.data this.setState({ allMemeImgs: memes }) }) }
To ensure that it works, we console.log
the first item, which looks something like this:
Here's an overview of the entire componentDidMount()
function.
componentDidMount() { //ensure that data is fetched at the beginning fetch("//api.imgflip.com/get_memes") //call to URL .then(response => response.json()) //turn promise into JS object .then(response => { const { memes } = response.data //pull memes array from response.data console.log(memes[0]) // check data is present this.setState({ allMemeImgs: memes }) // set allMemeImgs state }) }
6. Creating the input form
We now want to create a form which will eventually allow the user to input the top and bottom texts. We do this with an HTML tag and a simple
which says 'Gen'. We style it with the pre-provided CSS.
render() { return ( Gen ) }
7. Adding input fields to the form
Next, it is up to us to add the two input fields (one for the top text and one for the bottom text). The form should be a controlled form, so we will need to add all the attributes needed in order for that to work. We will create the onChange
handler later.
We create two input fields which both have the type text
and appropriate name attributes (topText
and bottomText
). Rather than using labels, we use placeholders: 'Top Text' and 'Bottom Text'.
Lastly, in order to make this a controlled form, we set the value as equal to the current value in state
with {this.state.topText}
and {this.state.bottomText}
.
render() { return ( Gen ) }
8. Creating the onChange handler.
Now, we create the onChange handler, which will update the corresponding state on every change of the input field.
First, we create a handleChange()
function which receives an event.
handleChange(event) { }
Now, we set the onChange
of both input fields to equal handleChange
.
Gen
We need to remember to bind the method in the constructor — a common gotcha for React developers.
constructor() { super() this.state = { topText: "", bottomText: "", randomImg: "//i.imgflip.com/1bij.jpg", allMemeImgs: [] } this.handleChange = this.handleChange.bind(this) }
To test the new handleChange()
function, we add a simple console.log
:
handleChange(event) { console.log("Working!") }
If it is correctly firing, you'll see something like this:
Now to fill in the handleChange()
function. To do this, we want to pull the name and value properties from event.target so that we can get the name of the state we are supposed to update (topText
or bottomText
) and the value which is typed into the box.
handleChange(event) { const { name, value } = event.target }
We will now use these to update state. As we are not interested in what the previous state was, we can just provide an object in which we set the [name]
to the value typed into the input field.
handleChange(event) { const {name, value} = event.target this.setState({ [name]: value }) }
9. Displaying a meme image alongside the top and bottom text
We now want the app to display a meme image alongside the top and bottom text. We insert an
tag underneath the and set the
randomImg
which we initialized as its source by using src={this.state.randomImg}
. We then add two
tags which display the corresponding text which is also saved in state. All of this is wrapped in a div
and styled with the pre-provided meme
class.
{this.state.topText}
{this.state.bottomText}
We can now test the app by typing into the text boxes. As state is being correctly set on every keystroke, the text displayed on the image changes each time we type.
10. Displaying a random meme image alongside the Top and Bottom text
Now, we need to create a method which displays a meme image which it randomly chooses from our allMemeImgs
array when the Gen
button is clicked. The property on the chosen image in the array is .url
.
We can break this task down into smaller parts.
Firstly, we set the form's onSubmit
to equal the name of our new method, which we will call handleSubmit()
.
We now create the handleSubmit()
function above the render()
function. We need to preventDefault on the event, otherwise, the method will try to refresh the page.
handleSubmit(event) { event.preventDefault() }
We also need to bind handleSubmit()
in our constructor()
.
constructor() { super() this.state = { topText: "", bottomText: "", randomImg: "//i.imgflip.com/1bij.jpg", allMemeImgs: [] } this.handleChange = this.handleChange.bind(this) this.handleSubmit = this.handleSubmit.bind(this) }
Now, we need to get a random number, get the meme from that index and set randomImg
to the .url
of the random item.
handleSubmit(event) { event.preventDefault() // get a random int (index in the array) // get the meme from that index // set `randomImg` to the `.url` of the random item I grabbed }
To get a random number, we use Math.floor(Math.random)
. To make sure that it is one of the indices in our allMemeImgs
array, we multiply by the length of the array.
const randNum = Math.floor(Math.random() * this.state.allMemeImgs.length);
We now set randMemeImg
to equal allMemeImgs
, with the index of allMemeImgs
as the randNum
we just got. We then add .url
to the end of it.
const randMemeImg = this.state.allMemeImgs[randNum].url;
Now, all we need to do is update the state by updating the randomImg property with randMemeImg
.
this.setState({ randomImg: randMemeImg });
Our completed handleSubmit()
function looks like this:
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 }) }
Completed Meme Generator
We now have completed the meme generator app, and get a different image every time we hit the Gen
button, which is then overlaid with the text we input.
لتعزيز تعلمنا ، يمكننا اللعب بالرمز ومعرفة ما إذا كان بإمكاننا تحسينه ، أو محاولة الحصول على صور من واجهة برمجة تطبيقات مختلفة. بالنسبة لبعض الممارسات الشاقة حقًا ، يمكننا حتى حذف جميع التعليمات البرمجية ومحاولة بنائها مرة أخرى من البداية.
تهانينا على متابعة البرنامج التعليمي وتعلم جميع المهارات المستخدمة في هذا المشروع.
وإذا كنت مستعدًا لذلك ، فراجع الدورة التدريبية المتقدمة القادمة ، حيث ستأخذك إلى المستوى الاحترافي في React!