Todo
Todo | Done |
---|---|
React で text input を扱うときの実装を考える | o |
protoc が何故か go を吐き出さない問題 | o |
mustEmbedUnimplemented** について調べる |
Log
React で text input を扱うときの実装を考える
input の Component を作ろうとしたときにどう作ればいいんだ問題。
イメージ的には、外から使う分にはこんな感じにするのが良いかなって。CreateUserForm が form の中の入力内容を state で持つ感じ。 Submit したときの動作を上から渡す。API 叩くのか、上流で値を受け取るのかなど。
<CreateUserForm onSubmit={(values: FormComponentValues) => result} />
で、CreateUserForm の Component がこう。あくまでイメージ
<form onSubmit={() => props.onSubmit(formState)}>
<CustomInput />
<CustomInput />
<CustomInput />
<Submit />
</form>
ただこれだと入力したイベントとかは外から渡せないが・・・Form の値を管理する責務を Form で Wrap するならこうなのかしら。。
まず React の form に関する記載はここ。
https://ja.reactjs.org/docs/forms.html
onChange を渡しておいて、 event.target.value を取れば良いみたい。
change event はここ。
https://developer.mozilla.org/ja/docs/Web/API/HTMLElement/change_event
ここだけ気になる。
など一部の要素では、コントロールがフォーカスを失うまで change イベントが発生しません。以下のフィールドに何かを入力してから、他の部分をクリックするとイベントが発生します。
フォーカスを失うまで change イベントが発生しないなら、なんで onChange で value={props.value}
が機能するんだろうか。
React の form のページにはこう。
handleChange はキーストロークごとに実行されて React の state を更新するので、表示される値はユーザがタイプするたびに更新されます。
試しに実装したところ、キーストローク毎に実行された。React で扱う input は HTML としての input と少し挙動が違うっぽい。
textarea とかもちょっと違う旨が書いてある。
React では、 は代わりに value 属性を使用します。こうすることで、 を使用するフォームは単一行の入力フォームと非常に似た書き方ができるようになります
使いやすいようになってるみたい。
protoc が何故か go を吐き出さない問題
吐き出されないと当然開発に入れないので困っている
以前書いた ProtocolBuffer の import の記事 で動作を確認しようと思ったら、よく見たらなんかおかしい。
protoc コマンドのオプション --go_out=plugins=grpc:./go
が記載してる protoc
のバージョン(3.6.0
)と一致してない・・・・
たぶん別のバージョンの protoc で動かしたんだと思うので、再度上から実行して書き直した。
すると、
protoc -I . -I ~/src --go-grpc_out ./go models/user.proto
ここでやっぱり user_grpc.pb.go が生成されない。もしかして service がないと生成されなくなってる?
試しに service を追加したら生成された。
というかよく生成されるコード読んでみたら、message に対応する type が生成されてないぞなんだこれ。
で、解決。そもそも、protoc のバージョンを変えたら以下のエラーが出るようになってた。
--go_out: protoc-gen-go: plugins are not supported; use 'protoc --go-grpc_out=...' to generate gRPC
ので、--go_out=plugins=grpc:./go
をとりあえず以下のようなオプションにした。
--go-grpc_out <dir>
この書き方をすると protoc-gen-go-grpc
が動いているという認識がそもそも足りなかったのだけど、 protoc-gen-go-grpc
は message
に対応する struct
を生成しない。
その struct の定義自体は grpc じゃないもんね。確かに。
今までもたぶん message
に対応する struct
を生成してくれていたのは protoc-gen-go
。
なので、正しくアウトプットするためには、
--go_out <dir> --go-grpc_out <dir>
というオプションが必要だった。勉強になった。
mustEmbedUnimplemented
昨日始めた時間がもう今日だったので、続きに書く。
無事 protoc がバージョンできてよかった、と思ったのもつかの間、 mustEmbedUnimplementedXXXXXServer
というメソッドの実装がないよ、というエラーが出た。
調べたところ、同じような issue がこれ。
https://github.com/grpc/grpc-go/issues/3794
そのなかに出てくる長い長い議論がこれ。
https://github.com/grpc/grpc-go/issues/3669
ちょっと読めないので、ソースコードなどをかいつまんで見てみると、UnimplementedServer を embeded すれば良いみたい。
以前書いた ProtocolBuffer の import の記事 で生成した Server を例にすると、
まず、こういう interface が生成される。
// UserServiceServer is the server API for UserService service.
// All implementations must embed UnimplementedUserServiceServer
// for forward compatibility
type UserServiceServer interface {
GetUser(context.Context, *GetUserMessage) (*GetUserResponse, error)
mustEmbedUnimplementedUserServiceServer()
}
問題になっているのは mustEmbedUnimplementedUserServiceServer
で、どうやら UnimplementedUserServiceServer
を Embed させるための func っぽい?
UnimplementedUserServiceServer
を見てみる。
// UnimplementedUserServiceServer must be embedded to have forward compatible implementations.
type UnimplementedUserServiceServer struct {
}
func (UnimplementedUserServiceServer) GetUser(context.Context, *GetUserMessage) (*GetUserResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetUser not implemented")
}
func (UnimplementedUserServiceServer) mustEmbedUnimplementedUserServiceServer() {}
何もしない func が入っている。 コメントにもある通り、上位互換性を保つために実装に Embed しないといけないらしい。
つまり、protobuf
側に新しい rpc
が生えたときに、UnimplementedUserServiceServer
を Embed しておくと、実装をしなくても、自動で codes.Unimplemented
を返却するメソッドを生やすよ、ということではないかと思う。
ちなみに Embed する実装はこう。
type server struct {
pb.UnimplementedUserServiceServer
}
そもそもこの func いらないよ!ってときは、go-grpc の option でなくせるらしい。やってない。
--go-grpc_opt=require_unimplemented_servers=false
上のキーワードで調べたらめっちゃわかりやすい note あった。ありがとうございます。
https://note.com/dd_techblog/n/nb8b925d21118
その他作業中に発生したこと
protoc の plugin についての記事
どっかで読んで作ってみたい
https://qiita.com/yugui/items/87d00d77dee159e74886
新しいバージョンの protoc で生成した protobuf を元々あったアプリに読み込ませたらエラー
mustEmbedUnimplemented***
という func がないエラーがドバーッと。
なんぞこれ?という同じ疑問の issue があがってたので、明日以降調べる。
https://github.com/grpc/grpc-go/issues/3794
Next