0.6秒間 テキストボックス に入力がない時に API を叩くようにする実装
あとは?
on_change毎にAPIにリクエストが入るとサーバーの負荷が高くなるので、
入力が終わってから0.6秒何も入力がなければそこで初めてAPIリクエストを送りたい
じゃあ状態が必要だなあ
入力内容が変化するたびに最終入力の時刻をメモし、
3秒経ったらAPIリクエストを送る
これどうやってやるのん
...メインループがあるわけじゃないしなあ。
む、と思ったらこういうコードをexamplesから発見
Intervalとかを格納できるんだったらいけそう。
Timeoutを状態として格納する。
---> 3000ms後にリクエストを送りつける。
use gloo::timers::callback::{Interval, Timeout};
このアルゴリズムはどう?
入力があったら、Timeoutをリセットして、再度時間計測を開始する。
このTimeoutをリセットするのが無理だった
---> いや、いけるのでは?
UseStateHandle<Option<Timeout>> をまずは作る。値はNoneで。
oninput関数内にmoveする。
ちなみに、html!の{oninput}の表記はoninput={oninput}の略記だそうな moveしたあと、cloneする
(値をセットする用)
cloneしたあとのやつに対して、dereferenceして、forgetを行う
ここを参考にしたい
The setter function is guaranteed to be the same across the entire component lifecycle. You can safely omit the UseStateHandle from the dependents of use_effect_with if you only intend to set values from within the hook.
どういうこっちゃ
こんなことできるのか?
200ms毎に更新を走らせる方で行こう
code:rs
*sec_past_timer.borrow_mut() = Some(Interval::new(1000, move || {
sec += 1;
sec_past.set(sec);
}));
所有権パズル
code:rs
let time = use_state(|| 0);
let input_value = use_state(|| String::new());
let interval = Interval::new(100, || {
time.set(*time - 100);
if *time == 0 { send_api_request(&*input_value); }
});
// FIXME ここのムーブの問題どうする?
let oninput = Callback::from(move |input_event: InputEvent| {
let input_value_cloned = input_value.clone();
let value = get_value_from_input_event(input_event);
input_value.set(value.clone());
});
time, input_valueの値を複数の箇所からアクセスできたらOK
これはどうか!?
time_ref input_value_refなど、同じ箇所にアクセスするための変数を追加
code:rs
fn App() -> Html {
let time = use_state(|| 0);
let time_ref = time.clone();
let input_value = use_state(|| String::new());
let input_value_ref = input_value.clone();
let _interval = Interval::new(100, move || {
let input_value_cloned = input_value.clone();
if *time >= 0 { time.set(*time - 100); }
if *time == 0 {
wasm_bindgen_futures::spawn_local(async move {
send_api_request(&*&input_value_cloned).await.unwrap_throw();
});
}
});
// FIXME ここのムーブの問題どうする?
let oninput = Callback::from(move |input_event: InputEvent| {
let value = get_value_from_input_event(input_event);
time_ref.set(600);
input_value_ref.set(value.clone());
});
html!(
<input type={"text"} {oninput}/>
)
}
いけたわ
こいつを使う
Struct Componentを作った方がいい気がする。
いや、ややこしいからやめ
というか、どちらにせよ200msごとに更新みたいな処理をとってる
code:rs
let callback = ctx.link().callback(|_| Msg::Tick);
let interval = Interval::new(200, move || callback.emit(()));
// FIXED: updateされるたびに複数回intervalが作られてしまって困る
code:rs
let interval = Interval::new(100, move || {
let input_value_cloned = input_value.clone();
if *time > 0 { time.set(*time - 100); }
if *time == 0 {
wasm_bindgen_futures::spawn_local(async move {
send_api_request(&*input_value_cloned).await.unwrap_throw();
});
}
web_sys::console::log_1(&(*time).to_string().into());
});
どないする?
時間を測るアプリケーションのいい例
function componentsだとクロージャーを使って状態を管理する必要があって大変
Context....って何?
おれはYewについてなにもしらない.......
Intervalをuse_stateにしたら、コンポーネントに対して一回だけIntervalが作られるのでは?
use_effect_withを使うといいっぽい。
どっちにしよう?
structの方が管理がしやすそう。
function_componentオンリーだと、データを構造化しづらく、かなりプログラミングが難しくなるかも
状態をわかりやすく、慣習に従って表示したい。
oninputと、send_apiのイベントを二つ用意して、それぞれに対してイベントハンドラを実装したい
が、そのイベントハンドラを作るために、&Context<Self>が必要になる。
impl Appブロックに実装したら、Componentの内容を参照できなくなる。
= Component::Message, Component::Propertiesが参照できなくなる。
Hmmm
とりま今日はここまで
Commit
https://gyazo.com/c03bf4003465e5aef7355b2104dc1f2f
ctx, selfをコールバック関数に持ち込めないのむずいな
確かにライフタイム途中で途切れちゃうからなあ
moveする必要があるのか?
わからんなあ
ライフタイム指定子っぽい
いや、結局ctxが通ってないから意味ないか
でも、これよく考えたらUpdateでも起こりうる問題だよな?
関数分離したことが原因じゃないな
なるほど、ctx.link()でcloneするか
code:rs
Msg::StartTimeout => {
let handle = {
let link = ctx.link().clone();
Timeout::new(3000, move || link.send_message(Msg::Done))
};
}
https://gyazo.com/e8a89cfee56ac1b92f17696cace7694b
これならどうか
いけてそう
https://gyazo.com/b2166fed5401ecf29b2583128252837c
もっとmoveを活用した
コピーの回数を減らせた!
実装できた!