文章目錄
  1. 1. lint
  2. 2. no-string-refs
  3. 3. Jest render fail?
  4. 4. Solution

嗯、取名無能。但最近在 lint 地獄,所以、來談談其中一個 airbnb/react 的 lint error:react/no-string-refs

lint

lint、其實也應該算是測試的一部份…吧?我是這摸認為的。撇開認為的寫法一致性等等的,也有怎摸寫才安全、怎摸寫才是貼近標準的寫法、有哪些寫法快要消失了這類的,都會有警示。

從以前 jslint 、 coffeelint 都沒有很在意啦~!每次一跑都紅字翻不完、更不喜歡,最近倒是體會到、雖然紅字很多,但是改改還是蠻好的,念歸念、煩歸煩,覺得符合 lint 還是一件很棒的事。

因為它代表了:

  • 程式持續的優化與進步。(<– 跟得上 standard 某方面也就是跟得上時代的腳步?畢竟最近 js 前進速度還是蠻快的咩~!)
  • 意外的發現可以讓測試 coverage 變好!

^^^^ 所以、整體感覺都很不錯的樣子,所以、決定只剩一張嘴的抱怨他了。

no-string-refs

react/no-string-refs 是怎摸樣的一個問題呢?就是字面上的、 React 的 ref 不能用 string,也就是…

1
<div ref="tryRef">try it</div>

以上這寫法是不可以的,他必須改成這樣

1
<div ref={ref => (this.tryRef = this)}>try it</div>

改完後、想想也是,會指定 refs 大概有幾種可能性:

  • 出現的馬上有某些事情發生,那 ref 帶入一個 function、執行某段程式、非常合理。
  • 某個 event listener 需要非 target (<– 就是非觸發 node) 來達到某些目的。
  • 也不一定是 event listener ,使用的時候,需要 ref node 達到目的。

前面兩種問題其實不大、的確都可以在正常的情況下,也就是已經 render 畫面, nodes 都存在了,然後可以正常的使用 this.resf.tryRef (舉例)。不會有 this.refs.tryRef == undefined 這種事情發生。但最後一種、很有可能不小心的在還沒 render 畫面的時候就呼叫了,那… 都還沒有 render 、怎摸會有 refs 呢?顯然不會有、所以、當然就 gg 啦~!

那、既然可能沒有 refs ,為什摸還要一個 this.refs 這樣的空間擺著呢?當然就不用啦!既然不用了、那… 當然 ref="tryRef" 這種定義方式完全可以不要了對吧!

以上是我腦補的過程啦~ 可能也不一定對,但整體前後看看好像蠻合理的樣子。也覺得這摸做蠻好的、就照著改了。

Jest render fail?

改得很開心、結果測試可能就 gg 了~。

以前寫 spec ,關於 render 測試,大概就是…. options 帶進去、然後可能用一下 innerHTML 或者 querySelector 看看有沒有包含某些重要的文字或 node 就可以結束這回合了。稱不上好不好,但、還行!

用 Jest 後,對、 Jest 很棒,對於 React 的測試真的很有幫助,對於 component 的 render 測試也很棒。btw ,不久前 Jest release 新的版本後,好像差蠻多的,一些寫法不太一樣了,新的請參考 tutorial-react ,下面寫法都還舊舊的歐~ T UT

1
expect(render()).toEqual(<a href="#go-btm">go buttom</a>);

當然、 snapshot-test 也很酷,但用意不太一樣啦~!

好、當 ref 是 string 的時候、我們測試可以這樣寫…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// demo component
class Sample extends Component {
render() {
return <input ref="tryRef" />;
}
}
/////////////
it('should render right', () => {
const instance = TestUtils.renderIntoDocument(<Sample />);
expect(instance.render()).toEqual(<input ref="tryRef" />);
});

而我們改寫不用 string-refs 的時候,還記得我們改完後的寫法嗎?來複習下…

1
<input ref={ref => (this.tryRef = ref)} />

React 很有趣,像這樣的寫法、每次重新 render , ref 都會是新的 function ,而我們知道… 因為是新的嘛,所以、新的跟舊的 function 當然是不一樣的,就跟複製O一樣、對、長得都一樣,但就是不一樣啊!

當然、這樣也不好啦~ 根據大大們的說法,都表示、這樣效能什摸的都不好,更糟糕的是…. 測試就會壞掉了!

Solution

那、那該怎摸辦?

簡單的說呢,就是把這段 ref => (this.tryRef = ref) 拿到 constructor 上定義,就跟我們 bind event function 一樣,將他們移到 constructor 定義就沒問題了!程式片段大概會像下面這樣:

BTW ,一些需要帶入額外參數的 event binding 也可以用類似的作法處理。

1
2
3
4
5
6
7
8
9
10
11
12
13
const Sample extends React.Component {
constructor(...args) {
super(...args);
this.setTryRef = (ref) => (this.tryRef = ref);
}
render() {
return (
<input ref={this.setTryRef} />
);
}
}
文章目錄
  1. 1. lint
  2. 2. no-string-refs
  3. 3. Jest render fail?
  4. 4. Solution