Link
Embed
Share
Beginning
This slide
Copy link URL
Copy link URL
Copy iframe embed code
Copy iframe embed code
Copy javascript embed code
Copy javascript embed code
Share
Tweet
Share
Tweet
Slide 1
Slide 1 text
Performance of rendering over 10k items using React React反省会 @ Wantedly by @izumin5210
Slide 2
Slide 2 text
@izumin5210 (Masayuki Izumi)
Slide 3
Slide 3 text
Wantedly People for PC の,話をします
Slide 4
Slide 4 text
### 技術stack ‑ React + ReduxのSPA ‑ generatorとasync/await使い放題 ‑ ドメインロジックはredux‑sagaからservice呼ぶ ‑ Flow + ESLint ‑ テストはドメインロジックがほとんど・E2Eはなし ‑ css‑module, PostCSS
Slide 5
Slide 5 text
### dependencies ‑ `immutable` 3.8.1 ‑ `react` 15.5.3 ‑ `react-router` 4.0.0 ‑ `redux` 13.6.0 ‑ `redux-saga` 0.14.3 ‑ `reselect` 2.5.4
Slide 6
Slide 6 text
### 開発体制 ‑ 1月末スタート ‑ 4/10リリース ‑ エンジニアひとり(週2.5くらい) ‑ APIとモバイルアプリのコード読みながら開発 ‑ リリース1週間前に増援
Slide 7
Slide 7 text
反省
Slide 8
Slide 8 text
No content
Slide 9
Slide 9 text
重い
Slide 10
Slide 10 text
やせたい
Slide 11
Slide 11 text
目標 つながりが20000人以上いても 快適に利用できるように
Slide 12
Slide 12 text
renderingされる回数を減らす
Slide 13
Slide 13 text
No content
Slide 14
Slide 14 text
### `shouldComponentUpdate` ‑ 検索・選択など,リストやアイテムの更新回数が増えがち ‑ 文字入力するたびにリストアイテム全件updateしていた
Slide 15
Slide 15 text
#### 対策前
Slide 16
Slide 16 text
#### `shouldComponentUpdate` 適用後
Slide 17
Slide 17 text
### ユーザ入力のdebounce ‑ 「1文字入力するごとに再描画」はヤバい ReactiveX ‑ Debounce operator
Slide 18
Slide 18 text
#### debounceの実装 ‑ `lodash.debounce` でコールバックの呼び出しを減らす ‑ `redux-saga` でも実装できる(後述) ‑ ※ throttleだとユーザの入力を取りこぼすので注意
Slide 19
Slide 19 text
#### 参考: redux‑sagaによるdebounceの実装 ``` function* handleInput({ input }) { yield call(delay, 500) // debounce by 500ms // ... } function* watchInput() { yield takeLatest('INPUT_CHANGED', handleInput); } ``` https://redux‑saga.js.org/docs/recipes/
Slide 20
Slide 20 text
`immutable` まわりのチューニング
Slide 21
Slide 21 text
### `immutable` ‑ `immutable` なデータ構造を提供 ‑ ↓ こういうのができて便利 ``` Object.assign({}, post, {title: "Title") {...post, title: 'Title'} post.set('title', 'Title') ``` React使い必見! Immutable.jsでReactはもっと良くなる | Wantedly Engineer Blog
Slide 22
Slide 22 text
#### `shouldComponentUpdate` と `immutable` ↓ こんなふうにしてた ``` import { is } from 'immutable' shouldComponentUpdate({ user }: Props) { return is(user, this.props.user) } ```
Slide 23
Slide 23 text
Componentの更新が遅い問題
Slide 24
Slide 24 text
対策
Slide 25
Slide 25 text
### `Immutable.is()` は重い ‑ `immutable` は変更なければ同一インスタンスが返るの で,ふつうの比較演算子でOK ‑ コレクションに `is()` 使うとヤバい ‑
Slide 26
Slide 26 text
### `React.PureComponent` ‑ 勝手に `shouldComponentUpdate` 定義してくれる君 ‑ `props` と `state` の値をそれぞれ `shallowEqual` ‑ `React.Component` → `React.PureComponent` だけで充分 な場合も多い
Slide 27
Slide 27 text
### その他 `immutable` の注意点 ‑ `toJS()` も当然重い(recursiveなので) ‑ `Map#get()` と `Map#has()` はO(1)ではない ‑ ↑ `map` や `filter` が普通より重くなりやすい
Slide 28
Slide 28 text
Componentおおすぎ問題
Slide 29
Slide 29 text
### 画面外のものは描画しない ‑ 100個を超えるcomponentがすべて描画されてた ‑ 画面外のものを描画するのは無駄
Slide 30
Slide 30 text
### `react-lazyload` `LazyLoad` 内は画面内に入るまで描画されない ``` ```
Slide 31
Slide 31 text
#### スクロール監視してるやつ多すぎ問題 ‑ Componentが1000を超えるとしんどい ‑ `` がばらばらにスクロール監視をしていた
Slide 32
Slide 32 text
### `react-virtualized` ‑ スクロールを監視するのはリストの親のみ ``` ( )} /> ```
Slide 33
Slide 33 text
## Conclusion ‑ `shouldComponentUpdate` or `PureComponent` を使う ‑ 量の多いイベントは `debounce` や `throttle` を検討 ‑ `immutable` の `is()` や `toJS()` は重い ‑ `immutable` の `get()` は `has()` は `O(1)` ではない ‑ 画面外のComponentは描画しない ‑ 巨大なリストには `react-virtualized` が有効