发布于 2026-01-06 0 阅读
0

通过构建表情包生成器来学习 React

通过构建表情包生成器来学习 React

表情包很棒——它们是表达想法和观点的一种非常有趣的方式。因此,我选择表情包生成器应用作为我在Scrimba 上的免费 React 课程的毕业设计项目也就不足为奇了。这款应用的工作原理是从 API 获取一张随机的表情包图片,然后将你的文字叠加在上面,从而创建出你专属的个性化表情包。

所以在本文中,我将提供创建应用程序的分步指南。如果您遇到任何困惑,也可以参考 Scrimba 课程中的这些步骤,从本讲开始。

如果您喜欢我的教学风格,并且在完成本教程后想要迎接更艰巨的挑战,请查看我即将推出的Scrimba 高级课程。

注意:你应该已经对 React 的一些基本概念比较熟悉,例如组件、状态、属性和生命周期方法。此外,本教程不使用 Hooks,但我在即将推出的课程中会深入讲解 Hooks,并提供大量的实践练习。

1. 创建样板并渲染 App 组件

创建样板任务

首先,我们需要创建应用程序的样板代码。为此,我们需要导入 `<module>`ReactReactDOM`<module>`,并使用它们ReactDOM来渲染一个名为 `<component>` 的组件App,该组件我们稍后会创建。然后,我们将该App组件放在根目录下。我们还需要App从其对应的 `<component>` 文件中导入 `<component>` "./App",该文件我们稍后也会创建。

// index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

ReactDOM.render(<App />, document.getElementById('root'));
Enter fullscreen mode Exit fullscreen mode

然后我们创建App.js文件。在文件中,我们创建一个名为 `<function_component>` 的函数式组件App,目前它返回一个简单的 `<select>` <h1>。然后我们导出它。`<select>` 组件<h1>允许我们检查应用程序是否在屏幕上正确显示。

import React from 'react';
function App() {
  return <h1>Hello world!</h1>;
}
export default App;
Enter fullscreen mode Exit fullscreen mode

最终输出结果如下:
渲染的“Hello World”

2. 创建 Header 和 MemeGenerator 组件

创建标题和表情包生成器任务

接下来,我们创建 Header 和 MemeGenerator 组件。Header 组件仅用于显示元素,而 MemeGenerator 组件会调用 API 并将数据保存在状态中。

我们先来创建Header.js文件。由于 Header 组件仅用于显示,因此它应该是一个函数式组件。目前,该组件应该返回一个简单的值<h1>。创建完成后,我们导出 Header 组件。

import React from 'react';
function Header() {
  return <h1>HEADER</h1>;
}
export default Header;
Enter fullscreen mode Exit fullscreen mode

接下来,我们创建MemeGenerator.js文件。由于该MemeGenerator组件将保存数据并调用 API,因此它必须是一个类组件。我们仍然需要导入 React,并且由于它将是一个类组件,我们Component还需要导入 `<React>`(这是一个命名导入)。

MemeGenerator 需要一个constructor()调用super(),并且由于它将保存状态,我们现在向其中添加一些空状态。与 Header 组件类似,我们<h1>首先渲染一个简单的元素。然后我们导出 MemeGenerator。

import React, { Component } from 'react';
class MemeGenerator extends Component {
  constructor() {
    super();
    this.state = {}; //empty state
  }
  render() {
    return <h1>MEME GENERATOR SECTION</h1>;
  }
}
export default MemeGenerator;
Enter fullscreen mode Exit fullscreen mode

现在,我们将 Header 和 MemeGenerator 导入到App.jsApp 组件中,并分别创建它们的实例。为了正确显示这些组件,我们将它们包裹在一个<div>.

import React from 'react';
import Header from './Header';
import MemeGenerator from './MemeGenerator';
function App() {
  return (
    <div>
      <Header />
      <MemeGenerator />
    </div>
  );
}
export default App;
Enter fullscreen mode Exit fullscreen mode

3. 完成头部组件。

为了完善<Header>组件,我们添加一个带有“trollface”字样的图片,方法是插入一个<img>标签并将 src 属性设置为图片的 URL。然后,我们添加一个<p>包含应用名称的标签,并将这两个标签包裹在语义化的 HTML5<header>标签中。

function Header() {
  return (
    <header>
      <img
        src='http://www.pngall.com/wp-content/uploads/2016/05/Trollface.png'
        alt='Problem?'
      />
      <p>Meme Generator</p>
    </header>
  );
}
Enter fullscreen mode Exit fullscreen mode

由于样式设置不在本课程的讨论范围之内,CSS 样式已经创建完毕并应用到<header>标签中。结果如下:

渲染后的头部

也就是说,学习者可以随时自行尝试不同的样式,磨练 CSS 技能。<Header/>现在这部分已经完成,挑战的其余部分将在……进行。<MemeGenerator/>

4. 初始化状态

初始化状态任务

现在我们需要初始化状态,以便保存顶部文本、底部文本和随机图像(已提供)。

为此,我们构建<MemeGenerator/>最初创建时放置在其中的空对象。我们将 ` topTexta` 和 ` b` 初始化bottomText为空字符串,并将 `c`初始化randomImg为提供的 URL。

class MemeGenerator extends Component {
  constructor() {
    super();
    this.state = {
      topText: '',
      bottomText: '',
      randomImg: 'http://i.imgflip.com/1bij.jpg'
    };
  }
}
Enter fullscreen mode Exit fullscreen mode

5. 发起 API 调用

执行 API 调用任务

接下来,我们向提供的 URL 发起 API 调用,并将返回的数据(一个位于 `<state>` 中的数组response.data.memes)保存到名为 `<state>` 的新状态属性中allMemeImgs
当我们需要从端点加载数据以供组件使用时,生命周期方法 `<state>` 是一个发出请求的好地方componentDidMount()。组件挂载后,我们立即使用原生fetch()函数 `<state>` 调用提供的 URL。

componentDidMount() {
  fetch("https://api.imgflip.com/get_memes")
}
Enter fullscreen mode Exit fullscreen mode

这会返回一个 Promise,我们使用该方法将其转换为 Javascript 对象.json()

componentDidMount() {
  fetch("https://api.imgflip.com/get_memes")
    .then(response => response.json())
}
Enter fullscreen mode Exit fullscreen mode

然后,我们通过从中提取 memes 数组来获得对我们有用的响应response.data

componentDidMount() {
fetch("https://api.imgflip.com/get_memes")
  .then(response => response.json())
  .then(response => {
  const { memes } = response.data
  })
}
Enter fullscreen mode Exit fullscreen mode

现在,我们将结果保存到一个名为 `save_results` 的新状态属性中allMemeImgs。为此,我们将其初始化allMemeImgs为一个空数组。

this.state = {
  topText: '',
  bottomText: '',
  randomImg: 'http://i.imgflip.com/1bij.jpg',
  allMemeImgs: []
};
Enter fullscreen mode Exit fullscreen mode

现在,回到初始componentDidMount()状态,我们设置状态。由于我们不关心之前的状态是什么,所以我们将其设置allMemeImgs为 memes。

componentDidMount() {
  fetch("https://api.imgflip.com/get_memes")
    .then(response => response.json())
    .then(response => {
  const { memes } = response.data
  this.setState({ allMemeImgs: memes })
  })
}
Enter fullscreen mode Exit fullscreen mode

为了确保其正常工作,我们console.log首先检查第一个项目,它看起来像这样:

控制台日志输出

以下是整个功能的概述componentDidMount()

componentDidMount() { //ensure that data is fetched at the beginning
  fetch("https://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
})
}
Enter fullscreen mode Exit fullscreen mode

6. 创建输入表单

现在我们想创建一个表单,最终允许用户输入顶部和底部文本。我们使用一个 HTML<form>标签和一个<button>包含“Gen”字样的简单元素来实现这一点。我们使用预先提供的 CSS 设置其样式。

render() {
  return (
    <div>
      <form className="meme-form">
        <button>Gen</button>
      </form>
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

渲染的 Gen 按钮

7. 向表单添加输入字段

添加输入字段任务

接下来,我们需要添加两个输入字段(一个用于顶部文本,一个用于底部文本)。该表单应为受控表单,因此我们需要添加所有必要的属性才能使其正常工作。我们onChange稍后会创建事件处理程序。

我们创建了两个输入字段,它们都具有类型text和相应的名称属性(topTextbottomText)。我们没有使用标签,而是使用占位符:“顶部文本”和“底部文本”。

最后,为了使之成为一个受控表单,我们将值设置为等于当前值,state并使用{this.state.topText}{this.state.bottomText}

render() {
  return (
    <div>
      <form className="meme-form">
        <input
          type="text"
          name="topText"
          placeholder="Top Text"
          value={this.state.topText}
        />
        <input
          type="text"
          name="bottomText"
          placeholder="Bottom Text"
          value={this.state.bottomText}
        />
        <button>Gen</button>
      </form>
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

8. 创建 onChange 处理程序。

创建 onChange 处理程序任务

现在,我们创建 onChange 处理程序,它会在输入字段每次发生变化时更新相应的状态。

首先,我们创建一个handleChange()接收事件的函数。

handleChange(event) {

}
Enter fullscreen mode Exit fullscreen mode

现在,我们将onChange两个输入字段的值设置为相等handleChange

<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>
Enter fullscreen mode Exit fullscreen mode

我们需要记住在构造函数中绑定方法——这是 React 开发人员常犯的一个错误。

constructor() {
  super()
  this.state = {
    topText: "",
    bottomText: "",
    randomImg: "http://i.imgflip.com/1bij.jpg",
    allMemeImgs: []
  }
  this.handleChange = this.handleChange.bind(this)
}
Enter fullscreen mode Exit fullscreen mode

为了测试新handleChange()功能,我们添加一个简单的console.log

handleChange(event) {
  console.log("Working!")
}
Enter fullscreen mode Exit fullscreen mode

如果它正常工作,你会看到类似这样的画面:
渲染 console.log(

现在来完善这个handleChange()函数。为此,我们需要从 event.target 中提取 name 和 value 属性,以便获取要更新的状态名称(topTextbottomText)以及在文本框中输入的值。

handleChange(event) {
  const { name, value } = event.target
}
Enter fullscreen mode Exit fullscreen mode

现在我们将使用这些信息来更新状态。由于我们并不关心之前的状态是什么,所以我们只需提供一个对象,并将该对象的值设置[name]为输入字段中输入的值即可。

handleChange(event) {
const {name, value} = event.target
this.setState({ [name]: value })
}
Enter fullscreen mode Exit fullscreen mode

9. 在顶部和底部文字旁边显示表情包图片

现在我们希望应用在顶部和底部文字旁边显示一张表情包图片。我们在 `<div>`<img>标签下方插入一个 `<div>` 标签<form>,并使用 `<div>` 标签将我们初始化的 `<div>` 设置randomImg为其源src={this.state.randomImg}。然后,我们添加两个 `<div>`<h2>标签来显示相应的文本,这些文本也保存在状态中。所有这些都被包裹在一个 `<div>` 标签中div,并使用预先提供的meme类进行样式设置。

<div className='meme'>
  <img src={this.state.randomImg} alt='' />
  <h2 className='top'>{this.state.topText}</h2>
  <h2 className='bottom'>{this.state.bottomText}</h2>
</div>
Enter fullscreen mode Exit fullscreen mode

现在我们可以通过在文本框中输入内容来测试该应用程序。由于每次按键都会正确设置状态,因此每次输入时,图像上显示的文本都会发生变化。

这是目前为止的进展示例。

10. 在顶部和底部文字旁边显示随机的表情包图片

显示随机表情包图片任务

现在,我们需要创建一个方法,allMemeImgsGen按钮被点击时,该方法会从数组中随机选择一张图片并显示出来。数组中被选中图片的属性是.url……
我们可以把这个任务分解成更小的部分。

首先,我们将表单的值为onSubmit等于我们新方法的名称,我们将称之为handleSubmit()

<form className="meme-form" onSubmit={this.handleSubmit}>

现在我们创建handleSubmit()上述函数render()。我们需要在事件上设置 preventDefault,否则该方法会尝试刷新页面。

handleSubmit(event) {
  event.preventDefault()
}
Enter fullscreen mode Exit fullscreen mode

我们还需要handleSubmit()在我们的系统中进行绑定constructor()

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)
}
Enter fullscreen mode Exit fullscreen mode

现在,我们需要获取一个随机数,从该索引中获取表情包,并将其设置randomImg为该.url随机项的值。

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
}
Enter fullscreen mode Exit fullscreen mode

为了获得一个随机数,我们使用…… Math.floor(Math.random)。为了确保它是allMemeImgs数组中的一个索引,我们将它乘以数组的长度。

const randNum = Math.floor(Math.random() * this.state.allMemeImgs.length);
Enter fullscreen mode Exit fullscreen mode

现在我们将其设置randMemeImg为相等allMemeImgs,索引为allMemeImgs我们randNum刚刚得到的值。然后我们将.url其添加到末尾。

const randMemeImg = this.state.allMemeImgs[randNum].url;
Enter fullscreen mode Exit fullscreen mode

现在,我们只需要通过更新 randomImg 属性来更新状态即可randMemeImg

this.setState({ randomImg: randMemeImg });
Enter fullscreen mode Exit fullscreen mode

我们最终完成的handleSubmit()函数如下所示:

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 })
}
Enter fullscreen mode Exit fullscreen mode

已完成的表情包生成器

工作应用程序

我们现在已经完成了表情包生成器应用程序,每次点击按钮都会生成不同的图像Gen,然后将我们输入的文本叠加到图像上。

为了进一步学习,我们可以修改代码,看看能否改进它,或者尝试从不同的 API 获取图像。如果想进行一些更具挑战性的练习,我们甚至可以删除所有代码,然后从头开始重新编写。

恭喜你完成了教程,并掌握了本项目中使用的所有技能。

如果你准备好了,不妨看看我即将推出的高级课程,它将带你达到 React 专业水平!

文章来源:https://dev.to/bobziroll/learn-react-by-building-a-meme-generator-41gh