react jquery

by Julien Benchetrit

通过朱利安·贝肯特里特

2019年React简介(面向仅了解jQuery的人们) (An Introduction to React in 2019 (For People Who Know Just Enough jQuery To Get By))

Back in 2015, @chibicode’s “React.js Introduction For People Who Know Just Enough jQuery To Get By” was my first contact with React and the tutorial that demystified the whole thing for me.

早在2015年, @ chibicode的“《 React.js入门指南 》 仅是了解jQuery的人 ”,这是我与React的首次联系,也是使我对整个事情神秘化的教程。

It walks you through the fundamentals of React in a meticulous manner and is especially well-suited for anyone who comes from the world of jQuery.

它以细致的方式带您了解React的基础知识,尤其适合来自jQuery世界的任何人。

Unfortunately, when trying to share it recently, I realized it was using React’s now obsolete createClass API and the images and embedded code samples weren’t loading anymore.

不幸的是,当最近尝试共享它时,我意识到它正在使用React现在过时的createClass API,并且图像和嵌入式代码示例不再加载。

So with @chibicode’s permission, I rewrote his article with the latest versions of React and JavaScript in mind and expanded upon some of the explanations.

因此,在@chibicode的允许下,我在撰写他的文章时考虑了最新版本的React和JavaScript,并扩展了一些解释。

Please note though that the vast majority of this tutorial is his work. I hope it will prove as useful to you as it did to me.

请注意,尽管本教程的绝大部分内容是他的作品。 我希望它对您像对我一样有用。

Without further ado, let’s learn us some React!

事不宜迟,让我们来学习一些React!

Small disclaimer: Some of the images are from @chibicode’s original article and the code they show is slightly different from the code we use here. The images are for illustrative purposes only. Always refer to the written code samples.

小免责声明:其中一些图像来自@chibicode的原始文章,它们显示的代码与我们在此使用的代码略有不同。 图像仅用于说明目的。 始终参考书面代码示例。

目标受众:知道足够了解jQuery的人 (Target Audience: People Who Know Just Enough jQuery to Get by)

Before I begin, I’d like to clarify who the target audience is.

在开始之前,我想澄清一下目标受众是谁。

Zed Shaw, the author of “Learn Code the Hard Way” series, wrote an excellent blog post called Early vs. Beginning Coders. In his post, Zed criticizes programming educators who claim that their materials are for “beginners”, but in reality are incomprehensible for most “total” beginners.

Zed Shaw是“ 艰苦学习代码 ”系列文章的作者,他写了一篇很棒的博客文章,叫做《 早期与初学者》 。 泽德(Zed)在他的文章中批评了编程教育者,他们声称他们的资料是为“初学者”准备的,但实际上对于大多数“总体”初学者来说都是难以理解的。

I don’t want to make a similar mistake here. Of the people who have never tried out React, some are comfortable with frontend JS frameworks like Backbone, Ember or Angular. Some know JavaScript pretty well. Some know just enough jQuery to get by. A tutorial that’s effective for one group may not be optimal for the other groups.

我不想在这里犯类似的错误。 在从未尝试过React的人们中,有些人对诸如Backbone , Ember或Angular的前端JS框架感到满意。 有些人非常了解JavaScript。 有些人知道足够的jQuery可以解决。 对一个小组有效的教程对于其他小组可能不是最佳的。

In this tutorial, I’m targeting the third group I mentioned: people who know just enough jQuery to get by. Examples of people who might fit in this category would be:

在本教程中,我针对的是我提到的第三组: 了解jQuery的人 。 可能适合该类别的人员包括:

  • Designers who can do basic coding in HTML/CSS/jQuery.
    可以在HTML / CSS / jQuery中进行基本编码的设计师。
  • WordPress developers who know how to use jQuery plugins.
    知道如何使用jQuery插件的WordPress开发人员。
  • Beginning developers who have completed basic HTML/CSS/JS tutorials online.
    刚完成在线基本HTML / CSS / JS教程的开发人员。
  • Backend developers who rely on Bootstrap and basic jQuery for their frontend needs.
    依靠Bootstrap和基本jQuery满足其前端需求的后端开发人员。
  • Anyone who does more copy-pasting than architecting when it comes to JavaScript.
    在JavaScript方面,任何比复制更具粘贴性的人。

If you’re comfortable with JavaScript or any of the frontend frameworks like Backbone/Ember/Angular, this tutorial is NOT for you, and you’ll be very frustrated with my writing style. There are tons of great tutorials you can learn from, including the official React tutorial.

如果您对JavaScript或Backbone / Ember / Angular之类的任何前端框架感到满意,那么本教程不适合您 ,并且您会对我的写作风格感到沮丧。 您可以从中学习很多很棒的教程,包括官方的React教程 。

Also, if you already know React, you’ll be pretty upset with me as well because I’ll be talking mostly about state instead of immutability or components. However, I found that teaching state first is the best way for jQuery developers to see why React is superior.

另外, 如果您已经知道React ,那么您也会对我感到不高兴,因为我主要谈论状态而不是不变性或组件。 但是,我发现首先讲授状态是jQuery开发人员了解为什么React优越的最好方法。

Anyways, let’s get started!

无论如何,让我们开始吧!

预计时间:1〜2小时 (Time Estimate: 1 ~ 2 hours)

If you go really fast (and copy-paste example code instead of typing), this tutorial should take a bit over an hour. If you take your time, it should take a little over 2 hours.

如果您真的很快(并且复制粘贴示例代码而不是键入代码),那么本教程将花费一个多小时。 如果您花时间,则应该花费2个多小时。

如果你被卡住 (If you’re stuck)

If you’re stuck or have questions, you can tweet the original author @chibicode or me @julienbenc.

如果您遇到困难或有疑问,可以发推原始作者@chibicode或我@julienbenc 。

概述:我们将建立一个“ Tweet Box” (Overview: We’re Going to Build a “Tweet Box”)

Many React tutorials begin by explaining how React works or why React is awesome. This tutorial does not.

许多React教程都是从解释React如何工作或为什么React很棒的开始。 本教程没有。

Instead, we’ll get right to building a simple UI, alternating between jQuery implementations and React implementations, explaining the differences along the way. I believe that you’ll think more this way as opposed to just typing out examples.

取而代之的是,我们将正确构建一个简单的UI,在jQuery实现和React实现之间交替,并解释其中的差异。 我相信您会以更多的方式思考,而不是仅输入示例。

The UI we’ll build will resemble the Tweet box that you find on Twitter. It won’t be exactly like the real Tweet box but it’ll be pretty similar. Hopefully you’ll find this example to be practical.

我们将构建的UI类似于您在Twitter上找到的Tweet框。 它不会完全像真正的Tweet框,但会非常相似。 希望您会发现这个例子很实际。

步骤1:CodePen简介(5-10分钟) (Step 1: Introduction to CodePen (5–10 minutes))

We’ll be using CodePen, an online code editor which supports both jQuery and React code. You might be familiar with similar services like JSBin or JSFiddle — they’re all pretty similar but I went with CodePen for easier embedding.

我们将使用CodePen ,这是一个在线代码编辑器,同时支持jQuery和React代码。 您可能熟悉诸如JSBin或JSFiddle之类的类似服务-它们非常相似,但是我使用CodePen来简化嵌入。

Here’s an example Pen:

这是Pen的示例:

Click “Run Pen” to see what happens when the code is run as well as the code itself (by clicking on the HTML button).

单击“运行笔”以查看运行代码以及代码本身(通过单击HTML按钮)会发生什么。

Next, click on “Edit on CodePen” to open the Pen in a new window. You can now modify the HTML on the top left — i.e. change the button’s text. You’ll see the changes appear in the bottom half of the window. That’s how CodePen works.

接下来,单击“在CodePen上编辑”以在新窗口中打开笔。 现在,您可以修改左上方HTML,即更改按钮的文本。 您将看到更改显示在窗口的下半部分。 这就是CodePen的工作方式。

创建一个CodePen帐户 (Create a CodePen Account)

Unless you already have a CodePen account, head to https://codepen.io/ to create an account. Click Sign Up to create your account.

除非您已经拥有一个CodePen帐户,否则请转到https://codepen.io/ 创建一个帐户 。 单击注册创建您的帐户。

After creating an account, you can fork public Pens to your account. More or less the same as forking a GitHub repository into your account.

创建帐户后,您可以派生公共笔到您的帐户。 与将GitHub存储库派生到您的帐户中大致相同。

Let’s try it. Open this next Pen in a new tab and click “Fork” in the top-right menu.

让我们尝试一下。 在新标签页中打开下一支钢笔,然后单击右上角菜单中的“叉子”。

Once you’re on the Pen, you can import popular open-source libraries. You do that by opening Settings and then heading to either the CSS or JavaScript tabs where you can then search for the library you want to add.

使用笔后,您可以导入流行的开源库。 为此,请打开“设置”,然后转到“ CSS”或“ JavaScript”选项卡,然后在其中搜索要添加的库。

Try doing the following in your forked Pen:

尝试使用分叉笔执行以下操作:

  • Add the latest Bootstrap from the CSS tab (the name will be “twitter-bootstrap”)
    从CSS选项卡添加最新的Bootstrap(名称将为“ twitter-bootstrap”)
  • Add btn btn-primary classes on the <button> tag

    <button>标签上添加btn btn-primary

And the output becomes a little prettier:

输出变得更漂亮:

创建一个推文框 (Create a Tweet Box)

You seem to be pretty comfortable with CodePen now. Alright, let’s build out a Tweet box. Still on the same Pen as before, change the HTML inside <body> like this:

您现在似乎对CodePen非常满意。 好吧,让我们建立一个Tweet框。 仍与以前使用同一支笔,如下更改<body>内HTML

<div class="card bg-light"><div class="card-body text-right"><textarea class="form-control"></textarea><br/><button class="btn btn-primary">Tweet</button></div>
</div>

We’re using Bootstrap classes like form-control, card, card-body, etc. but those are just for the looks and irrelevant for the tutorial. Here’s the result:

我们使用的是Bootstrap类,例如form-controlcardcard-body等,但它们只是为了外观而与本教程无关。 结果如下:

That’s it for the first step! Not too bad, eh?

第一步就是这样! 还不错吧?

步骤2:实施第一个功能-最初应禁用Tweet按钮(5分钟) (Step 2: Implement the First Feature — Tweet Button Should Initially Be Disabled (5 minutes))

Now, time for some JS. We’ll first implement the following feature:

现在,该花点时间学习一些JS。 我们将首先实现以下功能:

Feature 1: the “Tweet” button should initially be disabled. When there’s at least one character in the text field, the “Tweet” button should be enabled.

功能1:最初应禁用“ Tweet”按钮。 如果文本字段中至少有一个字符,则应启用“ Tweet”按钮。

Here’s the demo Pen. As you can see, the button is initially disabled. If you type something into the text box, the button becomes enabled.

这是演示笔。 如您所见,该按钮最初被禁用。 如果在文本框中键入内容,该按钮将变为启用状态。

To get this to work, you first need to add jQuery into the Pen. Do that inside the JavaScript tab in your Pen’s Settings. (If you’re having trouble with this step, check out CodePen’s official instructions.) Once that’s done, go to the small JavaScript window and add the following jQuery code.

为了使其正常工作,您首先需要将jQuery添加到Pen中。 在“笔的设置”中的“ JavaScript”选项卡中执行此操作。 (如果您在执行此步骤时遇到麻烦,请查阅CodePen的官方说明 。) 完成后,转到JavaScript小型窗口,并添加以下jQuery代码。

// Initially disable the button
$("button").prop("disabled", true);
// When the value of the text area changes...
$("textarea").on("input", function() {// If there's at least one character...if ($(this).val().length > 0) {// Enable the button.$("button").prop("disabled", false);} else {// Else, disable the button.$("button").prop("disabled", true);}
});

说明 (Explanation)

  • I used the tag names button and textarea as selectors — no need to add IDs or classes for this example.

    我将标签名称buttontextarea用作选择器-在此示例中无需添加ID或类。

  • To enable/disable the button, use $(...).prop("disabled", ...).

    要启用/禁用按钮,请使用$(...).prop("disabled", ...)

  • To listen for changes in textarea, use the input event which works on modern browsers.

    要侦听textarea中的更改,请使用在现代浏览器上有效的input事件。

Try it out by typing some text in the Tweet box and seeing the button’s enabled/disabled state change.

通过在“推文”框中键入一些文本并查看按钮的启用/禁用状态更改进行尝试

DO NOT PROCEED if this example was confusing to you — you might need to learn some more jQuery before moving onto React. There are lots of excellent learning resources like Codecademy, Treehouse, Code School, and others.

如果这个例子让您感到困惑,请不要继续-在转向React之前,您可能需要学习更多的jQuery。 有很多出色的学习资源,例如Codecademy , Treehouse , Code School等。

Now that this feature is complete, we’ll try to re-implement the same thing using React. This will take several steps.

现在,该功能已经完成,我们将尝试使用React重新实现相同的功能。 这将需要几个步骤。

第3步:使用React的Tweet框(5-10分钟) (Step 3: The Tweet Box Using React (5–10 minutes))

One of the first things you’ll notice in React is that you’ll be writing markup in JS, not in HTML.

在React中您会注意到的第一件事是, 您将使用JS而不是HTML编写标记

Let me show you what I mean. Here’s the React code which displays the same Tweet box.

让我告诉你我的意思。 这是显示相同Tweet框的React代码。

警告! 您不需要继续学习-只需阅读代码。 (WARNING! You don’t need to follow along yet — just read the code.)

Some observations:

一些观察:

  • Inside return (...) is HTML-like code, not JavaScript. In React, you’ll write in a special syntax called JSX which lets you put HTML-like code inside JavaScript.

    内部return (...)是类似HTML的代码,而不是JavaScript。 在React中,您将使用称为JSX的特殊语法编写代码,该语法可将类似HTML的代码放入JavaScript中。

  • I say HTML-“like” because it’s not identical to HTML. Notice that it uses className instead of class — but it’s pretty similar, so you’ll learn it quickly.

    我说HTML“喜欢”是因为它与HTML不同。 注意,它使用className而不是class ,但是它非常相似,因此您将快速学习它。

  • Your browser does not understand JSX so, before the code can be run, it is automatically converted into browser-compatible JavaScript by a JS compiler (called Babel).
    您的浏览器不了解JSX,因此在运行代码之前,它会由JS编译器(称为Babel)自动转换为与浏览器兼容JavaScript。
  • The HTML code inside return (...) is pretty much identical to the HTML code from step 1.

    return (...)内HTML代码与步骤1中HTML代码几乎相同。

  • Look at the remaining HTML code in our Pen and you’ll see that there’s no markup besides <body><div id="container">&lt;/div></body>. This is what I meant when I said that in React you’ll be writing markup in JavaScript (JSX) and not in HTML.

    查看笔中剩余HTML代码,您会发现除<body><div id="container">& lt; / div> </ body>之外没有任何标记。 当我说在React中使用JavaScrip t(JSX)而不是HTML 编写标记时,这就是我的意思

常见问题与解答 (Frequently Asked Questions & Answers)

Question: What do class TweetBox extends React.Component and ReactDOM.render do? Do I need to understand them now? Answer: Don’t worry about it for now. Basically, the first declares a React component with a name (in this case, TweetBox). This then gets rendered in the DOM via ReactDOM.render(<TweetBox />, document.getElementById("container")) — meaning this component is added inside the <div id="container"> tag. That’s all you need to know for now.

问题: class TweetBox extends React.ComponentReactDOM.render做什么? 我现在需要了解它们吗? 答:暂时不要担心。 基本上,第一个声明一个带有名称的React组件(在本例中为TweetBox )。 然后,通过ReactDOM.render(<TweetBox />, document.getElementById("contai ner”))在DOM中呈现它-意味着e the <div id="co ntainer”>标记中添加了此组件。 这就是您现在所需要知道的。

Question: Do I need to do anything special to write JSX on my local machine?Answer: Yes, but that’s outside the scope of this tutorial — in short, you need to enable something called Babel compilation. All you need to do to write JSX on CodePen is to (1) add the React and ReactDOM libraries and (2) select “Babel” from the list of JavaScript Preprocessors in the JS settings window.

问题:在本地计算机上编写JSX时,我需要做些特殊的事情吗? 答:是的,但这不在本教程的讨论范围之内—简而言之,您需要启用称为Babel编译的功能。 在CodePen上编写JSX所需要做的就是(1)添加React和ReactDOM库,以及(2)从“ JS设置”窗口中JavaScript预处理器列表中选择“ Babel”。

Question: Isn’t it bad practice to write markup (HTML) and behavior (JS) in the same place?Answer: It might be bad practice for simple web pages but not necessarily so for large web applications. In large web applications, there will be hundreds of pieces of UI, each containing their own markup and behaviors. The code will be more manageable if the markup and behaviors are kept together for each piece of UI, as opposed to keeping “all markup” together and “all behaviors” together. And React is designed for developing large web applications. In fact, React is developed and used by Facebook, one of the largest web applications out there.

问题:在同一位置编写标记(HTML)和行为(JS)是否不是一个好习惯? 答:对于简单的网页,这可能不是一个好习惯,但对于大型Web应用程序,则不一定如此。 在大型Web应用程序中,将有数百个UI,每个UI包含自己的标记和行为。 如果将每个UI的标记和行为都放在一起,而不是将“所有标记”和“所有行为”放在一起,则代码将更易于管理。 React是为开发大型Web应用程序而设计的。 实际上,React是由Facebook开发和使用的,Facebook是目前最大的Web应用程序之一。

Next, I’ll show you how to write the above React code step-by-step.

接下来,我将向您展示如何逐步编写上述React代码。

第4步:编写您的第一个React代码(5-10分钟) (Step 4: Writing Your First React Code (5–10 minutes))

Here’s a starter Pen. In it, I’ve imported Bootstrap (the CSS portion) and React. I also set the JavaScript Preprocessor to Babel so we can write classes and JSX.

这是入门笔。 在其中,我导入了Bootstrap(CSS部分)和React。 我还将JavaScript预处理器设置为Babel,以便我们可以编写类和JSX。

Please try to follow along. To begin, fork this Pen so you can edit and save as you go.

请尝试跟随。 首先,请分叉此笔,以便您可以随时编辑和保存。

Now you’re ready to write some React. Try to follow along and type the following JS code snippets into your Pen.

现在您可以编写一些React了。 尝试按照以下步骤在Pen中键入以下JS代码片段

class TweetBox extends React.Component {render() {return null;}
};

This is the template for creating a piece of UI using React (in this case, a Tweet box). It’s just as essential as $(selector).append('your HTML code or element') in jQuery.

这是使用React(在本例中为Tweet框)创建UI的模板。 它与jQuery中的$(selector).append('your HTML code or element')

To actually construct the UI, we must write the render() method. For now, let’s keep it simple with just a single div tag.

要实际构建UI,我们必须编写render()方法。 现在,让我们仅使用一个div标签使其简单。

class TweetBox extends React.Component {render() {return (<div>Hello World!</div>);}
};

Like in the example above, put a pair of parenthesis after return, and write the markup inside.

像上面的示例一样, return后面放一对括号,然后在其中写上标记。

JSX陷阱 (JSX Gotchas)

There’s one thing you need to remember with JSX — in render(), you must return only one outermost tag (or anything that can be considered a valid DOM node such as a string or a string).

使用JSX需要记住一件事—在render() ,您必须仅返回一个最外面的标签(或任何可以视为有效DOM节点的东西,例如字符串或字符串)。

This will work because it’s a string:

这将起作用,因为它是一个字符串:

return 'Hello World!';

But the following won’t work because there’s no quotes or outermost tag around the text:

但是以下内容将不起作用,因为文本周围没有引号或最外面的标记:

return (Hello World!
);

This also doesn’t work because there are two outer-most (span) tags inside return (…):

这也不起作用,因为在return (…)内部有两个最外面的( span )标签:

return (<span>Hello</span><span>World</span>
);

For the above example, the workaround is to create an extra div tag to wrap the two span tags.

对于上面的示例,解决方法是创建一个额外的div标签来包装两个span标签。

return (<div><span>Hello</span><span>World</span></div>
);

We used a div here but in the most recent versions of React, you can use the Fragment feature to render multiple outermost tags. Like this:

我们在这里使用了div ,但是在最新版本的React中,您可以使用Fragment功能来呈现多个最外面的标签。 像这样:

return (<React.Fragment><span>Hello</span><span>World</span></React.Fragment>
);

将UI附加到DOM (Attaching the UI to the DOM)

Now we need to “attach” this UI to the DOM in order to see Hello World. To do this, add ReactDOM.render() underneath the code we just wrote:

现在,我们需要将此UI“附加”到DOM才能看到Hello World 。 为此, 在我们刚刚编写的代码下面添加ReactDOM.render()

class TweetBox extends React.Component {...
};
ReactDOM.render(<TweetBox />,document.getElementById("container")
);

(Note: an ellipsis (…) in the code snippet indicates code that has been omitted for clarity. In other words, don’t touch this part of the code and leave it as is.)

( 请注意 :代码段中的省略号(...)表示为清楚起见已省略了代码。换句话说,请勿触摸代码的这一部分并保持原样。)

ReactDOM.render takes two arguments. The first argument is the React component, which is <VariableName />. The second argument is the DOM element where we want to render (in this case, document.getElementById('container')). Put together, the above code renders the TweetBox UI inside <div id="container">.

ReactDOM.render有两个参数。 第一个参数是React组件,它是<VariableName />。 第二个参数是我们要呈现的DOM元素(在本case, document.getElementById('conta conta iner'))。 综上所述,以上代码s the Tw nside <div id="co ntainer”>旁边呈现s the Tw两个eetBox UI。

Now, you should see Hello World appear in your Pen. Congratulations, you wrote and rendered your first React component!

现在,您应该看到Hello World出现在笔中。 恭喜,您编写并渲染了第一个React组件!

编写推文框的实际HTML (Write the Actual HTML for the Tweet Box)

Now, instead of Hello World, we’ll implement the HTML for the Tweet Box. Swap the code inside render() with this:

现在,我们将代替Tweet Box实现HTML,而不是Hello World与此交换在render()的代码:

return (<div className="card bg-light"><div className="card-body text-right"><textarea className="form-control" /><br /><button className="btn btn-primary">Tweet</button></div></div>
);

There are two things you need to watch out for:

您需要注意两件事:

  • Don’t use class. Instead, use className. It’s because JSX gets translated to JS and class is a reserved keyword in JS.

    不要使用class 而是使用className 。 这是因为JSX被转换为JS,而class是JS中的保留关键字。

  • If you use <br> instead of <br/>, you’ll get an error. Make sure to close all tags. Same thing with images: <img src="…" alt="…" />

    如果你使用< BR> inste ad of <BR/>,你将G等错误。 确保关闭所有标签。 与ith images: <img src相同的东西ith images: <img src =“…” alt =“ ...” />

Everything else should be the same as the jQuery example from before.

其他所有内容都应与之前的jQuery示例相同。

If you typed this correctly, then you should see the Tweet box in your Pen. If nothing appears in the output, check your code very carefully to make sure there aren’t any typos.

如果键入正确,则您应该在笔中看到Tweet框。 如果输出中没有任何内容,请非常仔细地检查代码,以确保没有错别字。

That’s it for this step! Here’s the Pen up to this part:

这就是步骤! 这是笔到这部分的内容:

第5步:在React中重新实现第一个功能-最初应禁用Tweet按钮-5至10分钟 (Step 5: Re-implement the First Feature — Tweet Button Should Initially Be Disabled — in React (5–10 minutes))

We’re going to re-implement with React the first feature we implemented using jQuery:

我们将使用React重新实现我们使用jQuery实现的第一个功能:

Feature 1: The “Tweet” button should initially be disabled. When there’s at least one character in the text field, the “Tweet” button should be enabled.

功能1:最初应禁用“ Tweet”按钮。 如果文本字段中至少有一个字符,则应启用“ Tweet”按钮。

Here’s the jQuery code we wrote:

这是我们编写的jQuery代码:

Let’s see how we can do this in React.

让我们看看如何在React中做到这一点。

Start with your Pen from the previous step. (Tip: Since you won’t be touching HTML in React, you can minimize the HTML tab on CodePen to get more screen space. Same thing with the CSS tab.)

从上一步开始使用笔。 ( 提示:由于您不会在React中接触HTML,因此可以最小化Code​​Pen上HTML选项卡以获得更多的屏幕空间。与CSS选项卡相同。)

First, let’s disable the button by adding disabled as an attribute.

首先,让我们通过添加disabled作为属性来disabled按钮。

render() {return (...<button className="..." disabled>Tweet</button>...);
}

In JSX, this is equivalent to writing disabled={true}.

在JSX中,这等效于编写disabled={true}

The button should now be disabled. Note that in our jQuery implementation we wrote:

现在应该禁用该按钮。 注意,在我们的jQuery实现中,我们编写了:

$("button").prop("disabled", true);

to initially disable the button, but we could have instead modified the button tag like above.

最初禁用按钮,但是我们可以像上面那样修改button标记。

Now, we need to enable the button when there’s at least one character in the text field.

现在,当文本字段中至少有一个字符时,我们需要启用该按钮。

处理变更事件 (Handle Change Event)

First, we need to listen for the user typing in the textarea. In our jQuery implementation, we wrote:

首先,我们需要听用户在textarea键入。 在我们的jQuery实现中,我们写道:

$("textarea").on("input", function() {...
}

In the React world, we write the event handler as a class method. Let’s call it handleChange:

在React世界中,我们将事件处理程序编写为类方法 。 我们称之为handleChange

class TweetBox extends React.Component {handleChange = () => {};render() {...}
}

Note that we’re using an arrow function so that we can access the class’s context (this) without having to bind the function in the constructor. Explaining this in-depth is outside the scope of this tutorial but you will very likely learn about it in due time.

请注意,我们使用的是箭头函数,这样我们就可以访问类的上下文( this ),而不必在constructor函数中绑定该函数。 对此进行深入解释超出了本教程的范围,但是您很可能会在适当的时候对其进行了解。

Next, we call this handler when text is entered. To do so, modify the textarea tag in render() like this:

接下来,我们在输入文本时调用此处理程序。 为此,请像这样修改render()textarea标签:

<textarea className="form-control" onChange={this.handleChange}>
</textarea>
  • We used the input event for jQuery but in React we use onChange — you’ll learn about how events differ in React’s JSX from the official React documentation so don’t worry too much for now.

    我们将input事件用于jQuery,但在React中我们使用onChange -您将从官方React文档中了解事件在JSX的JSX中有何不同,所以现在不必太担心。

  • More importantly, we used curly brackets to include JavaScript code inside the HTML syntax part of JSX. In this case, we passed the handler handleChange and we prefixed it with this because it’s a class method.

    更重要的是 ,我们使用大括号将JavaScript代码包含在JSXHTML语法部分中。 在这种情况下,我们通过处理handleChange ,我们用前缀它this ,因为它是一个类的方法。

  • If you’re used to jQuery, this might seem like bad practice but don’t worry. Again, in large applications, the code will be more manageable if the markup and behaviors are kept together for each piece of UI.
    如果您习惯使用jQuery,这似乎是一种不好的做法,但是不用担心。 同样,在大型应用程序中,如果将每个UI的标记和行为放在一起,则代码将更易于管理。

To make sure that the handler is indeed being called, let’s add console.log inside handleChange:

为了确保确实调用了该处理程序, 让我们在handleChange内添加console.log

handleChange = (e) => {console.log(e.target.value);
};

The event object (nicknamed e) contains target which is the textarea. We get the value to output the current content of the textarea.

event对象(昵称为e )包含target ,即textarea 。 我们获得该value以输出textarea的当前内容。

In your Pen, open the console tab (with the button in the bottom left of the screen) to check the output. Then type something in the Tweet box.

在笔中,打开console选项卡(使用屏幕左下方的按钮)以检查输出。 然后在“推文”框中键入内容。

You can also try it out here (you’ll need to open the Pen in a new tab to see the console button):

您也可以在此处进行尝试(您需要在新标签页中打开笔以查看console按钮):

That’s it for this step! We’ll finish this feature in the next step.

这就是步骤! 我们将在下一步中完成此功能。

NOTE: Close the console tab in CodePen when you’re done. We no longer need it.

注意:完成后,关闭CodePen中的console选项卡。 我们不再需要它。

步骤6:实施状态(10-15分钟) (Step 6: Implementing State (10–15 minutes))

I’ll now explain one of the biggest differences between jQuery-style code and React-style code.

现在,我将解释jQuery风格的代码和React风格的代码之间的最大区别之一。

In jQuery, when some event happens, you usually modify the DOM directly (like we did earlier with $("button").prop("disabled", true)):

在jQuery中,当发生某些事件时,通常可以直接修改DOM(就像我们之前使用$("button").prop("disabled", true) ):

In React, you never modify the DOM directly. Instead, in an event handler, you modify something called the “component state”. And this is done by calling this.setState.

在React中, 您永远不会直接修改DOM。 相反,您可以在事件处理程序中修改称为“组件状态”的内容 。 这是通过调用this.setState来完成的。

Then, every time the state is updated, render() is called again. And inside render() you can access the state to tell React how you want the DOM to be modified.

然后,每次state更新时, 都会再次调用 render() render()内部,您可以访问状态以告诉React如何修改DOM。

This is how you update the UI in response to an event. Yes it’s confusing at first so let me explain using code.

这是您响应事件来更新UI的方式。 是的,一开始令人困惑,所以让我解释一下代码。

编写事件处理程序 (Writing the Event Handler)

Start with your Pen from the previous step. First, we need to initialize the state object. We can do that inside the class constructor.

从上一步开始使用笔。 首先,我们需要初始化状态对象。 我们可以在类constructor

What goes in the object? Let’s create a single key called text and have it store whatever is inside the Tweet box.

对象中有什么? 让我们创建一个名为text键,并将其存储在Tweet框中的所有内容。

class TweetBox extends React.Component {constructor(props) {super(props);this.state = {text: '',};}handleChange = (e) => {...};render() {...}
};

Don’t worry about why we’re calling super(props) at the top of our constructor. It’s an important step but not necessary to understand React for now.

不必担心为什么我们在constructor的顶部调用super(props) 。 这是很重要的一步,但现在不必了解React。

Next, we’ll modify the event handler to set the state’s text field to whatever is currently in the textarea. To do this, we use a special method called setState and pass the updated key-value pair.

接下来,我们将修改事件处理程序,以将状态的text字段设置为textarea当前存在的内容。 为此, 我们使用一种称为setState的特殊方法并传递更新的键值对。

handleChange = (e) => {this.setState({ text: e.target.value });
};

Now, let’s check that the state is correctly being set by writing some debug-only code in render().

现在,让我们通过在render()编写一些仅调试的代码来检查状态是否正确设置。

To do this, simply add this.state.text near the end of render() and use curly brackets to use JS code inside the HTML syntax part of JSX.

为此, 只需在render()末尾附近添加this.state.text ,并使用大括号在JSXHTML语法部分内使用JS代码。

render() {return (<div className="card bg-light">...{this.state.text}</div>);
}

Now, try entering some text in the Tweet box. The same text should appear below the button.

现在,尝试在“推文”框中输入一些文本。 该按钮下方应显示相同的文本。

You can try it out on the Pen below as well:

您也可以在下面的笔上尝试一下:

Now the previous diagram might make more sense to you:

现在,上一张图可能对您更有意义:

删除调试代码 (Remove the Debugging Code)

Once you confirm that the state is correctly being set, remove the debugging code we just added:

确认正确设置了状态后,请删除我们刚刚添加的调试代码:

{this.state.text}

启用/禁用按钮 (Enabling/Disabling the Button)

Now that we can listen for text changes, the next step is to enable/disable the button depending on whether the text is empty or not.

现在我们可以侦听文本更改了,下一步是根据text是否为空来启用/禁用button

Using the state, we can use this logic:

使用state ,我们可以使用以下逻辑:

  • If this.state.text.length === 0, the button should be disabled.

    如果this.state.text.length === 0 ,则应禁用该按钮。

To do this in React, add the disabled attribute and set its value as the output of this.state.text.length === 0. Since this is JS code, you need to wrap it with {}.

要在React中执行此操作,请添加disabled属性并将其值设置为this.state.text.length === 0的输出 。 由于这是JS代码,因此需要用{}包装。

<button className="btn btn-primary" disabled={this.state.text.length === 0}>Tweet</button>

If you write disabled="true" or disabled="false" in raw HTML it won’t work — in raw HTML, you need to add/remove the disabled attribute to enable the button. But React is not raw HTML — it does the following behind the scenes:

如果您在原始HTML中编写disabled="true"disabled="false"无效,那么在原始HTML中,您需要添加/删除disabled属性以启用button 。 但是React 不是原始HTML-它在后台执行以下操作:

  • If you write disabled={true} in JSX, it gets converted to just <button disabled> in HTML.

    如果您在JSX中编写了disabled={true} ,那么它将在HTML中转换为<button disabl >。

  • If you write disabled={false} in JSX, the disabled attribute is removed from the button tag in HTML.

    如果您在JSX中编写了disabled={false} ,则会从HTML的button标记中删除disabled属性。

This works with other Boolean attributes like checked. (You can read more about this aspect of JSX here.)

这可与其他布尔属性(如checked 。 (您可以在此处阅读有关JSX这方面的更多信息。)

The resulting Pen is below:

生成的Pen如下:

感言 (Reflections)

Again, keep this difference between jQuery and React in mind before moving on to the next step:

同样,在继续下一步之前,请记住jQuery和React之间的区别:

  • In jQuery, you write event handlers which modify the DOM.

    在jQuery中,您编写了修改DOM的事件处理程序。

  • In React, you write event handlers which modify the state. And you write render() to reflect the current state.

    在React中,您可以编写事件处理程序来修改state 。 然后编写render()以反映当前状态。

步骤7:jQuery中的剩余字符数(5分钟) (Step 7: Remaining Character Count in jQuery (5 minutes))

The next feature we’ll implement is the remaining character count.

我们将实现的下一个功能是剩余字符数。

Here’s the spec:

规格如下:

  • The character count will display 280 — the length of the text.

    字符数将显示280 — the length of the text

We’ll first implement this in jQuery, then in React.

我们将首先在jQuery中实现,然后在React中实现。

We’ll start with our previous jQuery implementation and put our React code on hold for now. Going forward, I will give you new code to start with at the beginning of each chapter, as we alternate between jQuery and React. That means after you’re done with each step, you can play with the code before moving to the next step.

我们将从先前的jQuery实现开始,并暂时搁置我们的React代码。 展望未来,随着我们在jQuery和React之间交替,我将在每一章的开头为您提供新的代码 。 这意味着在完成每一步之后,您可以先处理代码,然后再进行下一步。

✔ Fork the Pen below to get started.

✔分叉下面的钢笔以开始使用。

First, add the character count in HTML. Let’s set it inside a span:

首先, 在HTML中添加字符数。 让我们将其设置为span

<textarea {...}></textarea><br>
<span>280</span>
<button {...}>Tweet</button>

And inside the input handler in JS, add this code to update the character count:

在JS的输入处理程序中,添加以下代码以更新字符数:

$("textarea").on("input", function() {$("span").text(280 - $(this).val().length);...
});

That’s it! Try typing in the Tweet box and you’ll see the character count gets updated as you type. Here’s the Pen:

而已! 尝试在“推文”框中键入内容 ,您会看到键入时字符数已更新。 这是笔:

步骤8:React中的剩余字符数(5分钟) (Step 8: Remaining Character Count in React (5 minutes))

How about in React? You should try doing this on your own. Start with our previous React implementation.

在React中怎么样? 您应该尝试自己执行此操作。 从我们之前的React实现开始。

✔ Fork the Pen below to get started.

✔分叉下面的钢笔以开始使用。

(Tip: Since you won’t be touching HTML in React, you can minimize the HTML tab on CodePen to get more screen space.)

( 提示:由于您不会在React中触摸HTML,因此可以最小化Code​​PenHTML选项卡以获得更多的屏幕空间。)

Hints:

提示:

  • No need to change the constructor() or handleChange() methods.

    无需更改constructor()handleChange()方法。

  • Use this.state.text.length in render().

    render()使用this.state.text.length

回答: (Answer:)

Add this code after <br/> in your render():

your re render()中的<b r />之后添加以下代码:

<span>{280 - this.state.text.length}</span>

Here’s the Pen:

这是笔:

Too easy? Not sure why building UIs with React is so much better than jQuery? Well, the next step has more complexity and this is where React really starts to shine.

太容易了? 不确定为什么用React构建UI比jQuery好得多? 好了,下一步变得更加复杂了,这就是React真正开始发光的地方。

第9步:“添加照片”按钮(5分钟) (Step 9: The “Add Photo” Button (5 minutes))

For our next feature, we’ll add an “Add Photo” button to the Tweet Box. This is where things start to get tricky.

对于我们的下一个功能,我们将在“ Tweet框”中添加一个“添加照片”按钮。 这就是事情开始变得棘手的地方。

However, we won’t actually write the code to upload images. Instead, here’s what we’re going to do:

但是, 我们实际上不会编写代码来上传图像。 相反,这是我们要做的:

When you upload a photo on Twitter, it counts against the character limit. On my attempt, it decreased the number of remaining characters from 280 to 257.

当您在Twitter上上传照片时,该照片将计入字符数限制。 在我的尝试中,它将剩余字符数从280个减少到257个。

Yes, I know that Twitter no longer counts photos against the character limit but we’ll disregard that for this tutorial.

是的,我知道Twitter不再根据字符数限制来计算照片,但在本教程中我们将不考虑它。

Here’s the spec:

规格如下:

  • Create an “Add Photo” button.
    创建一个“添加照片”按钮。
  • Clicking this button toggles an ON/OFF state.

    单击此按钮可切换开/关状态。

  • If the button is ON, it will say ✓ Photo Added and the number of available characters decreases by 23.

    如果该按钮为开,它将显示✓ Photo Added并且可用字符数减少了23。

  • Also, if the button is ON, even if there’s no text entered, the “Tweet” button remains enabled.

    另外,如果按钮为ON, 即使没有输入文字,“ Tweet”按钮也会保持启用状态。

Here’s the demo CodePen. Try clicking the “Add Photo” button and see what happens to the character count and the Tweet button.

这是演示CodePen。 尝试单击“添加照片”按钮 ,查看字符数和“鸣叫”按钮会发生什么。

Let’s implement this with jQuery first.

让我们首先用jQuery实现它。

第10步:jQuery中的“添加照片”按钮(15-20分钟) (Step 10: The “Add Photo” Button in jQuery (15–20 minutes))

Start with the latest version of our jQuery implementation.

从我们的jQuery实现的最新版本开始。

✔ Fork the Pen below to get started.

✔分叉下面的钢笔以开始使用。

Earlier, we were attaching a handler to $("button") but this won’t work anymore if we have two buttons. So let’s modify the HTML like this:

早些时候,我们在$("button")上附加了一个处理程序,但是如果我们有两个按钮,它将不再起作用。 因此,让我们像这样修改HTML:

...
<button class="js-tweet-button btn btn-primary" disabled>Tweet</button>
<button class="js-add-photo-button btn btn-secondary">Add Photo</button>
...

Here are the changes:

更改如下:

  • Added the second button which says “Add Photo”.

    添加了第二个按钮 ,显示“添加照片”。

  • Added classes js-tweet-button and js-add-photo-button to each button. The class names are prefixed with js- to remember that they’re used only in JS and not in CSS.

    向每个按钮添加了js-tweet-buttonjs-add-photo-button button类。 类名以js-为前缀,以记住它们仅在JS中使用,而不在CSS中使用。

  • Added the initial disabled attribute to the Tweet button so we don’t have to do it in JS.

    在“ Tweet”按钮上添加了初始的disabled属性,因此我们不必在JS中执行此操作。

Next, rewrite the entire JS file like this:

接下来,像这样重写整个JS文件:

$("textarea").on("input", function() {$("span").text(280 - $(this).val().length);if ($(this).val().length > 0) {$(".js-tweet-button").prop("disabled", false);} else {$(".js-tweet-button").prop("disabled", true);}
});

Here are the changes:

更改如下:

  • (Important) Removed $("button").prop("disabled", true); from the first line because we added the disabled attribute directly to the Tweet button.

    (重要)已删除$("button").prop("disabled", true); 从第一行开始,因为我们将disabled属性直接添加到了Tweet按钮。

  • Replaced $("button") with $(".js-tweet-button") so it can be distinguished from .js-add-photo-button.

    $("button")替换$(".js-tweet-button")以便将其与.js-add-photo-button区分开。

添加按钮 (Adding the Button)

Next, we’ll implement one of the features:

接下来,我们将实现以下功能之一:

  • Clicking the “Add Photo” button toggles the ON/OFF state. If it’s ON, the button will say ✓ Photo Added.

    单击“添加照片”按钮切换ON / OFF状态。 如果开启,按钮将显示✓ Photo Added

To do this, let’s add this piece of code:

为此, 我们添加以下代码:

$("textarea").on("input", function() {...
});$(".js-add-photo-button").on("click", function() {if ($(this).hasClass("is-on")) {$(this).removeClass("is-on").text("Add Photo");} else {$(this).addClass("is-on").text("✓ Photo Added");}
});

We use the class is-on to keep track of the state. Check to see that this works by clicking the “Add Photo” button multiple times and seeing the text alternate.

我们使用类is-on来跟踪状态。 多次单击“添加照片”按钮,然后交替查看文字,以检查是否有效

减字符数 (Decrement Character Count)

Next, we’ll implement this feature:

接下来,我们将实现此功能:

  • If the “Add Photo” button is ON, the number of available characters decreases by 23.

    如果“添加照片”按钮为开, 则可用字符数减少23。

To do this, modify the click handler we just added like this.

为此,请修改我们刚刚添加的点击处理程序。

if ($(this).hasClass("is-on")) {$(this).removeClass("is-on").text("Add Photo");$("span").text(280 - $("textarea").val().length);
} else {$(this).addClass("is-on").text("✓ Photo Added");$("span").text(280 - 23 - $("textarea").val().length);
}

We change the span’s content on every click. If the button is ON, we need to subtract the text length from 257 (i.e. 280 — 23). We use 280 — 23 for clarity right now but, if we were building a production app, we should use constants instead.

我们每次点击都会更改span的内容。 如果button为ON,则需要从257 (即280 — 23 )中减去文本长度。 为了清楚起见,我们现在使用280 — 23 ,但是,如果要构建生产应用程序,则应改用常量。

Check to see that this works by clicking the “Add Photo” button.

单击“添加照片”按钮,检查是否可以使用

修复输入处理程序 (Fixing the Input Handler)

This isn’t complete however — if you have the “Add Photo” button ON and start typing in the textarea, the remaining character count goes out of sync.

但是,这还不完整- 如果您打开“添加照片”按钮并开始在textarea输入内容,则剩余字符数将不同步。

This happens because the handler for the textarea doesn’t take into account the status of the “Add Photo” button.

发生这种情况是因为textarea的处理程序未考虑“添加照片”按钮的状态。

To fix this, we need to update the handler for textarea like this:

为了解决这个问题, 我们需要像这样更新textarea的处理程序:

$("textarea").on("input", function() {if ($(".js-add-photo-button").hasClass("is-on")) {$("span").text(280 - 23 - $(this).val().length);} else {$("span").text(280 - $(this).val().length);}if (...) {...}
});

Make sure that this works by turning on the “Add Photo” button and then typing some text.

通过打开“添加照片”按钮,然后键入一些文本来确保此方法有效

我知道这需要一些时间… (I know this is taking some time…)

But stick with it! The jQuery code here is supposed to be confusing so don’t worry!

但是坚持下去! 此处的jQuery代码应该令人困惑,所以请不要担心!

实施最后一个功能 (Implement the Last Feature)

The last feature we need to implement is this:

我们需要实现的最后一个功能是:

  • If the “Add Photo” button is ON, even if there’s no text entered, the “Tweet” button remains enabled.

    如果“添加照片”按钮为开, 即使没有输入文字,“推文”按钮仍保持启用状态。

To do this, we need to modify the click handler of the “Add Photo” button:

为此, 我们需要修改“添加照片”按钮的点击处理程序:

$(".js-add-photo-button").on("click", function() {if ($(this).hasClass("is-on")) {...if ($("textarea").val().length === 0) {$(".js-tweet-button").prop("disabled", true);}} else {...$(".js-tweet-button").prop("disabled", false);}
});

Here’s the explanation:

解释如下:

  • If the “Add Photo” button is going from ON to OFF (if clause), we need to check if there’s no text entered and, if so, disable the “Tweet” button.

    如果“添加照片”按钮从“开”变为“关”( if子句),我们需要检查是否没有输入文字,如果是,请禁用“ Tweet”按钮。

  • If the “Add Photo” button is going from OFF to ON (else clause), we always enable the “Tweet” button.

    如果“添加照片”按钮从“关”变为“开”( else子句),则我们始终启用“推”按钮。

但是,这又被打破了 (But again, this is broken)

We’re not done yet. There’s a bug in the code right now. Try it out yourself by following these steps:

我们还没有完成。 现在代码中有一个错误。 请按照以下步骤尝试一下:

  • Turn on the “Add Photo” button.
    打开“添加照片”按钮。
  • Type some text.
    输入一些文字。
  • Delete all of the text.
    删除所有文本。
  • The “Tweet” button should still be enabled because the “Add Photo” button is ON, but this isn’t the case.
    由于“添加照片”按钮处于打开状态,因此“ Tweet”按钮仍应处于启用状态,但实际情况并非如此。

This means that our input handler for textarea is missing some logic. To fix this, we need to add another condition to the if statement in the input handler.

这意味着我们的textarea输入处理程序缺少某些逻辑。 为了解决这个问题, 我们需要在输入处理程序的if语句中添加另一个条件。

$("textarea").on("input", function() {...if ($(this).val().length > 0 || $(".js-add-photo-button").hasClass("is-on")) {...} else {...}
});

This is the explanation for this additional condition:

这是对此附加条件的解释:

  • When the text changes, if the text isn’t empty OR if the “Add Photo” button is ON, do not disable the “Tweet” button.

    当文本更改时, 如果文本不为空或“添加照片”按钮为“开” ,请不要禁用“推文”按钮。

Try the above steps again and this time it will work as expected.

再次尝试上述步骤 ,这一次可以正常工作。

第11步:对jQuery代码的反思-为什么如此令人困惑? (5分钟) (Step 11: Reflection on the jQuery Code — Why So Confusing? (5 minutes))

Here’s the final HTML and JS code from the previous step:

这是上一步的最终HTML和JS代码:

Take a look at the jQuery code once again. It’s very confusing. If you’re keeping the code as-is, you’ll probably need comments everywhere to remember how it works. There are also clear signs of code duplication but you’d have to think quite a bit before refactoring.

再次看一下jQuery代码。 这非常令人困惑。 如果您将代码保持原样,则可能到处都需要注释以记住其工作方式。 也有明显的代码重复迹象,但是在重构之前您必须考虑很多。

The question is: why did it get so ugly so fast?

问题是: 为什么它变得如此丑陋如此之快?

The answer has to do with the “jQuery style” of code we talked about previously. Recall this diagram:

答案与我们之前讨论的“ jQuery样式”有关。 回想一下这个图:

Things are simple when there is only 1 event handler and 1 DOM element. However, as we just saw, if several event handlers are modifying several parts of the DOM, the code gets ugly and complicated.

当只有1个事件处理程序和1个DOM元素时,事情就很简单。 但是,正如我们刚刚看到的, 如果多个事件处理程序正在修改DOM的多个部分,则代码将变得丑陋且复杂。

This is an example of what people mean when they say “spaghetti code”.

这是人们说“意大利面条代码”时的意思的示例。

Imagine adding more features that could influence both the character limit and the “Tweet” button state. The code would become even harder to manage.

想象添加更多可能会影响字符限制和“ Tweet”按钮状态的功能。 该代码将变得更加难以管理。

You can, in theory, mitigate this by refactoring into reusable functions. But you’d still have to think hard about it every time you add something new.

从理论上讲,您可以通过重构为可重用的函数来减轻这种情况。 但是,每次添加新内容时,您仍然都必须认真考虑一下。

Note: Someone shared a refactored version of the jQuery code (for the original tutorial). Very clean. You’ll notice that the update() function takes care of most of the updates to the DOM based on its current “state”. The event listeners then run this function on every call.

注意:有人共享了jQuery代码的重构版本 (适用于原始教程)。 很干净。 您会注意到, update()函数根据DOM的当前“状态”来处理DOM的大多数更新。 然后,事件侦听器在每次调用时都运行此功能。

In that way it’s similar to React’s render. However, there are still many downsides to this solution. For one, the absence of a real state object makes the logic more opaque. It also doesn’t allow you to break down your UI into multiple components and is likely to have performance issues as you continue adding to it.

这样就类似于React的render 。 但是,该解决方案仍然存在许多缺点。 首先,缺少实时state对象会使逻辑更加不透明。 它还不允许您将UI分解为多个组件,并且在继续添加时可能会遇到性能问题。

Now, let’s see what it’s like to do the same thing with React.

现在,让我们看看使用React进行相同操作的感觉。

Spoiler alert: It’s going to be much simpler.

剧透警报:它将变得更加简单。

步骤12:React中的“添加照片”按钮(10至20分钟) (Step 12: The “Add Photo” Button in React (10–20 minutes))

Let’s start with our previous React implementation.

让我们从之前的React实现开始。

✔ Fork the Pen below to get started.

✔分叉下面的钢笔以开始使用。

添加按钮 (Adding the Button)

First, let’s add the “Add Photo” button. Modify the JSX:

首先,让我们添加“添加照片”按钮。 修改JSX:

<button ...>Tweet</button><button className="btn btn-secondary">Add Photo
</button>

Now, let’s add a click handler to this button so that the text changes from Add Photo to ✓ Photo Added. Recall the React way of writing code:

现在,让我们添加一个单击处理这个按钮,让文字从改变Add Photo✓ Photo Added 。 回想一下React编写代码的方式:

We will:

我们会:

  1. Create a state variable that keeps track of whether the “Add Photo” button is ON or OFF.

    创建一个状态变量 ,以跟踪“添加照片”按钮是打开还是关闭。

  2. Use the state in render() to decide whether to show Add Photo or ✓ Photo Added.

    使用 render() 的状态来决定显示“ Add Photo还是“ ✓ Photo Added Add Photo

  3. Update the state in the click handler.

    更新点击处理程序中的状态

For (1), we’ll modify the initial state in the constructor by adding a key-value pair to keep track of whether the photo is added or not:

对于(1), 我们将通过添加键值对来修改constructor的初始状态,以跟踪是否添加了照片:

constructor(props) {super(props);this.state = {text: '',photoAdded: false,};
}

For (2), we’ll modify the JSX markup for the “Add Photo” button. We’ll have the button say “Photo Added” if this.state.photoAdded is true. We can just use a ternary operator here:

对于(2), 我们将为 “添加照片”按钮修改JSX标记 。 如果this.state.photoAdded为true,则按钮将显示“已添加照片”。 我们可以在这里使用三元运算符 :

<button className="btn btn-secondary">{this.state.photoAdded ? "✓ Photo Added" : "Add Photo" }
</button>

Finally, for (3), we’ll attach an event handler on JSX like we did for the textarea:

最后,对于(3), 我们将像在textarea 一样在JSX上附加一个事件处理程序

<button className="btn btn-secondary" onClick={this.togglePhoto}>{this.state.photoAdded ? "✓ Photo Added" : "Add Photo" }
</button>

Notice that we’re using onClick instead of onChange. This is because we’re dealing with a button and not a textarea or an input.

请注意,我们使用的是onClick而不是onChange 。 这是因为我们要处理的是button而不是textareainput

We’ll also add a handler method which toggles the value of this.state.photoAddded:

我们还将添加一个处理程序方法,用于切换this.state.photoAddded的值:

togglePhoto = () => {this.setState((prevState) => ({ photoAdded: !prevState.photoAdded }));
}

This time you’ll see that we’re passing a function to this.setState. This is necessary if you want to update your component state but need to use a value from the previous state. Why we do that is outside the scope of this tutorial but you can read about it in this section of the official React documentation.

这次您将看到我们正在将一个函数传递给this.setState 。 如果要更新组件状态,但需要使用先前状态的值,则这是必需的。 我们为什么这样做不在本教程的讨论范围之内,但是您可以在React官方文档的本节中阅读到。

Now, clicking on Add Photo should toggle the button text. Try it out yourself.

现在,单击添加照片应切换按钮文本。 自己尝试一下。

减字符数 (Decrement Character Count)

We’ll now implement the next feature:

现在,我们将实现下一个功能:

  • If the “Add Photo” button is ON, the number of available characters decreases by 23.

    如果“添加照片”按钮为开, 则可用字符数减少23。

Currently, the number of available characters is displayed as follows in render():

当前,可用字符数在render()显示如下:

<span>{280 - this.state.text.length}</span>

This value will now also depend on this.state.photoAdded so we need an if and else here.

现在,该值还将取决于this.state.photoAdded因此在这里需要ifelse

However, in JSX, you can’t write if or else inside { ... }. You could use a ternary expression (a ? b : c) like we did earlier but it would be pretty long and hard-to-read in this case.

但是, 在JSX中,您不能在{ ... }内编写ifelse 。 您可以像我们之前使用的那样使用三元表达式( a ? b : c ),但是在这种情况下,它会很长且难以阅读。

Often the simplest solution in this situation is to refactor a conditional into a method. Let’s try it.

在这种情况下,最简单的解决方案通常是将条件重构为方法。 让我们尝试一下。

First, modify the above code to use a class method, like this:

首先,修改上面的代码以使用类方法,如下所示

<span>{this.getRemainingChars()}</span>

And define the method like this:

并定义如下方法:

getRemainingChars = () => {let chars = 280 - this.state.text.length;if (this.state.photoAdded) chars = chars - 23;return chars;
}

Now, the remaining character count should update as expected when the “Add Photo” button is toggled.

现在,当切换“添加照片”按钮时,剩余字符数应按预期更新。

Question: In render(), why does {this.getRemainingChars()}have () but {this.handleChange} and {this.togglePhoto} don’t?

问题 :在render() ,为什么{this.handleChange} {this.getRemainingChars()}具有()但是{this.handleChange}{this.togglePhoto}没有?

Good question. Let’s take a look at render() again:

好问题。 让我们再次看一下render()

render() {return (...<textarea className="..." onChange={this.handleChange}></textarea>...<span>{this.getRemainingChars()}</span>...    <button className="..." onClick={this.togglePhoto}>...</button>...);}

Answer:

  • We’ve written the getRemainingChars() method to return a number. We need to get this number and put it inside <span>&lt;/span>, so we need to call the getRemainingChars() method by using (). That’s why we have () in getRemainingChars().

    我们已经编写了getRemainingChars()方法来返回数字 。 我们需要获取此数字并将其放在<span>& lt; / span>中,因此我们需要 to call the getRema iningChars()甲基od通过使用()。 这是wh Ÿ我们have () in getRema iningChars()。

  • On the other hand, handleChange and togglePhoto are event handlers. We want these methods to be called only when the user interacts with the UI (typing in the textarea or clicking a button). To do so, we need to write them without () in render() and assign them to attributes like onChange and onClick. React will take care of attaching the methods to the relevant event listeners for us.

    另一方面, handleChangetogglePhoto事件处理程序 。 我们希望仅当用户与UI交互时(在textarea键入或单击button )才调用这些方法。 为此,我们需要在render()编写不带() ,并将其分配给诸如onChangeonClick类的属性。 React将为我们将方法附加到相关的事件监听器上。

“ Tweet”按钮的状态 (The “Tweet” Button’s Status)

We have one more feature to implement:

我们还有一个功能可以实现:

  • If the “Add Photo” button is ON, even if there’s no text entered, the “Tweet” button remains enabled.

    如果“添加照片”按钮为开,则即使没有输入文字,“推文”按钮仍保持启用状态。

This is actually really easy thanks to React. Previously, the Tweet button’s disabled option was set as:

多亏了React,这真的很容易。 以前,“鸣叫”按钮的“ disabled选项设置为:

<button ... disabled={this.state.text.length === 0}>...</button>

In other words, previously the “Tweet” button was disabled if the text’s length was 0. Now, the “Tweet” button is disabled if:

换句话说,以前如果文本的长度为0 ,则“ Tweet”按钮被禁用。现在,如果满足以下条件,则“ Tweet”按钮被禁用

  • The text’s length is 0
    文字长度为0
  • AND

  • The “Add Photo” button is OFF.
    “添加照片”按钮关闭。

So the logic looks like this:

所以逻辑看起来像这样:

<button ... disabled={this.state.text.length === 0 && !this.state.photoAdded}>...</button>

One way you can clarify the above code is by utilizing getRemainingChars(). If there are 280 characters remaining, that means that the textarea is empty and the “Add Photo” button is OFF so the “Tweet” button should be disabled.

您可以使用getRemainingChars()澄清以上代码的一种方法。 如果剩余280个字符,则表示textarea为空,并且“添加照片”按钮为OFF,因此应禁用“ Tweet”按钮。

<button ... disabled={this.getRemainingChars() === 280}>...</button>

This works but could break if, for example, you later refactor getRemainingChars so that it returns a string instead of a number. Instead, we can keep the previous logic and just move it to the top of the render():

这是可行的,但是如果例如稍后您重构getRemainingChars使其返回字符串而不是数字,则可能会中断。 Instead, we can keep the previous logic and just move it to the top of the render() :

render() {const isTweetButtonDisabled = this.state.text.length === 0 && !this.state.photoAdded;return (...<button className="..." disabled={isTweetButtonDisabled}>Tweet</button>...);}

That’s it! Try toggling the “Add Photo” button and check that the “Tweet Button” is enabled/disabled correctly.

而已! Try toggling the “Add Photo” button and check that the “Tweet Button” is enabled/disabled correctly.

We're Done! (We’re Done!)

Here’s the resulting Pen:

Here's the resulting Pen:

Step 13: Reflection on the React Code — Why So Simple? (5 minutes) (Step 13: Reflection on the React Code — Why So Simple? (5 minutes))

The changes to accommodate the “Add Photo” button were minimal when using React. No refactor needed. Why is this the case?

The changes to accommodate the “Add Photo” button were minimal when using React. No refactor needed. 为什么会这样呢?

Again, it has to do with React’s style of writing UI code. In React, event handlers modify the state, and whenever the state is modified, React automatically calls render() again to update the UI.

Again, it has to do with React's style of writing UI code. In React, event handlers modify the state , and whenever the state is modified, React automatically calls render() again to update the UI.

In this particular example, the diagram now looks like this:

In this particular example, the diagram now looks like this:

The state becomes an intermediary thing which sits in between the event handlers and render():

The state becomes an intermediary thing which sits in between the event handlers and render() :

  • Event handlers don’t need to worry about which part of the DOM changes. They just need to set the state.

    Event handlers don't need to worry about which part of the DOM changes. They just need to set the state .

  • Similarly, when you write render(), all you need to worry about is what the current state is.

    Similarly, when you write render() , all you need to worry about is what the current state is.

Compare with jQuery (Compare with jQuery)

You can imagine what would happen as the UI gets more features. Without the intermediary state, we’d have a tough time managing complexity. This is why you’d want to use React over jQuery for complex UIs.

You can imagine what would happen as the UI gets more features. Without the intermediary state, we'd have a tough time managing complexity. This is why you'd want to use React over jQuery for complex UIs.

Again, it’s possible to write clean jQuery code that doesn’t look like spaghetti code. But you have to come up with the code structure yourself and think about how to refactor every time you add a new feature. React provides you this structure and reduces your cognitive load.

Again, it's possible to write clean jQuery code that doesn't look like spaghetti code. But you have to come up with the code structure yourself and think about how to refactor every time you add a new feature. React provides you this structure and reduces your cognitive load.

Note that the idea of separating the state from the rendering wasn’t invented with React. We’re just looking at it from the perspective of React.

Note that the idea of separating the state from the rendering wasn't invented with React. We're just looking at it from the perspective of React.

Step 14: The Final Feature — Highlighting Overflown Characters (5 minutes) (Step 14: The Final Feature — Highlighting Overflown Characters (5 minutes))

The last feature we’re going to implement is highlighting characters that are over the limit.

The last feature we're going to implement is highlighting characters that are over the limit .

Unfortunately, we’re not going to highlight the actual text inside the Tweet box because that would require us to change <textarea&gt; to<div contenteditable="true"> and contenteditable is a bit too complicated for illustrative purposes.

Unfortunately, we're not going to highlight the actual text inside the Tweet box because that would require us to change <textar ea& gt; to<div contenteditabl e="tr ue"> and con tenteditable is a bit too complicated for illustrative purposes.

Instead, we’ll be displaying a Bootstrap alert box on top and indicate which characters need to be deleted, like this:

Instead, we'll be displaying a Bootstrap alert box on top and indicate which characters need to be deleted, like this:

To try it out, copy the following quote from the official React documentation:

To try it out, copy the following quote from the official React documentation:

React embraces the fact that rendering logic is inherently coupled with other UI logic: how events are handled, how the state changes over time, and how the data is prepared for display.

React embraces the fact that rendering logic is inherently coupled with other UI logic: how events are handled, how the state changes over time, and how the data is prepared for display.

Instead of artificially separating technologies by putting markup and logic in separate files, React separates concerns with loosely coupled units called “components” that contain both.

Instead of artificially separating technologies by putting markup and logic in separate files, React separates concerns with loosely coupled units called “components” that contain both.

  • It should show an alert box with the overflow characters highlighted in red.
    It should show an alert box with the overflow characters highlighted in red.
  • It should also show 10 characters before the cutoff point, without any highlighting.
    It should also show 10 characters before the cutoff point, without any highlighting.

If we were to implement this in jQuery, our code would become a lot messier. Notice in the diagram that we’ll be adding two more arrows for one new feature.

If we were to implement this in jQuery, our code would become a lot messier. Notice in the diagram that we'll be adding two more arrows for one new feature.

So we’re not going to implement this in jQuery. We’ll just do it with React and call it a day. It’ll be pretty simple to do with React — just one extra arrow in the diagram:

So we're not going to implement this in jQuery . We'll just do it with React and call it a day. It'll be pretty simple to do with React — just one extra arrow in the diagram:

Step 15: Highlighting Overflow Characters with React (10–15 minutes) (Step 15: Highlighting Overflow Characters with React (10–15 minutes))

Let’s start with our previous React implementation.

Let's start with our previous React implementation.

✔ Fork the Pen below to get started.

✔ Fork the Pen below to get started.

We’ll do this step by step. First, we’ll display a simple alert with static text when you write past the limit.

We'll do this step by step. First, we'll display a simple alert with static text when you write past the limit.

Since this will require a conditional, let’s write it in a separate method. Add {this.renderOverflowAlert()} above the textarea:

Since this will require a conditional, let's write it in a separate method. Add {this.renderOverflowAlert()} above the textarea :

{this.renderOverflowAlert()}
<textarea ...></textarea>

Now, this method should return:

Now, this method should return:

  • A div tag for the alert box if there are no more characters left.

    A div tag for the alert box if there are no more characters left.

  • Nothing (i.e. empty string or NULL) otherwise.

    Nothing (ie empty string or NULL) otherwise.

It turns out that in React, you can return JSX markup from a method and use this in any other method, everything will just work. In other words, you can do something like:

It turns out that in React, you can return JSX markup from a method and use this in any other method , everything will just work. In other words, you can do something like:

someMethod = () => {return (<a href="#">Hello World</a>);
}
anotherMethod = () => {return (<h1>{this.someMethod()}</h1>);
}

In renderOverflowAlert, we can return ( <div> ... </div> )  in one case and nothing in the other. So our renderOverflowAlert method will look like this:

In renderOverflowAlert , we can return ( <div> ... </div> ) in one case and nothing in the other. So our renderOverflowAlert method will loo k like this:

renderOverflowAlert = () => {if (this.getRemainingChars() < 0) {return (<div className="alert alert-warning text-left"><strong>Oops! Too Long:</strong></div>);}return '';
};

Notice that we’re checking this.getRemainingChars() to see if we need to show the alert or not.

Notice that we're checking this.getRemainingChars() to see if we need to show the alert or not.

Try this out by typing 280+ characters (or 257+ characters with the “Add Photo” button ON). The alert should appear just as the character limit reaches -1.

Try this out by typing 280+ characters (or 257+ characters with the “Add Photo” button ON). The alert should appear just as the character limit reaches -1.

Displaying Overflown Characters (Displaying Overflown Characters)

Here’s a breakdown of the logic we want for the alert message:

Here's a breakdown of the logic we want for the alert message:

  • Between “Oops! Too Long:” and the actual text, there’s an empty single space followed by three dots. I used here because when writing markup in JSX, white spaces between tags get removed. (You can add them manually using {' '}.)

    Between “Oops! Too Long:” and the actual text, there's an empty single space followed by three dots. 我用了 here because when writing markup in JSX, white spaces between tags get removed. (You can add them manually using {' '} .)

  • Then there are the 271st~280th (total of 10) characters of this.state.text.

    Then there are the 271st~280th (total of 10) characters of this.state.text .

  • Then there are the remaining characters highlighted in red.
    Then there are the remaining characters highlighted in red.

Let’s write this in JSX. Inside the if clause of overflowAlert, we’ll create two variables: beforeOverflowText and overflowText. We’ll use the substring method on this.state.text.

Let's write this in JSX. Inside the if clause of overflowAlert , we'll create two variables: beforeOverflowText and overflowText . We'll use the substring method on this.state.text .

renderOverflowAlert = () => {if (this.getRemainingChars() < 0) {const beforeOverflowText = this.state.text.substring(280 - 10, 280);const overflowText = this.state.text.substring(280);return (<div className="alert alert-warning text-left"><strong>Oops! Too Long:</strong>&nbsp; &#8230;{beforeOverflowText}<strong className="bg-danger text-light">{overflowText}</strong></div>);}return '';
};
  • If you do .substring(a, b), it will return the (a + 1)-nth until the b-th characters from the string.

    If you do .substring(a, b) , it will return the (a + 1)-nth until the b-th characters from the string.

  • If you do .substring(a), it will return the (a + 1)-nth until the last characters from the string.

    If you do .substring(a) , it will return the (a + 1)-nth until the last characters from the string.

  • We use Bootstrap’s bg-danger class to highlight the text in red and text-light to make the text readable against the now-dark background.

    We use Bootstrap's bg-danger class to highlight the text in red and text-light to make the text readable against the now-dark background.

Copy paste the following text again and check that the part of the text after the first 280 characters is highlighted. We’re almost done!

Copy paste the following text again and check that the part of the text after the first 280 characters is highlighted. 我们快完成了!

React embraces the fact that rendering logic is inherently coupled with other UI logic: how events are handled, how the state changes over time, and how the data is prepared for display.

React embraces the fact that rendering logic is inherently coupled with other UI logic: how events are handled, how the state changes over time, and how the data is prepared for display.

Instead of artificially separating technologies by putting markup and logic in separate files, React separates concerns with loosely coupled units called “components” that contain both.

Instead of artificially separating technologies by putting markup and logic in separate files, React separates concerns with loosely coupled units called “components” that contain both.

What if the “Add Photo” button is ON? (What if the “Add Photo” button is ON?)

If the “Add Photo” button is ON then the character limit decreases by 23. So our beforeOverflowText and overflowText need to take that into account:

If the “Add Photo” button is ON then the character limit decreases by 23. So our beforeOverflowText and overflowText need to take that into account:

renderOverflowAlert = () => {if (this.getRemainingChars() < 0) {const imageLength = this.state.photoAdded ? 23 : 0;const beforeOverflowText = this.state.text.substring(280 - imageLength - 10,280 - imageLength,);const overflowText = this.state.text.substring(280 - imageLength);return (<div className="alert alert-warning text-left"><strong>Oops! Too Long:</strong>&nbsp; &#8230;{beforeOverflowText}<strong className="bg-danger text-light">{overflowText}</strong></div>);}return '';};

Now, try toggling the “Add Photo” button while entering any text that’s longer than the limit. It should work as expected. Here’s the Pen:

Now, try toggling the “Add Photo” button while entering any text that's longer than the limit. It should work as expected. Here's the Pen:

That’s it! Again, you can see that the code changes were simple:

而已! Again, you can see that the code changes were simple:

Step 16: What's Next? (5 minutes) (Step 16: What’s Next? (5 minutes))

This concludes the tutorial. Hopefully you:

This concludes the tutorial. Hopefully you:

  • understood the advantages of React’s component structure vs manually modifying the DOM with jQuery, and
    understood the advantages of React's component structure vs manually modifying the DOM with jQuery, and
  • learned how to write simple React components using JavaScript and JSX.
    learned how to write simple React components using JavaScript and JSX.

下一步是什么? (What’s next?)

There are many ways to go from here.

There are many ways to go from here.

One possibility would be to take a look at this short article called How to Learn React — A roadmap from beginner to advanced. It can help you decide how to best continue learning React.

One possibility would be to take a look at this short article called How to Learn React — A roadmap from beginner to advanced . It can help you decide how to best continue learning React.

I also highly recommend reading the following portions the official React documentation:

I also highly recommend reading the following portions the official React documentation:

  • Getting started which includes the React team’s recommended learning resources, and

    Getting started which includes the React team's recommended learning resources, and

  • Thinking in React which will help you understand how to think about building components and applications with React.

    Thinking in React which will help you understand how to think about building components and applications with React.

Before you leave though, I have an optional challenge for you!

Before you leave though, I have an optional challenge for you!

If you feel comfortable enough with React already and want to write your own code, try to move remainingChars to the component’s state. Make sure it gets updated where necessary and use it in all the relevant places.

If you feel comfortable enough with React already and want to write your own code, try to move remainingChars to the component's state . Make sure it gets updated where necessary and use it in all the relevant places.

Feel free to post the result as a Pen in the comments and I’ll be very happy to check it out!

Feel free to post the result as a Pen in the comments and I'll be very happy to check it out!

谢谢 (Thanks)

Thanks a lot for reading this far! And above all thanks to @chibicode for the huge amount of work he put into the first version of this tutorial! I hope this updated version does it justice.

Thanks a lot for reading this far! And above all thanks to @chibicode for the huge amount of work he put into the first version of this tutorial! I hope this updated version does it justice.

I’m Julien. I work as a frontend engineer at Healthy.io and I help maintain react-boilerplate on GitHub. If you catch a mistake, want any clarifications or think I skipped something important, please let me know and I’ll make sure to fix it.

I'm Julien. I work as a frontend engineer at Healthy.io and I help maintain react-boilerplate on GitHub. If you catch a mistake, want any clarifications or think I skipped something important, please let me know and I'll make sure to fix it.

翻译自: https://www.freecodecamp.org/news/react-introduction-for-people-who-know-just-enough-jquery-to-get-by-2019-version-28a4b4316d1a/

react jquery

react jquery_2019年React简介(面向仅了解jQuery的人们)相关推荐

  1. 从零开始React:一档 React环境搭建,语法规则,基础使用

    手挽手带你学React入门第一期,带你熟悉React的语法规则,消除对JSX的恐惧感,由于现在开发中都是使用ES6语法开发React,所以这次也使用ES6的模式进行教学,如果大家对ES6不熟悉的话,先 ...

  2. (React 框架)React技术

    1.简介 React 是Facebook 开发并开源的前端框架 当时他们的团队在市面上没找到合适的MVC 框架,就自己写一个 JS 框架,用来架设 instagram(图片分享社交网路),2013年开 ...

  3. 如何将React App转换为React Native

    I have been working on a lot of mobile projects lately - including Cordova, PhoneGap, React Native, ...

  4. [react] 你觉得react上手快不快?它有哪些限制?

    [react] 你觉得react上手快不快?它有哪些限制? 相对vue来说不快. 限制 需要学习JSX 需要工程化的配置 需要对原生JavaScript有相当的掌握 react只是一个UI层面的库,像 ...

  5. [react] 在使用react过程中你都踩过哪些坑?你是怎么填坑的?

    [react] 在使用react过程中你都踩过哪些坑?你是怎么填坑的? 组件不像Vue一样有(beforeRouteLeave, beforeRouteEnter)路由守卫 Hooks中的闭包渲染问题 ...

  6. [react] 怎样在react中创建一个事件?

    [react] 怎样在react中创建一个事件? var EventEmitter = require('events').EventEmitter; class App extends Compon ...

  7. [react] 写一个react的高阶组件并说明你对高阶组件的理解

    [react] 写一个react的高阶组件并说明你对高阶组件的理解 定义高阶组件 import React, { Component } from 'react';const simpleHoc = ...

  8. [react] 怎样在react中使用innerHTML?

    [react] 怎样在react中使用innerHTML? 使用dangerouslySetInnerHTML属性,该属性传入一个对象,对象中__html属性的值即时innerHTML的富文本代码 个 ...

  9. [react] 有用过react的Fragment吗?它的运用场景是什么

    [react] 有用过react的Fragment吗?它的运用场景是什么 代替div作为外层,可做不可见的包裹元素. 个人简介 我是歌谣,欢迎和大家一起交流前后端知识.放弃很容易, 但坚持一定很酷.欢 ...

最新文章

  1. 虚拟机桌面linux系统,KVM - Linux下三大免费桌面虚拟机评测_Linux教程_Linux公社-Linux系统门户网站...
  2. 批处理清除VisualStudio解决方案文件夹
  3. python视频课程推荐-听说程序员都在用,5款Python开发工具推荐
  4. coreldraw 双层边框
  5. visual studio学习python_python3从零学习-开发环境搭建之Visual Studio Code篇
  6. win10用Eclipse+OpenJTag对S3C2440开发板进行动态调试
  7. 使用D9的SetFVF无法控制数据字段在内存中的顺序,所有字段的顺序都是固定的。自能选择好用还是不用。...
  8. 疯狂软件对Oracle放弃Java EE的看法
  9. CUDA学习(二十九)
  10. Win32汇编学习(7):鼠标输入消息
  11. Shared library can't open object
  12. Node.js学习(第一章:Node.js安装方法及模块化理解)
  13. OLAP引擎——Kylin介绍
  14. 拓展SOUI中SImRichEdit控件的语音OLE控件(AudioOle)
  15. 如何elf文件转换为asm汇编文件
  16. 微信小程序,动态改变背景图片
  17. 泰山OFFICE技术讲座:一个字符,用哪个字体绘制
  18. 固态硬盘长期不通电数据丢失吗 数据丢失怎么恢复
  19. 2020年起重机械指挥模拟试题及起重机械指挥模拟考试题
  20. 为什么你看书记不住,记住不会用?-我的技术学习方法论

热门文章

  1. 2014创新工场校招笔试题及参考答案
  2. 什么是异常 java 1615309028
  3. 吃货阶段02 商品类的定义 需求 0925
  4. python-描述符的分类
  5. linux-新建一个centos虚拟机系统-安装全过程图示
  6. 用户控件(UserControl)
  7. 迷宫(AHOI2016初中组T3)
  8. 性能测试分析与调优原理
  9. 2011 ICM 美国数据建模赛题
  10. Ext.ClassManager源码