Blackbing Playground

[ReactJS] tips of Writting JSX with CoffeeScript

由於一開始我沒有認真看 JSX (而且也很懶得看)就開始使用 coffeescript 來寫 React 了,所以一直沒有去搞懂 JSX 到底要怎麼寫,直到最近才開始認真使用 JSX 來開發,詳看上集。關於 jsx 的 tip 其實官方有介紹一些技巧與注意事項:可以參考 React Tips Introduction

因為自己習慣用 coffee 的關係,所以會遇到一些小問題,這篇文章主要紀錄一下用 coffee 寫 react 需要注意的地方與心得,本篇文章的程式碼也都是 coffeescript。

browserify

強烈建議一定要使用 browserify ,官方寫的 todomvc-flux就是用 browserify 來打包程式的,用了 browserify 之後就可以用 coffeeifyreactify 來 compile 程式了。

關於 browserify 的設定可以參考我的專案設定 https://github.com/blackbing/htccs-webapp/blob/master/gulp/tasks/browserify.coffee

jsx header

若程式之中有需要做 reactify 的程式要在第一行加上這行,讓 reactify 認得要 parse jsx 語法。

1
`/** @jsx React.DOM */`

jsx component

jsx 特有的語法就是用 element tag name 來當語法,例如:

1
2
3
4
5
var HelloMessage = React.createClass({
render: function() {
return <div>Hello {this.props.name}</div>;
}
});

用 coffee 來撰寫時就會用到 ``` 來轉成 javascript 再交給 reactify 來處理。

1
2
3
4
HelloMessage = React.createClass(
render: ()->
return `<div>Hello {this.props.name}</div>`
}

this and @

coffee 用 @ 代表 this,但小心不要在 jsx 語法裡頭用 @,因為被 `` 包住的部分會被當成 javascript 來處理,coffeeify不會去處理這部分。舉例來說。

1
2
3
4
5
6
HelloMessage = React.createClass(
onClick: ->
alert 'onClick'
render: ()->
`<div onClick={@onClick}>Hello {@props.name}</div>`
}

如此 @onClick 就會變成 undefined。應該要改成 this.onClick 來處理。像這樣:

1
2
3
4
5
6
HelloMessage = React.createClass(
onClick: ->
alert 'onClick'
render: ()->
`<div onClick={this.onClick}>Hello {this.props.name}</div>`
}

every component need a root parent

每一個 component 都需要一個 parent 來包住,例如你不能這樣寫 jsx:

1
2
3
4
5
6
HelloMessage = React.createClass(
render: ()->
`<div>Hello foo</div>
<div>Hello bar</div>
<div>Hello foobar</div>`
}

而是要用一個 element 包住:

1
2
3
4
5
6
7
8
HelloMessage = React.createClass(
render: ()->
`<div>
<div>Hello foo</div>
<div>Hello bar</div>
<div>Hello foobar</div>
</div>`
}

由於這可能會影響 HTML 的結構,需要跟 Designer 確定一些實做細節。

Empty text node will wrap by \

例如

1
`<th>type{foo}</th>`

會變成這樣

這可能會跟原本預期的不太一樣,為了避免樣式問題,可能要跟 Designer 確認避免產生空的文字節點。

Sperate component if there’s any logic control

用了 jsx 之後會發現遇到邏輯部分的程式會不太好寫。例如用 js/coffee 來寫的話會像是這樣。

1
2
3
4
5
6
7
8
9
10
11
HelloMessage = React.createClass(
render: ()->
R.div className="form-component"
if type is 'image'
R.img src:data.src
else if type is 'input'
if inputType is 'text'
R.input type:"text"
else if inputType is 'radio'
R.input type:"radio"
#...(skip)

而用 jsx 要在一個 render function 做這些判斷會看起來很可怕。建議盡量拆 component,拆 component 是不用錢的。由於 component 都是單一物件的設計,所以盡可能的將一個 component 的邏輯簡化。如上例,可以將裡頭的 if-else 判斷拆出去 FormItem,像這樣:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
FormItem = React.createClass
render: ->
data = @props.data
if data.type is 'image'
`<img src={data.src} />`
else if data.type is 'input'
if data.inputType is 'text'
`<input type="text" value={data.value} />`
else if data.inputType is 'radio'
`<input type="radio" value={data.value} />`
HelloMessage = React.createClass(
render: ()->
`<div className="form-component"
<FormItem data={data} />
</div>`
#...(skip)

這是一個很簡單的技巧也可以將 component 快速的拆開,不要嘗試在一個 component 裡頭包入太複雜的邏輯判斷。另一個好處是可以針對單一個 component 來做 unit-test。

false in jsx

false 在 jsx 裡頭有些不同的意義,在 http://facebook.github.io/react/tips/false-in-jsx.html 有說明,不過因為很重要所以要講三次

其中最重要的是 false element

1
`<div>{false}</div>`

這樣會變成 <div></div>,成為一個空的節點。在做一些邏輯判斷時還蠻好用的。

Never modify DOM by yourself

如果你開始使用 React 了,請戒掉用 jquery 操作 DOM 的「壞習慣」。真的,一開始會很不習慣,例如addClass('loading') 太方便了,但是摻雜使用的後果就是很難 debug。建議要做任何 DOM 的操作都交給 state/props 來決定。

如果有其他使用 React 的小技巧也歡迎分享喔~