参考资料:http://reactfordesigners.com/labs/reactjs-introduction-for-people-who-know-just-enough-jquery-to-get-by/
Target Audience: People Who Know Just Enough jQuery to Get by
Before I begin, I’d like to clarify who my target audience is.
Zed Shaw, the author of “Learn Code the Hard Way” series, recently wrote an excellent blog post called Early v.s. 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.
I don’t want to make a similar mistake here. Of 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.
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:
- Designers who can do basic coding in HTML/CSS/jQuery.
- WordPress developers who know how to use jQuery plugins.
- Beginning developers who have completed basic HTML/CSS/JS tutorials online.
- Backend developers who rely on Bootstrap and basic jQuery for their frontend needs.
- Anyone who does more copy-pasting than architecting when it comes to 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.
Also, if you already know React, you’ll be pretty upset with me as well because I’ll be talking mostly about states instead of immutability or componetization. However, I found that teaching states first is the best way for jQuery developers to see why React is superior.
Anyways, let’s get started!
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 go slow, it should take a bit over 2 hours.
If you’re stuck
If you’re stuck, do any of the following:
- Comment on the comment box at the very bottom of this page.
- Email me at [email protected].
- Tweet me at @chibicode.
- File an issue on this repo.
Overview: We’re Going to Build a “Tweet Box”
Many React.js tutorials begin by explaining how React works or why React is awesome. My tutorial does not.
Instead, we’ll get right to building a simple UI, alternating between jQuery implementations and React.js implementations, explaining the differences along the way. I believe that you’ll think more this way as opposed to just typing out examples.
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.
Step 1: Introduction to JSBin (5 - 10 minutes)
We’ll be using JSBin, an online HTML/CSS/JS editor which supports both jQuery and React.js code. You might be familiar with similar services like CodePen or JSFiddle - they’re all pretty similar, so I just decided to go with JSBin.
Here’s an example JSBin:
JSBin not loading? Click here.
Try modifying the HTML on the left - i.e. change the button’s text. You’ll see the change on the right. That’s how JSBin works.
Create a JSBin Account
Unless you already have a JSBin account, head to jsbin.com to create an account. Click Login or Register on the menu to create an account.
After creating an account, you can clone public JSBins to your account, just like you clone public GitHub repositories.
Let’s try it. Click “Save” on the menu on the JSBin below.
JSBin not loading? Click here.
Once you’re on the JSBin site, you can select “Add Library” from the menu to import popular CSS/JS libraries.
Try doing the following:
- Click “Add Library” and add the latest Bootstrap
- Add
btn btn-primary
classes on
And the output becomes a little prettier:
JSBin not loading? Click here.
Create a Tweet Box
You seem to be pretty comfortable with JSBin now. Alright, let’s build out a Tweet box. Still on the same JSBin as before, change the HTML inside like this:
We’re using Bootstrap classes like form-control
, well
, clearfix
, etc., but those are just for the looks and irrelevant for the tutorial. Here’s the result:
JSBin not loading? Click here.
That’s it for this step! Not too bad, eh?
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:
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.
Here’s the demo. As you can see, the button is initially disabled. If you type something into the text box, the button becomes enabled.
JSBin not loading? Click here.
To get this to work, continue from the previous JSBin, open the JavaScript tab, and add the following jQuery code. You don’t need to add jQuery because Bootstrap, which we added on the previous step, includes 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
andtextarea
, as selectors - no need to add IDs/classes for this trivial example. - To enable/disable the button, use
$(...).prop(disabled, ...)
. - To listen for the changes in
textarea
, use theinput
event, which works on modern browsers.
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.
Now that this feature is complete, we’ll try to re-implement the same thing using React. This will take several steps.
Step 3: The Tweet Box Using React.js (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.
Let me show you what I mean. Here’s the React.js code which displays the same Tweet box.
WARNING! You don’t need to follow along yet - just read the code.
JSBin not loading? Click here.
Some observations:
- Inside
return (...)
is HTML code, not JavaScript. In React, you’ll write in a special syntax called JSX, which lets you put HTML-like code inside JavaScript. - I say HTML-“like” because it’s not identical to HTML. Notice that it uses
className
instead ofclass
- but they’re pretty similar, so you’ll learn them quickly. - Your browser does not understand JSX, so when React processes your JSX code, it automatically converts the HTML part inside JSX into valid JavaScript code so that the browser can understand it.
- The HTML code inside
return (...)
is pretty much identical to the HTML code from step 1. - Try clicking on “HTML” on the above JSBin, and you’ll see that there’s no markup in HTML besides
. This is what I mean when I said in React, you’ll be writing markup in JavaScript (JSX), not in HTML.
Frequently Asked Questions & Answers
Question: What do Question: Do I need to do anything special to write JSX on my local machine? Question: Isn’t it a bad style to write markup (HTML) and behaviors (JS) in the same place? Next, I’ll show you how to write the above React code step-by-step. I created a starter HTML file for you. Using “Add library,” I’ve imported Bootstrap (removed bootstrap.js and jquery) and React (without addons). Please try to follow along. To begin, click “Save” to copy this to your JSBin. JSBin not loading? Clnotaick here. After saving to your JSBin, open the JavaScript tab and select “JSX (React)”: Now you’re ready to write some React. Try to follow along and type the following JS code snippets on your JSBin. This is the template for creating a piece of UI using React (in this case, a Tweet box). It’s just as essential as To actually construct the UI, we must fill in the Like the above example, put a pair of parenthesis There’s one thing you need to remember with JSX - on So the following doesn’t work because there’s zero outer-most tag: This also doesn’t work because there are two outer-most ( For the above example, the workaround is to create an extra tag which wraps the two Now we need to “attach” this UI to the DOM in order to see (Note: an ellipsis ( Now, you should see Now, instead of There are two things you need to watch out for: Everything else should be the same with the jQuery example from before. If you typed this correctly, then you should see the Tweet box on your JSBin. If nothing appears in the output, then check your code very carefully, to make sure there aren’t any typos. That’s it for this step! Here’s the JSBin up to this part: JSBin not loading? Click here. We’re going to re-implement in React the first feature we implemented using 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. Here’s the jQuery code we wrote: JSBin not loading? Click here. Let’s see how we can do this in React. Start with the JSBin from the previous step. (Tip: Since you won’t be touching HTML in React, you can close the HTML tab on JSBin so you can get more screen space). First, let’s disable the button by adding Then the button should now be disabled. Note that in our jQuery implementation we wrote: to initially disable the button, but we could have instead modified the Now, we need to enable the button when there’s at least one character in the text field. First, we need to wait when users enter the text. In our jQuery implementation, we wrote: In the React land, we write the event handler as a method. Let’s call it Next, we invoke this handler when text is entered. To do so, modify the To make sure that the handler is indeed being called, let’s add The In your JSBin, open the You can try it out here: JSBin not loading? Click here. That’s it for this step! We’ll finish this feature on the next step. NOTE: Close the console tab on JSBin when you’re done. We no longer need it. I’ll now explain one of the biggest differences between jQuery-style code and React.js-style code. In jQuery, when some event happens, you usually change the DOM (like we did earlier): In React, you don’t directly modify the DOM. Instead, in an event handler, you modify something called the “state”. And this is done by calling Then, every time the state is updated, This is how you update the UI in response to an event. Yes it’s confusing, so let me explain using code. Start with the JSBin from the previous step. First, we need to initialize the state object - without this, nothing will work. To do this, we need to write a special method called What goes in the object? Let’s create a single key called Next, we’ll modify the event handler to set the state’s Now, let’s check that the state is correctly being set by writing some debug-only code in To do this, simply add Now, try entering some text on the tweet box. The same set of text should appear below the button. You can try it out on the JSBin below as well: JSBin not loading? Click here. Now the previous diagram might make more sense to you. Once you confirm that the state is correctly being set, remove the debugging code we just added: Now that we can watch for the text changes, all that’s left is to enable/disable the button depending on whether the text is entered. Using the state, we can use this logic: To do this in React, add If you write This works with other boolean attributes like The resulting JSBin is here: JSBin not loading? Click here. Again, keep this difference between jQuery and React in mind before moving onto the next step: The next feature we’ll implement is the remaining character count. Here’s the spec: We’ll first implement this in jQuery, then in React. We’ll start with our previous jQuery implementation. We’ll put our React.js code on hold. From now on, 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. JSBin not loading? Click here. First, add character count in HTML using And inside the That’s it! Try typing in the Tweet box and you’ll see the character count update. Here’s the JSBin: JSBin not loading? Click here. How about in React? You should try doing this on your own. Start with our previous React implementation. JSBin not loading? Click here. (Tip: Since you won’t be touching HTML in React, you can close the HTML tab on JSBin so you can get more screen space). Hint: Add this after Here’s the JSBin: JSBin not loading? Click here. Too easy? Not sure why React.js is so much better than jQuery? Well, the next step has more complexity, and this is when React.js really shines. For our next feature, we’ll add an “Add Photo” button to the UI. This is when things get tricky. However, we will not actually let users upload photos. Instead, here’s what we’re going to do. When you upload a photo on Twitter, it counts against the number of characters you can use. On my attempt, it decreased the number of remaining characters from 140 to 117: So that’s what we’re going to do. Here’s the spec: Here’s the demo JSBin. Try clicking the “Add Photo” button and see what happens to the character count and the Tweet button. JSBin not loading? Click here. Let’s implement this. We’ll first try with jQuery. Start with our previous jQuery implementation. JSBin not loading? Click here. We’ll modify both the HTML and JS. Before, we were attaching a handler to Here are the changes: Next, rewrite the entire JS file like this: Here are the changes: Next, we’ll implement one of the features: To do this, let’s add this piece of code: We use the class Next, we’ll implement this feature: To do this, modify the click handler we just added like this. We change Check to see that this works by clicking the “Add Photo” button. This is not complete however - if you have the “Add Photo” button ON and start typing on the text area, the remaining character count goes out of sync. To fix this, we also need to update the input handler for Check to see that this works by clicking the “Add Photo” button and typing some text. But stick with it! The jQuery code here is supposed to be confusing, so don’t worry! The last feature we need to implement is this: To do this, we need to modify the click handler of the “Add Photo” button: Here’s the explanation: We’re not done yet. The following steps will break the code. Try it out yourself: This means that our input handler for We add the following check to whether or not the button should be disabled: Try the above steps again and this time it won’t break. Here’s the final HTML and JS code from the previous step: JSBin not loading? Click here. 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 some comments so you remember what you did. There are clear signs of duplication, but you have to think a bit on how to refactor. The question is: why did it get so ugly so fast? And the answer has to do with the “jQuery style” of code we talked about previously. Recall this diagram: This is simple when there are only 1 event handler and 1 DOM. However, like we just saw, if several event handlers are modifying several parts of the DOM, the code gets ugly. Imagine adding some more features that could influence both the character limit and the “Tweet” button state. The above diagram will have even more arrows. And the code would become unmanageable. 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. (Update: Someone from Hacker News sent me the refactored jQuery code. Very clean but again, it requires some thinking.) Now, let’s see how it’s like to do the same thing in React. Hint: It’s going to be much simpler. Start with our previous React implementation. JSBin not loading? Click here. (Tip: Since you won’t be touching HTML in React, you can close the HTML tab on JSBin so you can get more screen space). First, let’s add the “Add Photo” button. Modify the JSX: Now, let’s add a click handler to this button so that the text changes from We will: For (1), we’ll modify For (2), we’ll modify the JSX markup for the “Add Photo” button. We’ll have the button say “Photo Added” if Finally, for (3), we’ll attach a click handler on JSX like we did for And add a handler method which reverses Now, clicking on We’ll now implement the next feature: Currently, the number of available characters is displayed as follows in This will now also depend on However, in JSX, you can’t write Usually the simplest way in this situation is to refactor a conditional into a method. Let’s try it. First, modify the above code to use a method, like this: And define the method like this: Now, the remaining character count should update accordingly when the “Add Photo” button is toggled. Question: In Good question. Let’s take a look at Answer: We’ve got one more feature to implement: This is actually really easy to do. Previously, the Tweet button’s In other words, previously the “Tweet” button was disabled if the text’s length was 0. Now, the “Tweet” button is disabled if: So the logic becomes like this: Or, you can simplify the above code by utilizing That’s it! Try toggling the “Add Photo” button and check that the “Tweet Button” is enabled/disabled correctly. That was easy. Here’s the resulting JSBin: JSBin not loading? Click here. The changes to accommodate the “Add Photo” button were minimal when using React. No refactoring needed. Why is this the case? 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 In this particular example, the diagram now looks like this: The state becomes an intermediary thing which sits in between the event handlers and 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. 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. 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 Instead, we’ll be displaying an alert box on top and indicate which characters need to be deleted, like this: To try it out, copy the following quote by Steve Jobs: If you haven’t found it yet, keep looking. Don’t settle. As with all matters of the heart, you’ll know when you find it. And, like any great relationship, it just gets better and better as the years roll on. And paste it into the Tweet box below: JSBin not loading? Click here. If we were to implement this in jQuery, our code will be even 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 in React and call it a day. It’d be pretty simple to do in React - just one extra arrow on the diagram: Start with our previous React implementation. JSBin not loading? Click here. We’ll do this step by step. First, we’ll display a simple alert when you write past the limit. The alert will have some static text. Since this will require a conditional, let’s write it in a separate method. Add Now, this method should return: It turns out that in React, you can return JSX markup from a method and use this in some other method, everything will just work. In other words, you can do something like: In our case, we can return Notice that we’re checking Try this out by typing 140+ characters (or 117+ characters with the “Add Photo” button ON). It should show the alert. Here’s the breakdown of what goes inside the alert message: Let’s write this in JSX. Inside the Copy paste this text again and see that the correct texts are highlighted. We’re almost done! If you haven’t found it yet, keep looking. Don’t settle. As with all matters of the heart, you’ll know when you find it. And, like any great relationship, it just gets better and better as the years roll on. If the “Add Photo” button is ON then the character limit decreases by 23. So our Now, try toggling the “Add Photo” button while entering any text that’s longer than the limit. It should work correctly. Here’s the JSBin: JSBin not loading? Click here. That’s it! Again, you can see that the code changes were simple: This concludes my tutorial. Hopefully you learned: 2jQuery在react中使用案例,参考案例:https://taylorlovett.com/2015/08/05/modifying-the-dom-with-jquery-within-react-components-in-isomorphic-applications/ React works awesome within isomorphic JavaScript applications. There are a number of frameworks and design patterns available for accomplishing this. My personal favorite is Fluxible. In an isomorphic application, your JavaScript renders views both server side and client side. Essentially the same view code is being executed client side and server side. At first it was hard for me to wrap my head around that concept. React components can be used to implement those views. jQuery, especially it’s UI libraries, is a useful client side tool. Since jQuery itself relies on a client side DOM, we can’t use it server side. Therefore we need to execute jQuery code in our React components but only during client side renderings. Here is an example ES6 React component using JSX. Let’s pretend we are using this as a view in an isomorphic JavaScript application where it is being rendered both server side and client side: Let’s use the jQuery tooltip plugin to power our tooltip. First make sure you include jQuery and the tooltip plugin in your page output. It usually makes sense to add external scripts to your base React component. Let’s setup our tooltip code: First, we added a Are you interested in migrating your existing jQuery project to React? Maybe you’re just interested in using a jQuery plugin in your project and there’s no React component that handles your needs. Using a lot jQuery plugins in your React project is not something that I would encourage, but in these situations wrapping a jQuery plugin with React might be your best option. The first step when wrapping a jQuery plugin with React is to create a component to manage the jQuery plugin. This component will provide a React-centric view of the jQuery component. In this tutorial I’ll show you how to: To make it easier to follow along, I’m going to provide a real world example. If you didn’t know, truncating multi-line content is non-trivial on the web. Fortunately there’s a jQuery plugin that can help us with this: jQuery.dotdotdot, advanced cross-browser ellipsis for multiple line content. Let’s start by looking at an example using the jQuery plugin and we’ll slowly convert it over to React. You can also see the original jQuery implementation in action. I have consolidated this example to a single file so that it is easy for you to try on your own. See the code in action at JSBin class='dotdotdot'> Cincinnati paul brown stadium freedom center historic architecture rivertown central christian moerlein fifty west 1788 union terminal river front slavery cyclones midpoint music festival. 1788 fifty west humid john roebling otr. Washington park city reds cincinnati coffee emporium humid main street hyde park. Freedom center hyde park zinzinnati over-the-rhine museum center immigrants city walnut hills washington park flying pig oktoberfest isaac m. wise temple cyclones city beat union terminal reds. class='dotdotdot'> Cincinnati paul brown stadium freedom center historic architecture rivertown central christian moerlein fifty west 1788 union terminal river front slavery cyclones midpoint music festival. 1788 fifty west humid john roebling otr. Washington park city reds cincinnati coffee emporium humid main street hyde park. Freedom center hyde park zinzinnati over-the-rhine museum center immigrants city walnut hills washington park flying pig oktoberfest isaac m. wise temple cyclones city beat union terminal reds. In general I like to solve really small problems and iteratively add complexity. Let’s start by getting jQuery, jQuery.dotdotdot, and React working together. We can then use the component in our code: In all but the most trivial cases you’re going to need to pass configuration options to the jQuery plugin. Instead of hardcoding this into our component, we can pass the configuration in via component props. Don’t ask me why, but you’re interested in using ☃ instead of ellipsis. We can setup the component to pass the prop down to the jQuery plugin. This works, but there are a few drawbacks: We can use Object Rest Destructuring to extract only the options that we want to pass down. Now any option that the plugin supports now (or in the future) is handled automatically. Many jQuery plugins provide a mechanism for cleaning up after themselves when they’re no longer needed. DotDotDot provides an event that we can trigger to tell the plugin to unbind its DOM events, remove CSS classes, etc. React Lifecycle Methodscomes to the rescue again and provides a mechanism to hook into when the component is being unmounted. You can see the final version working with React here Wrapping jQuery plugins with React isn’t always the best choice, but it is nice to know that it is an option. It is a viable option if you’re migrating a legacy jQuery application to React or maybe you just can’t find a React plugin that suits your needs. This is not the first time that I have been interested in how jQuery and other JavaScript frameworks interact, 2 years ago I took a look at integrating jQuery Knob with Angular. One thing that I did not cover in this article is integrating React into your existing codebase. We’re big fans of Ruby on Rails and we’ve had great success integrating React and Rails via the most excellent react-rails. I recommend looking for similar plugins for your platform if you are considering migrating your project to React. 转载于:https://www.cnblogs.com/MiWang/p/6114106.htmlReact.createClass
and ReactDOM.render
do? Do I need to understand them now?
Answer: Don’t worry about it for now. Basically, React.createClass
creates a piece of UI with a name (in this case, TweetBox
). This then gets attached to the DOM through ReactDOM.render(
- meaning this UI is added inside the
Answer: Yes, but that’s outside the scope of this tutorial - in short, you need to import something called JSX transformer (here’s how). This step is not necessary on JSBin though. All you need to do to write JSX on JSBin is to (1) add a React library (the one without addons) from the dropdown and (2) select “JSX (React)” from the dropdown menu on the JS view.
Answer: It might be a bad style 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 its own markup and behaviors. The code will be more manageable if those 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 was actually created and used by Facebook, one of the largest web applications ever.Step 4: Writing Your First React.js Code (5 - 10 minutes)
var TweetBox = React.createClass({
render: function() {
}
});
$(function() { ... })
on jQuery.render()
method. For now, let’s keep it simple with just a single div
tag.var TweetBox = React.createClass({
render: function() {
return (
(...)
after return
, and write the markup inside.JSX Gotchas
render()
, there must be exactly one outer-most tag inside return (...)
.return (
Hello World!
);
span
) tags inside return (...)
:return (
Hello
World
);
span
tags. I just used div
here. This is a necessary evil when using React.return (
Attaching the UI to the DOM
Hello World
. To do this, add ReactDOM.render()
below the code we just wrote:var TweetBox = React.createClass({
...
});
ReactDOM.render(
...
) on 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 UI object, which is
. The second argument is the DOM object (in this case, document.getElementById("container")
). Put together, the above code renders the TweetBox
UI inside Hello World
appear on your JSBin. Congratulations, you wrote your first React UI!Write the Actual HTML for the Tweet Box
Hello World
, we’ll implement the HTML for the Tweet Box. Swap the code inside render()
with this:return (
class
. Instead, use className
. It’s because JSX gets translated to JS, and class
is a keyword in the newest version of JS.
instead of
, it won’t work. Make sure to put /
on self-closing tags.Step 5: Re-implement the First Feature - Tweet Button Should Initially Be Disabled - in React (5 - 10 minutes)
disabled
.render: function() {
return (
...
...
);
}
$("button").prop("disabled", true);
button
tag like above.Handle Change Event
$("textarea").on("input", function() {
...
}
handleChange
:React.createClass({
handleChange: function(event) {
},
render: function() {
...
}
});
textarea
tag in render()
like this:
input
event for jQuery, but in React we use onChange
- you’ll learn about how events differ in React’s JSX from React’s documentation, so don’t worry too much now.{...}
syntax to include any JavaScript code inside the HTML syntax part of JSX. In this case, we want to pass the handler handleChange
, and we prefix it with this.
because it’s a method on this UI object.console.log
inside handleChange
:handleChange: function(event) {
console.log(event.target.value);
},
event
object contains target
, which is the textarea
. We use .value
on it to output the current value of the textarea
.console
tab to check the output. Then type something on the Tweet box.Step 6: Implementing State (10 - 15 minutes)
this.setState
.render()
is called again. And inside render()
you can access the state.Writing the Event Handler
getInitialState
and have it return a JS object, which becomes the initial state.text
and have it store whatever is inside the Tweet box.var TweetBox = React.createClass({
getInitialState: function() {
return {
text: ""
};
},
handleChange: ...
render: ...
});
text
field to whatever is currently in the text box. To do this, we use a special built-in method called setState
and pass the updated key-value pair.handleChange: function(event) {
this.setState({ text: event.target.value });
},
render()
.this.state.text
near the end of render()
, and use the { ... }
syntax to call JS code inside the HTML syntax part of JSX.render: function() {
return (
{this.state.text}
Remove the Debugging Code
{this.state.text}
Enabling/Disabling the Button
this.state.text.length === 0
, then the button should be disabled.disabled
attribute, and set it with the return value of this.state.text.length === 0
. Since this is JS code, you need to wrap it with {}
.
disabled="true"
or disabled="false"
in raw HTML it won’t work - in raw HTML, you need to remove the disabled
attribute to enable the button. But React is not raw HTML - it does the following magic behind the scenes:
disabled={true}
in JSX, it gets converted to just in HTML.
disabled={false}
in JSX, the disabled
attribute is removed from the button
tag in HTML.checked
. This is not officially documented as of writing, but it should be included soon.Reflections
render()
to reflect the current state.Step 7: Remaining Character Count in jQuery (5 minutes)
140 - the number of characters entered
.span
. Let’s set it as span
:
140
input
handler in JS, add this code to update the character count:$("textarea").on("input", function() {
$("span").text(140 - $(this).val().length);
...
});
Step 8: Remaining Character Count in React.js (5 minutes)
getInitialState()
or handleChange()
this.state.text.length
in render()
.Answer:
in render()
:{140 - this.state.text.length}
Step 9: The “Add Photo” Button (5 minutes)
✓ Photo Added
.Step 10: The “Add Photo” Button, in jQuery (15 - 20 minutes)
$("button")
, but this won’t work if there are two buttons. So let’s modify the HTML like this:...
...
js-tweet-button
and js-add-photo-button
to each button. They’re prefixed with js-
because they are used only in JS and not in CSS.disabled
attribute to the Tweet button so I don’t have to do this in JS.$("textarea").on("input", function() {
$("span").text(140 - $(this).val().length);
if ($(this).val().length > 0) {
$(".js-tweet-button").prop("disabled", false);
} else {
$(".js-tweet-button").prop("disabled", true);
}
});
$("button").prop("disabled", true);
from the first line because I added disabled
attribute to the Tweet button,$("button")
with $(".js-tweet-button")
so it can be distinguished from .js-add-photo-button
.Adding the Button
✓ Photo Added
.$("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");
}
});
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.Decrement Character Count
if ($(this).hasClass("is-on")) {
$(this)
.removeClass("is-on")
.text("Add Photo");
$("span").text(140 - $("textarea").val().length);
} else {
$(this)
.addClass("is-on")
.text("✓ Photo Added");
$("span").text(140 - 23 - $("textarea").val().length);
}
span
’s text on every click. If the button becomes ON, then we need to subtract the text length from 117, which is 140 - 23
. We use 140 - 23
for clarity now - eventually we should use constants.Fixing the Input Handler
textarea
:$("textarea").on("input", function() {
if ($(".js-add-photo-button").hasClass("is-on")) {
$("span").text(140 - 23 - $(this).val().length);
} else {
$("span").text(140 - $(this).val().length);
}
if (...) {
...
});
I know this is taking some time…
Implement the Final Feature
$(".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);
}
});
if
clause), we need to check if there’s no text entered and if so, disable the “Tweet” button.else
clause), we always enable the “Tweet” button.But again, this is broken
textarea
is missing some logic. To fix this, we need to add another condition to the if
statement in the input handler.$("textarea").on("input", function() {
...
if ($(this).val().length > 0 || $(".js-add-photo-button").hasClass("is-on")) {
...
} else {
...
}
});
Step 11: Reflection on the jQuery Code - Why So Confusing? (5 minutes)
Step 12: The “Add Photo” Button, in React (10-20 minutes)
Adding the Button
Add Photo
to ✓ Photo Added
. Recall the React style of writing code:
render()
to decide whether to show Add Photo
or ✓ Photo Added
.getInitialState
and add a key-value pair in the state to keep track of whether the photo is added or not:getInitialState: function() {
return {
text: "",
photoAdded: false
};
},
this.state.photoAdded
is true. We can just use a ternary expression here.
textarea
:
this.state.photoAdded
:togglePhoto: function(event) {
this.setState({ photoAdded: !this.state.photoAdded });
},
Add Photo
should toggle the text. Try it out yourself.Decrement Character Count
render()
:{140 - this.state.text.length}
this.state.photoAdded
, so we need an if
and else
here.if
or else
inside { ... }
. You can use a ternary expression (a ? b : c
) like we did before, but that would be pretty long in this case.{ this.remainingCharacters() }
remainingCharacters: function() {
if (this.state.photoAdded) {
return 140 - 23 - this.state.text.length;
} else {
return 140 - this.state.text.length;
}
},
render()
, why does { this.remainingCharacters() }
have ()
but { this.handleChange }
and { this.togglePhoto }
don’t?render()
again:render: function() {
return (
...
...
{ this.remainingCharacters() }
...
remainingCharacters()
method to return a number. We need to get this number and put it in between , so we need to call
remainingCharacters()
method by using ()
. That’s why there’s ()
in remainingCharacters()
.handleChange
and togglePhoto
are event handlers. We want these methods to be called only when the user interacts with the UI (changing the text or clicking the button). To do so, in render()
, we need to write them without ()
and assign them to attributes like onChange
and onClick
.The “Tweet” Button’s States
disabled
option was set as:
remainingCharacters()
. If there are 140 characters remaining, that means that no text is entered and that the “Add Photo” button is OFF, so the “Tweet” button should be disabled.
We’re Done!
Step 13: Reflection on the React Code - Why So Simple? (5 minutes)
render()
again to update the UI.render()
:
render()
, all you need to worry about is what the current state
is.Compare with jQuery
Step 14: The Final Feature - Highlighting Overflown Characters (5 minutes)
textarea
to contenteditable
, and contenteditable
is a bit too complicated for illustrative purposes.
Step 15: Highlighting Overflown Characters in React (10 - 15 minutes)
{this.overflowAlert() }
in front of the text box:{ this.overflowAlert() }
someMethod: function() {
return (
Hello World
);
},
someMethod2: function() {
return (
{ this.someMethod() }
);
},
(
on one condition, and nothing on the other. So our overflowAlert
method will look like this:overflowAlert: function() {
if (this.remainingCharacters() < 0) {
return (
this.remainingCharacters()
to see if we should show the alert or not.Displaying Overflown Characters
here because when writing markup in React, white spaces between tags get removed.this.state.text
.if
clause of overflowAlert
, we’ll create two variables: beforeOverflowText
and overflowText
. We’ll use .substring()
method on this.state.text
.if (this.remainingCharacters() < 0) {
var beforeOverflowText = this.state.text.substring(140 - 10, 140);
var overflowText = this.state.text.substring(140);
return (
.substring(a, b)
, it will return a + 1
th through b
th characters from the string..substring(a)
, it will return a + 1
th through last characters from the string.bg-danger
class to highlight the text in red.
What if the “Add Photo” button is ON?
beforeOverflowText
and overflowText
need to take that into account:if (this.state.photoAdded) {
var beforeOverflowText = this.state.text.substring(140 - 23 - 10, 140 - 23);
var overflowText = this.state.text.substring(140 - 23);
} else {
var beforeOverflowText = this.state.text.substring(140 - 10, 140);
var overflowText = this.state.text.substring(140);
}
Step 16: What’s Next? (5 minutes)
Modifying the DOM using jQuery within React Components in Isomorphic Applications
import React from 'react'; class MyComponent extends React.Component { render() {
import React from 'react'; class MyComponent extends React.Component { componentDidMount() { jQuery(React.findDOMNode(this.refs.tooltip)).tooltip(); } render() {
ref
tag to our tooltip. This let’s us reference our component node later. We then added a componentDidMount
method. componentDidMount
executes after initial rendering on client side only. Refer to the React lifecyclefor more details on this. React.findDOMNode
selects our tooltip node based on ref
. We then wrap the node in jQuery and call the jQuery tooltip method. Since componentDidMount
executes client side only this works perfectly and doesn’t cause any issues with our server side rendering.Wrapping jQuery with React
An Approach
An Example
Original jQuery Example
charset="utf-8"> name="viewport" content="width=device-width">
1. Create a component
const DotDotDot = React.createClass({ componentDidMount: function() { // Every React component has a function that exposes the // underlying DOM node that it is wrapping. We can use pass that // DOM node to jQuery and initialize the plugin. // You'll find that many jQuery plugins follow this same pattern // and you'll be able to pass the component DOM node to jQuery // and call the plugin function. $(ReactDOM.findDOMNode(this)).dotdotdot(); }, render: function() { return <div> {this.props.text} </div>; } });
<DotDotDot text="Text that you want to truncate" />
2. Pass configuration options via props
componentDidMount: function() {
$(ReactDOM.findDOMNode(this)).dotdotdot({ ellipsis: this.props.ellipsis }); }
<DotDotDot
ellipsis="☃"
text="Text that you want to truncate" />
componentDidMount: function() {
// We know that text is a prop that we don't want to pass to dotdotdot // because it's part of our API, not dotdotdot, so we extract that and // pass everything else down. const { text, ...config } = this.props; $(this.getDOMNode()).dotdotdot(config); }
<DotDotDot
callback={this.handleTruncation} fallbackToLetter={false} text="Text that you want to truncate" watch={false} />
3. Clean up after yourself
componentWillUnmount: function() {
$(ReactDOM.findDOMNode(this)).trigger('destroy.dot'); }
Conclusion
const DotDotDot = React.createClass({ componentDidMount: function() { const { text, className, ...options } = this.props; $(ReactDOM.findDOMNode(this)).dotdotdot(options); }, componentWillUnmount: function() { $(ReactDOM.findDOMNode(this)).trigger('destroy.dot'); }, render: function() { return <div className={this.props.className}> {this.props.text} </div>; } });