over 2 years ago

Linting React Babel projects

I use eslint to lint ES2015 + React projects. One problem I encounter with eslint is that it does not support the spread operator. I realized that I had to install babel-eslint to make this work. I have to modify .eslintrc to make it work with babel-eslint:

Then, I run eslint and got this error:

It turns out that if you are using eslint 2.0, you have to use babel-eslint 6.x.x. The detail is explained in this thread.

over 2 years ago

Do not use .bind() or Arrow Functions in JSX Props

I was learning eslint's react/jsx options and stumbled upon this rule react/jsx-no-bind:

A bind call or arrow function in a JSX prop will create a brand new function on every single render. This is bad for performance, as it will result in the garbage collector being invoked way more than is necessary.

The following patterns are considered warnings:

The following patterns are not considered warnings:

over 2 years ago

React ES6 class constructor super()

When writting React using the ES6 class syntax like this:

Two questions may arise:

1. Is it necessary to call super() inside constructor?
2. What is the difference between callling super() and super(props)?

Always call super() if you have a constructor and don't worry about it if you don't have a constructor

Calling super() is necessary only if you need to have a constructor. Take a look at this code:

The code above is perfectly valid. You don't have to call super() for every react component you create. However, if there is a constructor in your code, then you MUST call super:

The reason why this cannot be allowed before super() is because this is uninitialized if super() is not called [1]

You may think you can get away with an empty constructor without callling super():

ES6 class constructors MUST call super if they are subclasses. Thus, you have to call super() as long as you have a constructor. (But a subclass does not have to have a constructor)

Call super(props) only if you want to access this.props inside the constructor. React automatically set it for you if you want to access it anywhere else.

The effect of passing props when calling super() allows you to access this.props in the constructor:

To fix it:

There is no need to pass props into the constructor if you want to use it in other places. Because React automatically set it for you [2]

over 2 years ago

Webpack devtool source map

TL;DR

For development, use cheap-module-eval-source-map. For production, use cheap-module-source-map.

Disclaimer: The following result is based on a small project. The result may vary depending on the size of your project.

Webpack currently provides seven options to produce a source map. It is nice that it gives so many choices to developers, but it also downright horrible for beginners.

As a beginner, I find the offical document impossible to understand. So I decided to test it out myself. I am testing all of the options on a project with the following attributes:

1. 18 .js files (modules if you prefer) along with libraries they referenced are bundled into a bundle.js file
2. The bundle.js file is minified to 680 KB
3. I left a bug in the code on purpose so that I can see what's the differences between the source map options. The bug is on line #37 in a file named CreateLogForm.js
4. I wrote my code in ES6 and JSX and used babel to transpile it back to ES5
5. I tested the error in Chrome's debug tools:
1. I verfied the line number and the file name where the error orginated
2. I clicked on the linked error file and see if the original source is displayed

source-map

I am going to start out with this one because this option produces exactly what you would expect, a source map. After the bundling process, I got a bundle.js.map file:

• Size: 5.44 MB
• Bundle Time: 50949 ms (This is how long it took to pack the bundle. There are fonts, images and css being emitted by webpack, so this is not how long it took to produce the source map file. This is the result of running this operation once. Thus, it should not be interpreted as the average running time of the operation.)
• Bug Display:
• File name displayed correctly
• Line number displayed correctly (the line number matches the original source file's line number)
• The file referenced by the error: ./~/react-dnd/~/invariant/browser.js which is completely wrong

cheap-source-map

A SourceMap without column-mappings. SourceMaps from loaders are not used.

No idea what that means, but this time:

• Size: 698 B
• Bundle Time: 46098 ms
• Bug Display:
• File name displayed correctly
• Line number displayed incorrectly (the line number matches the transpiled file's line number instead of the original)
• The file referenced by the error: ./~/react-dnd/~/lodash/lang/isFunction.js which is completely wrong

cheap-module-source-map

A SourceMap without column-mappings. SourceMaps from loaders are simplified to a single mapping per line.

No idea what it is talking about:

• Size: 308 B
• Bundle time: 56611 ms
• Bug Display:
• File name displayed correctly
• Line number displayed correctly
• The file referenced by the error: ./~/react-dnd/~/dnd-core/lib/index.js which is completely wrong

Note: This is the best option for production because:

1. Both bundle.js and bundle.js.map are smallest
2. The correct file name and line number are provided

eval

Each module is executed with eval and //@ sourceURL

No .map file emitted and the bundle.js file size is increased to 2.34 MB:

• Size: N/A
• Bundle Time: 33879 ms
• Bug Display:
• File name displayed correctly
• Line number displayed incorrectly (the line number matches the transpiled file's line number instead of the original)
• The file referenced by the error: The transpiled code of the original source is displayed

eval-source-map

Each module is executed with eval and a SourceMap is added as DataUrl to the eval

No .map file emitted and the bundle.js file size is increased to 5.83 MB:

• Size: N/A
• Bundle Time: 34257 ms
• Bug Display:
• File name displayed correctly
• Line number displayed correctly (CreateLogForm.js?b337:37 I don't know what does the b337 portion stands for though)
• The file referenced by the error: The original source code is displayed

cheap-eval-source-map

No .map file emitted and the bundle.js file size is increased to 5.8 MB:

• Size: N/A
• Bundle Time: 40663 ms
• Bug Display:
• File name displayed correctly
• Line number displayed incorrectly (the line number matches the transpiled file's line number instead of the original)
• The file referenced by the error: The transpiled code of the original source is displayed

cheap-module-eval-source-map

No .map file emitted and the bundle.js file size is increased to 5.74 MB:

• Size: N/A
• Bundle Time: 40663 ms
• Bug Display:
• File name displayed correctly
• Line number displayed correctly (CreateLogForm.js?b337:37 I don't know what does the b337 portion stands for though)
• The file referenced by the error: The original source code is displayed

Note: This is the best option for development because it is the smallest option that shows the correct line number.

over 2 years ago

React event is null in setState callback

The code above prints an event object with nulls set to all of its properties. So you cannot access e.target.value or e.target.name as you normally would. This issue is explained in this thread:

Events are pooled so we wipe out their values. If you want to use the event outside the current event loop then you need to call ev.persist() which will pull that event out of the pooling.

I think what that means is that React resues a set of event objects instead of creating new event objects everytime an event comes up. persist() prevents it from cleaning:

almost 3 years ago

Django OneToOneField and Iterating Model's Fields

Two small issues I run into when dealing with OneToOneField and iterating through a model's fields.

One to One Fields

When models are defined like above, you can grab a reference to B this way:

Since B's primary key equals to A's primary key, when Django's ORM creating B in the database, it will not create an 'id' column. Instead, a column named 'A_id' is created. Thus, when ever you want to access B's primary key, you cannot do:

You have to use b_instance.pk instead.

Model's _meta field

I once had a task which needs to determine if any field within a model instance is empty. To do it, I need a way to loop through all of the fields defined in the instance first:

Here is the code for determining if a model instance is empty:

almost 3 years ago

Understanding Django's Formset 1

Django's formset can be difficult to understand, so I will try to explain it in a more understanbable way here.

What is it used for?

Let's say you are building a website which keeps track of users' daily activities. They can logon to your site and fill out a form with the following information:

• Date and time
• Activity name
• Duration

Multiple activities can be recorded throughout a day. When users start to record for a new day, he should see an empty form with the aforementioned fields and an add button below the form to add more activities:

In this case, you cannot predict how many activities users will add beforehand. Thus, you cannot create a form to prepare for it. This is when Formset comes in. Formset allows you to add/remove forms on the fly (with the help of javascript which I will talk about in detail later).

How it works?

Before getting into the implementation details, it is important to understand how formset works. The best way to learn it is to think out how you would implement it by hand.

Requirements

CRUD is a good starting point to define what needs to be accomplished：

• Forms need to be created (i.e. create new form data that do not exist in the database)
• Forms need to be read (i.e. fill forms with existing data and display them to the user)
• Forms need to be updated (i.e. fetch existing data and save changes made to them)
• Forms need to be deleted (i.e. delete an existing form)

To accomplish any of these tasks, we need a way to keep track of forms. Thus, an ID is needed for each form. Also, when a form is deleted, we need a way to detect that. Thus, a form needs to be marked as deleted or not deleted.

How does Django do it?

To manage which form is which and mark them as deleted when neccessary, Django insert hidden input fields into the rendered HTML to help itself keeping track of the forms. Django inserts the following hidden data:

All of these hidden data, are added by the ManagementForm. You don't need to read about ManagementForm at the moment, just knowing which componment within Django is responsible for these is enough at this point.

To keep track of each form, Django also inserts hidden primary keys that are associated with existing forms:

To keep track of which form has been deleted, Django also inserts a hidden field:

The can_delete parameter is responsible for marking forms as deleted. I will explain this parameter later.

This post is long enough for a short read. I will explain more details about formset in the next blog post.

almost 3 years ago

Django how to reverse urls belonged to other apps

When writing a Django project, it happens often that mulitple apps will be included. Let me use an example:

In this example, I created a Django project that contains two apps. The Account app handles user registration and login. The Journal app allows users to write journals and save it to the database. Here is the what the urls look like:

This above file is what the ROOT_URLCONF points to. Inside the Note app, the urls look like this:

So each journal has a 4 digit id. When a journal is access, it's url may look like this: www.mynote.com/note/1231/

Let's say user John bookmarked a journal written by another person. He wants to comment on it. When John tries to access that journal www.mynote.com/note/1231/, he is redirected to the login page. In the login page's view handler, a redirect should be made to Journal ID 1231 once authentication is passed:

The reverse(...) statement is not going to work in this case. Because the view_handler belongs to the Account app. It does not know about the urls inside the Journal app. To be able to redirect to the detail page of the Journal app:

So the format for reversing urls that belong to other apps is:

almost 3 years ago

Django create and login user manually

There are some pitfalls when you need to create and login users manually in Django. Let's create a user first:

Note that request.POST.get('username', None) should be used instead of request.POST['username']. If the later is used, you will get this error:

MultiValueDictKeyError

The above code is wrong. Because when create is used instead of create_user, the user's password is not hashed. You will see the user's password is stored in clear text in the database, which is not the right thing to do.

So you should use the following instead:

What if you want to test if the user you are about to create has already existed:

get_or_create will get the existing user or create a new one. Two values are returned, an user object and a boolean flag created indicating whether if the user created is a new one (i.e. created = True) or an existing one (i.e. created = False)

It is import to not forget including user.save() in the end. Because set_password does NOT save the password to the database.

Now a user has been created successfully, the next step is to login.

authenticate() only sets user.backend to whatever authentication backend Django uses. So the code above is equivlent to:

Django's documentation recommends the first way of doing it. However, there is an use case for the second approach. When you want to login an user without a password:

The is used when security isn't an issue but you still want to distinguish between who's who on your site.

So to sum up the code above, here is the view_handler that manually create and login an user:

almost 3 years ago

Javascript's Bitwise Not operator (tilde)

Saw this example on MDN:

According to the documentation,

Bitwise NOTing any number x yields -(x + 1). For example, ~5 yields -6.

So if a character exists within a string, indexOf will return the first occurance of that character's index which will either be an 0 or any positive nubmer.

Thus, the tilde operator will turn them into:

Any none zero number is considered a true in JS, so:

Thus, if str.indexOf() returns any number other than -1, ~str.indexOf() equals to a negative number, which will be considered True.

In the case of -1 is returns (i.e. the character does not exist in the string):

Thus, the else branch is executed.