jpnykw’s blog

軽率なアウトプットをします

styled-componentsでラップした複数の子要素に同じpropsを同時に渡す

タイトルの通りです。あるコンポーネント内で配下にある全ての子要素(styled-componentsでラップされたものであるとします)に共通したpropsを渡す場合のやり方の話です。愚直に書いていたらキリがなく最悪なコードが出来上がります。

結論

styled-components/ThemeContext を使おう。

import { ThemeContext } from 'styled-components'

具体例

まずこんな感じの複雑なコンポーネント Component が存在しているとします。多くのコンポーネントやDOMを内包していますが、それらは全てstyled-componentsでラップされています。

const A = styled.div`
  /* ... */
  ${props => props.value}
  /* ... */
`

const B = styled.div`
  /* ... */
  ${props => props.value}
  /* ... */
`

const C = styled.div`
  /* ... */
  ${props => props.value}
  /* ... */
`

// ...

const Z = styled.div`
  /* ... */
  ${props => props.value}
  /* ... */
`

const Component = () => {
  return (
    <Container>
      <A />
      <B />
      <C />
      {/* ... */}
      <Z />
    </Container>
  )
}

ここで、全ての(あるいは殆どの)内包したコンポーネントvalue という共通した値を使いまわしたいとします。(この valueuseContext などで更に上層から受け取ったものとします)

そんな時に、こんなこと↓なんてやていられません。

const Component = () => {
  return (
    <Container>
      <A value={value} />
      <B value={value} />
      <C value={value} />
      {/* ... */}
      <Z value={value} />
    </Container>
  )
}

こういうときは ThemeContext を使いましょう、一発で解決します。

const Component = () => {
  return (
    <ThemeContext.Provider value={/* 任意の値 */}>
      <Container>
        <A />
        <B />
        <C />
        {/* ... */}
        <Z />
      </Container>
    </ThemeContext.Provider>
  )
}

ただし、注意点として呼び出す際のpropsのプロパティがthemeになるので、既に違うプロパティで定義してる場合は修正しましょう。

- ${props => props.value}
+ ${props => props.theme}

また当然ではありますがthemeにオブジェクトを渡すことでpropsを一層ラップした状態でこれまで通りに値を扱えます。

interface Attrs {
  // 渡したいpropsの型定義
}

const A = styled.div`
  /* ... */
  ${({ theme: props }: { theme: Attrs }) => props.aaa}
  ${({ theme: props }: { theme: Attrs }) => props.bbb}
  ${({ theme: props }: { theme: Attrs }) => props.ccc}
  /* ... */
`

const Component = () => {
  const attrs: Attrs = { /* ... */ }

  return (
    <ThemeContext.Provider value={attrs}>
      <Container>
        <A />
        <B />
        <C />
        ...
        <Z />
      </Container>
    </ThemeContext.Provider>
  )
}

以上です。

GitHubの言語比率計算

知ってましたか?GitHubには、Repositoryごとに使用されている言語の比率を表示(計算)する素晴らしい機能があります。こんな具合に。

f:id:jpnykw:20200423142603p:plain

実はこの比率と言語は偽造できるんです。

事の発端

まず僕のツイートを見てください。ついでにフォローもしてください。


これはRust(WebAssembly)とReact+TSで開発しているインタプリタのRepositoryなのですが、メインで使用していないJavaScriptの割合が「一番多い」という由々しき事態がありました。原因はWebAssemblyが吐き出してるjsがminifyされていない(出来ない)ことが原因でした。

これはかなり嫌です、JavaScriptがではなく(ほんまか?)メインで使用していな言語がラベル付されて主張されているのが個人的に嫌だったんです。

出会い

この事があまりに嫌だったのでもう一回、同じようなツイートをしてしまいました。


するとディレクトリ単位でignoreできる、というリプをもらいました。ちなみにgitignoreと勘違いしてますがgitattirbutesというファイルのことらしいです。

linguist

ここに来てついにGitHubの言語比率計算はlinguistというツールが使われていることが判明しました。更には、configファイルを追加することで、あれこれ(例えば特定のディレクトリ以下のファイルを言語比率計算から除外するなど)出来ることが判明しました。

such as JavaScript libraries, into your git repo is a common practice, but this often inflates your project's language stats and may even cause your project to be labeled as another language.


copy from https://github.com/github/linguist#vendored-code

あまりに感動したので、座右の銘にしました。WasmによってトランスパイルされたJSを除外することは、まさにピッタリの用途です。

解決

というわけでやっちゃいました。こんな簡単なことだったとは。これにて無事、でかいケツゾロリしました。めでたしめでたし。



言語の偽装

# Example of a `.gitattributes` file which reclassifies `.rb` files as Java:
*.rb linguist-language=Java

ふむ

github.com

2020年 PIXIV TECH FES に参加した

2020年2月17日に開催された PIXIV TEC FES という最高なイベントに参加してきました.

conference.pixiv.co.jp

このイベントは完全招待制で, Pixivの社員の方に招待されないと参加できないようです. 僕の場合は未踏Jrで開発していたプロジェクトの関係上, シェーダー界隈の方々と繋がりがあったので, FMS_Cat*1さんに招待していただきました. (お声掛けいただきありがとうございました!)

内容が変わった

実は20:00から開催されるAFTER PARTY / LIVE PERFORMANCEがコロナウイルスの影響で中止になってしまいました. AFTER PARTYからが"""本番"""らしく, 僕も楽しみにしていたので残念でした.

しかし, その代わりに開場から開始までの1時間の間にDJ/VJパフォーマンスが開催されていました. これがその時の様子です. DJ/VJを生で見て滅茶苦茶感動しました. Live Codingってこんなに盛り上がるんだ. ヤバ太郎 (ボキャ貧).

始まりの時

17時ごろになるとパフォーマンスが終わって照明が落とされて画面全部にPIXIV TECH FES の文字が. いよいよ始まりを感じてドキドキが増してきました.

f:id:jpnykw:20200218143915p:plain

すると突然「「エモーーーーッショナル・スーパー・映像・オブ・エモい映像・ハイパーウルトラエモ映像」」が流れ始めました.

ライブ会場での開催だったことも有り, 音圧と映像が語感を支配してきました. テックイベントでこれはアツすぎる. ヤバいわよ! ということで動画最後にも写ってますがPixivのCTOの方の登場です.

Keynote Session

Keynote Sessionでは会社の取り組んでいる業務的な内容から技術的な内容までを社員の方々の発表形式で聞きました. Pixivの展開するサービスの紹介から, 規模など会社の概要から, Webエンジニアの方によるUI大改造の歴史のお話, App開発をするお話, データ駆動のお話, 基盤であるデータを良い感じに扱い監視するお話, 認証基盤のセキュリティ担保のお話などがありました. めちゃくちゃ為になります.

休憩

2時間にも及ぶKeynote Sessionも終わり, 休憩時間になりました. たまたまイベントにツイッタ上だけで知り合ってた方がいたのでエンカさせてもらい休憩中はお話してました.

休憩明け

小峠が登場しました. ガチで笑った.

f:id:jpnykw:20200218150632p:plain

f:id:jpnykw:20200218150655p:plain

LTバトル

最後のショートセッションは†新宿BLAZE LT BATTLE†という~潰し~戦い合いの激アツLT大会でした. 個人的に楽しみだったyui540*2さんのお話を聞けて満足でした. CSSは無料版After Effects.

最後に

冒頭でも書きましたが最高のイベントでした. 来年も開催予定らしいので, ぜひ参加したいですね. AFTER PARTY参加したい. 本当に楽しかったですありがとうございました

x86の除算命令

x86の四則演算を行う命令は add, sub, imul, idiv の4種類ある (左から, 加算, 減算, 乗算, 除算).
ここで左3つの命令は一般的な命令と同様に, 以下のBNFを満たす.

<instruction> ::= <register> "," (<register> | <value>)

しかし idiv だけ実装が特殊で, このようなことができない.
では, 具体的に x \div y を計算する方法について書く.

どうやるの

x=14, y=7 の時について

mov rax, 14
mov rdi, 7

それぞれの値をrax, rdiレジスタに退避させる.

cqo

符号拡張を行う転送命令で, この操作によって rax の値を 128bit integer に拡張し, rax, rdi レジスタへ格納する. これは idiv の仕様上必要な工程.

idiv rdi

さて, これが問題の idiv. この命令は rdx, rax を合わせた値を 128bit integer として扱い, それを第1オペランドレジスタの 64bit 値で割る. 商を rax, 余りを rdi レジスタに格納する.

全体像

実行できる様に全体を書く.

.intel_syntax noprefix
.global main

main:
  mov rax, 14
  mov rdi, 7
  cqo
  idiv rdi
  ret

完成. こいつをコンパイルすれば2が出力されるはず. こんな感じ.

f:id:jpnykw:20200207024531p:plain

では, 良いアセンブリライフを

x86でFibonacci

最近, Cコンパイラの自作を始めました. そこでサポートしてるアセンブリx86-64なので, アセンブリを理解する必要がりました. 折角なので, アセンブリを直接書いてfibonacciを作ってみようと思います.

雑設計

一応関数を分離して記述します.

.intel_syntax noprefix
.global main, fib

main:
    ...

fib:
    ...

実装

愚直に実装します. 条件分岐と再帰を書きます. ediレジスタの値を計算します. 引数をstackに詰んで引っ張り, cmpの演算結果に応じてL1, L2にjumpさせればOKです.

.intel_syntax noprefix
.global main, fib

main:
    push rbp
    mov rbp, rsp
    mov edi, 10 # index
    call fib
    pop rbp
    ret

fib:
    push rbp
    mov rbp, rsp
    push rbx
    sub rsp, 24
    mov DWORD PTR [rbp-20], edi
    cmp DWORD PTR [rbp-20], 1
    jg .L1
    mov eax, 1
    jmp .L2

.L1:
    mov eax, [rbp-20]
    sub eax, 1
    mov edi, eax
    call fib
    mov ebx, eax
    mov eax, DWORD PTR [rbp-20]
    sub eax, 2
    mov edi, eax
    call fib
    add eax, ebx

.L2:
    add rsp, 24
    pop rbx
    pop rbp
    ret

書けました.

index 0 1 2 3 4 5 6 7 8 9 10 ...
value 1 1 2 3 5 8 13 21 34 55 89 ...


0-indexedで考えると, 実行結果が89になっていれば良いですね. では, Linux環境*1で, gccを使ってアセンブリコンパイルして動かしてみます.

f:id:jpnykw:20200125155642p:plain

無事に出力されました 🎉

*1:Docker, VM上で可

Rustの所有権について

今回はRustの借用/参照と所有権について雑に書きなぐる.

所有権とは

所有権はRustに導入されているゼロコスト抽象化*1の例の一つ. 具体的な例を上げると, 変数が非primitiveな型*2である場合に, 以下のような問題に直面する.

fn some(x: Vec<i8>) {
  // TODO:
}

fn main() {
  let x = vec![2];
  some(x);
  println!("{:?}", x);
}

この処理を実行してみる. 内容は順にxにVectorを代入して, xの中身をprintlnで表示している. someの中身は重要ではないので無視する. 実行してみると次のようなエラーが発生する.

borrow of moved value: `x`

意訳するとxが移動された後に借用された という意味になる. 実はこの移動されたというのは, 所有権が移動したという意味だ. xの所有権はmain関数のスコープにあった訳だが, some(x) を呼び出した時点で所有権がsomeに移動する. つまり, それ以降からxを参照しようとすると, 所有権がないのでエラーになる.

参照と借用

これを回避するためにはxの所有権を渡すのではなく, xを借用させれば良い.

fn some(x: &Vec<i8>) {
  // TODO:
}

fn main() {
  let x = vec![2];
  some(&x);
  println!("{:?}", x);
}

注意してほしいのが, some関数が引数で受け取る値はVector型ではなく&Vector型であることだ. 即ち各要素の型も&i8になる. こうすることで, xの所有権を渡すこと無く, xの値を参照することが可能だ.

Mutable参照

&mut T を用いることでMutable参照を実現する. この実装によってリソースの変更が可能で, 副作用を持たせることが出来る.

fn main() {
  let mut x = 2;
  {
    let y = &mut x;
    *y = 6;
  }
  println!("{}", x);
}

外側のスコープで宣言したxを &mut 参照を用いてyに引き渡している. アスタリスクを引き渡したyに追加することで, 参照内容であるxにアクセスすることが出来る. 即ちxの値を書き換えることが出来る.

*1:実行時コストを抑えたままに抽象化を実現する仕組み.

*2:primitiveな型にはCopyトレイトが実装されている