経緯
Tauri で React 側の入力値を Rust に渡す際に以下のエラーが出力される事象に遭遇したのでメモ。
Uncaught (in promise) invalid args
hogeHoge
for commandfunc
: command func missing required key hogeHoge
もう少し正確に書くと以下のエラーとなります。
Uncaught (in promise) invalid args
hogeHoge
for commandgreet
: command greet missing required key hogeHoge
コード
事象が発生した際のコードは以下のような感じです。
React (App.tsx)
import { useState } from "react";
import { invoke } from "@tauri-apps/api/tauri";
import 'bootstrap/dist/css/bootstrap.min.css';
import { Container, Button } from 'react-bootstrap';
function App() {
const [greetMsg, setGreetMsg] = useState("");
const [hoge, setHoge] = useState("");
async function getHoge() {
// Learn more about Tauri commands at <https://tauri.app/v1/guides/features/command>
const hoge_hoge: String = hoge;
setGreetMsg(await invoke("greet", { hoge_hoge }));
}
return (
<Container>
<form
className="form-inline"
onSubmit={(e) => {
e.preventDefault();
getHoge();
}}
>
</form>
<p>{greetMsg}</p>
</Container>
);
}
export default App;
不要な部分を省略したり簡素化したりしていますが、サンプルを少し弄った程度です。ボタン押下時にその値を state に hoge という名前で代入し、それを非同期関数内で取り出して(実際は加工をしています)別の変数 hoge_hoge に代入、 hoge_hoge を Rust 側へ引数として渡す、というイメージです。
Rust (main.rs)
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
use serde_json;
//use std::io::Write;
// Learn more about Tauri commands at <https://tauri.app/v1/guides/features/command>
#[tauri::command]
fn greet(hoge_hoge: &str) -> String {
format!("Hello, {}! You've been greeted from Rust!", hoge_hoge)
}
fn main() {
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![greet])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
Rust 側は先の処理のところで躓いてしまったので、サンプルから変更していない状態です。
最初にここを弄り始めた際に tsx と Rust 側で変数名は同じにしないとエラーになると気付いたこと、その上で Rust 側は変数名をスネークケースで記述しないと忠告されるのでスネークケースで記述し、 tsx 側も意図的に同じ名前にしました。
すると、先のエラーが yarn tauri dev
で起動した開発中のブラウザのコンソールログで出力される、という状態です。
原因
妙なのは、エラーで出力されている変数名 hogeHoge
は tsx 側には存在していないということです。先述の通り、意図的に変数名は hoge_hoge
としているので……。
そこで軽く詰まってしまったのですが、むしろ「同じ名前にする」というところに固執し過ぎていたことが原因でした。正しくは以下のようなコードになります。
import { useState } from "react";
import { invoke } from "@tauri-apps/api/tauri";
import 'bootstrap/dist/css/bootstrap.min.css';
import { Container, Button } from 'react-bootstrap';
function App() {
const [greetMsg, setGreetMsg] = useState("");
const [hoge, setHoge] = useState("");
async function getHoge() {
// Learn more about Tauri commands at <https://tauri.app/v1/guides/features/command>
const hogeHoge: String = hoge;
setGreetMsg(await invoke("greet", { hogeHoge }));
}
return (
<Container>
<form
className="form-inline"
onSubmit={(e) => {
e.preventDefault();
getHoge();
}}
>
</form>
<p>{greetMsg}</p>
</Container>
);
}
export default App;
そう、 tsx 側はスネークケースではなくキャメルケースで記述 (hoge_hoge
ではなく hogeHoge
) するのが正解。これで Rust 側の hoge_hoge
と対応が取れます。
そういえば css のプロパティ名を JavaScript で記述する際もキャメルケースで普通に解釈されていましたし……ということに気付けば何と言うことはないのですが、久々にコードを書いたので気付くまでに時間がかかってしまいました (そしてエラー文で検索しても情報が得られなかったので)。
参考?
エラー文で検索して近い文章がヒットしたケース。実際はここから直接答えには到達しなかったのですが……。