<style>
:host {
--color-primary: rgba(255, 102, 102, 0.8);
--spacing: 1.5625%;
}
:host > div {
background-color: rgba(0, 0, 0, 0.04);
padding: calc(3 * var(--spacing));
}
* {
//font-family: "FOT-Humming Std";
// font-family: "FOT-Skip Std";
// font-family: "FOT-Rodin ProN";
font-family: "FOT-RodinCattleya Pro";
// font-family: "FOT-Seurat ProN";
font-weight: 500;
line-height: 1.8;
box-sizing: border-box;
margin: 0;
padding: 0;
color rgba(0, 0, 0, 0.8);
}
h1 {
font-size: 130%;
}
h2 {
font-size: 120%;
}
h2:before {
content: '##';
}
h3 {
font-size: 110%;
}
h3:before {
content: '###';
}
h4 {
font-size: 100%;
}
h4:before {
content: '####';
}
h2,
h3,
h4 {
margin-bottom: calc(3 * var(--spacing));
border-bottom: 2px solid rgba(0, 0, 0, 0.24);
}
h2:before,
h3:before,
h4:before {
font-size: 80%;
color: rgba(0, 0, 0, 0.24);
padding-right: var(--spacing);
}
a:link {
color: rgba(0, 0, 0, 0.8);
border-bottom: 2px dotted rgba(0, 0, 0, 0.24);
text-decoration: none;
}
ul {
margin-left: calc(2 * var(--spacing));
list-style: none;
}
li {
margin-bottom: calc(2 * var(--spacing));
}
li:before {
content: '- ';
font-size: 80%;
color: rgba(0, 0, 0, 0.24);
padding-right: var(--spacing);
}
code,
pre {
font-family: Ricty;
}
code {
// background-color: rgba(0, 0, 0, 0.12);
// padding: calc(0.25 * var(--spacing)) calc(0.5 * var(--spacing));
// border-radius: calc(0.5 * var(--spacing));
padding: 0 calc(1 * var(--spacing));
}
code:before,
code:after {
color: rgba(0, 0, 0, 0.24);
content: '`';
}
pre {
font-size: 85%;
background-color: rgba(0, 0, 0, 0.04);
padding: calc(2 * var(--spacing));
margin: calc(2 * var(--spacing));
}
pre:before,
pre:after {
display: block;
color: rgba(0, 0, 0, 0.24);
content: '```';
}
pre > code {
padding: 0;
}
pre > code:before,
pre > code:after {
content: '';
}
strong {
font-weight: bold;
}
img {
max-width: 100%;
max-height: 100%;
}
blockquote {
font-size: 90%;
border-left: 4px solid rgba(0, 0, 0, 0.24);
padding-left: calc(2 * var(--spacing));
margin: 0 calc(2 * var(--spacing));
}
blockquote a {
font-size: 85%;
}
.center {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
}
.blue {
background-color: #31bdd9;
color: white;
}
.purple {
background-color: #a96dd8;
color: white;
}
.onlyHeading h2,
.onlyHeading h3,
.onlyHeading h4 {
border: none;
padding: 0;
margin: 0;
width: 100%;
text-align: center;
}
.onlyHeading h2:before,
.onlyHeading h3:before,
.onlyHeading h4:before {
content: '';
}
</style>
<style>
.title {
align-items: flex-start;
background: linear-gradient(hsla(0,0%,100%,.2),hsla(0,0%,100%,.2)),linear-gradient(82deg,#31bdd9,#a96dd8);
color: white;
}
.title h1 {
border-bottom: 2px solid white;
margin-bottom: calc(1.5 * var(--spacing));
padding: calc(1.5 * var(--spacing)) var(--spacing);
font-weight: 100;
font-size: 130%;
}
.title h1 strong {
font-weight: 500;
}
.title p {
padding: 0 var(--spacing);
font-weight: 300;
font-size: 95%;
}
</style>
Performance of rendering over 10k items using React
React反省会 @ Wantedly by @izumin5210
<style>
.profile {
justify-content: flex-end;
}
.profile img {
border-radius: 50%;
margin-bottom: var(--spacing);
border: 3px solid rgba(0,0,0,.06);
}
.profile a:link {
color: var(--color-primary);
text-decoration: none;
border: none;
}
</style>
@izumin5210 (Masayuki Izumi)
<style>
.people {
background-image: linear-gradient(hsla(0,0%,0%,.5),hsla(0,0%,0%,.5)), url(https://i.gyazo.com/4137bf47fb95274ddd7385b216c2d989.png );
background-position: center center;
background-size: contain;
background-repeat: no-repeat;
color: white;
}
</style>
の,話をします
React + ReduxのSPA
generatorとasync/await使い放題
ドメインロジックはredux-sagaからservice呼ぶ
Flow + ESLint
テストはドメインロジックがほとんど・E2Eはなし
css-module, PostCSS
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
1月末スタート
4/10リリース
エンジニアひとり(週2.5くらい)
APIとモバイルアプリのコード読みながら開発
リリース1週間前に増援
重い
やせたい
つながりが20000人以上いても
快適に利用できるように
検索・選択など,リストやアイテムの更新回数が増えがち
文字入力するたびにリストアイテム全件updateしていた
ReactiveX - Debounce operator
lodash.debounce
でコールバックの呼び出しを減らす
redux-saga
でも実装できる(後述)
※ throttleだとユーザの入力を取りこぼすので注意
参考: 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/
immutable
なデータ構造を提供
↓ こういうのができて便利
Object . assign ( { } , post , { title : "Title" )
{ ...post , title : 'Title' }
post . set ( 'title' , 'Title' )
React使い必見! Immutable.jsでReactはもっと良くなる | Wantedly Engineer Blog
shouldComponentUpdate
とimmutable
↓ こんなふうにしてた
import { is } from 'immutable'
shouldComponentUpdate({ user }: Props) {
return is(user, this.props.user)
}
対策
immutable
は変更なければ同一インスタンスが返るので,ふつうの比較演算子でOK
コレクションにis()
使うとヤバい
勝手にshouldComponentUpdate
定義してくれる君
props
とstate
の値をそれぞれshallowEqual
React.Component
→React.PureComponent
だけで充分な場合も多い
toJS()
も当然重い(recursiveなので)
Map#get()
とMap#has()
はO(1)ではない
↑ map
やfilter
が普通より重くなりやすい
100個を超えるcomponentがすべて描画されてた
画面外のものを描画するのは無駄
LazyLoad
内は画面内に入るまで描画されない
<LazyLoad height={80}>
<ContactItem
{...{user}}
/>
</LazyLoad>
Componentが1000を超えるとしんどい
<LazyLoad>
がばらばらにスクロール監視をしていた
<List
{...{ width, height, rowCount, rowHeight }}
rowRenderer={({ key, index: i, style }) => (
<ContactItem {...{ key, style, user: users.get(i) }} />
)}
/>
shouldComponentUpdate
or PureComponent
を使う
量の多いイベントはdebounce
やthrottle
を検討
immutable
のis()
やtoJS()
は重い
immutable
のget()
はhas()
はO(1)
ではない
画面外のComponentは描画しない
巨大なリストにはreact-virtualized
が有効