quick proof-of-concept of updating state and subscribing to events from react

main
Ashelyn Dawn 6 months ago
parent e826df051c
commit 092fe2a12f
No known key found for this signature in database
GPG Key ID: D1980B8C6F349BC1

@ -1,15 +1,11 @@
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
// Learn more about Tauri commands at https://tauri.app/v1/guides/features/command
#[tauri::command]
fn greet(name: &str) -> String {
format!("Hello, {}! You've been greeted from Rust!", name)
}
mod plugins;
fn main() {
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![greet])
.plugin(plugins::config::init())
.run(tauri::generate_context!())
.expect("error while running tauri application");
}

@ -0,0 +1,67 @@
use std::sync::Mutex;
use tauri::{
plugin::{Builder, TauriPlugin},
Manager, Runtime,
};
use serde::{Serialize, Deserialize};
struct AppConfig {
pub theme: ApplicationTheme
}
#[derive(Serialize, Deserialize, Clone)]
enum ApplicationTheme {
Light,
Dark,
}
impl AppConfig {
pub fn load() -> Self {
println!("Mock loading config");
AppConfig {
theme: ApplicationTheme::Light,
}
}
pub fn save(&self) {
println!("Mock saving config")
}
}
pub fn init<R: Runtime>() -> TauriPlugin<R> {
let config = AppConfig::load();
Builder::new("config")
.invoke_handler(tauri::generate_handler![set_application_theme, get_application_theme])
.setup(|app| {
app.manage(Mutex::new(config));
Ok(())
})
.build()
}
#[tauri::command]
fn set_application_theme<R: Runtime>(theme: &str, state_lock: tauri::State<Mutex<AppConfig>>, app_handle: tauri::AppHandle<R>) {
let mut config = state_lock.lock().unwrap();
match theme {
"light" => config.theme = ApplicationTheme::Light,
"dark" => config.theme = ApplicationTheme::Dark,
_ => {
panic!("Unknown theme type {}", theme)
}
}
config.save();
app_handle.emit_all("theme-change", config.theme.clone()).expect("Could not emit theme change event");
}
#[tauri::command]
fn get_application_theme(state_lock: tauri::State<Mutex<AppConfig>>) -> ApplicationTheme {
let config = state_lock.lock().unwrap();
config.theme.clone()
}

@ -0,0 +1 @@
pub mod config;

@ -1,53 +1,52 @@
import { useState } from "react";
import reactLogo from "./assets/react.svg";
import { useState, useEffect } from "react";
import { invoke } from "@tauri-apps/api/tauri";
import { Event } from "@tauri-apps/api/event";
import useTauriEvent from "./hooks/useTauriEvent";
import "./App.css";
function App() {
const [greetMsg, setGreetMsg] = useState("");
const [name, setName] = useState("");
const [currentTheme, setCurrentTheme] = useState('')
// Tell rust to change the theme (async)
const changeTheme = (theme: string) =>
invoke('plugin:config|set_application_theme', {theme})
async function greet() {
// Learn more about Tauri commands at https://tauri.app/v1/guides/features/command
setGreetMsg(await invoke("greet", { name }));
}
// On first render, query the current theme (async)
useEffect(() => {
invoke('plugin:config|get_application_theme')
.then((theme : unknown) => {
if (typeof theme === 'string')
setCurrentTheme(theme)
})
}, [])
// On theme update events, update the React UI state
useTauriEvent('theme-change', ({payload: theme} : Event<string>) => {
setCurrentTheme(theme)
}, [])
return (
<div className="container">
<h1>Welcome to Tauri!</h1>
<div className="row">
<a href="https://vitejs.dev" target="_blank">
<img src="/vite.svg" className="logo vite" alt="Vite logo" />
</a>
<a href="https://tauri.app" target="_blank">
<img src="/tauri.svg" className="logo tauri" alt="Tauri logo" />
</a>
<a href="https://reactjs.org" target="_blank">
<img src={reactLogo} className="logo react" alt="React logo" />
</a>
Quick and dirty example of manipulating state in the Rust layer,
and getting events back
</div>
<p>Click on the Tauri, Vite, and React logos to learn more.</p>
<div className="row">
<form
onSubmit={(e) => {
e.preventDefault();
greet();
}}
>
<input
id="greet-input"
onChange={(e) => setName(e.currentTarget.value)}
placeholder="Enter a name..."
/>
<button type="submit">Greet</button>
</form>
<p>Application theme: {currentTheme}</p>
</div>
<div className="row">
<p>
<button onClick={() => changeTheme('dark')}>dark</button>
<button onClick={() => changeTheme('light')}>light</button>
</p>
</div>
<p>{greetMsg}</p>
</div>
);
}
export default App;

@ -0,0 +1,22 @@
import {useEffect, useRef, useCallback} from 'react'
import { EventCallback, listen, UnlistenFn } from "@tauri-apps/api/event";
export default function useTauriEvent<T>(eventName : string, callback : EventCallback<T>, depArray : any[]) {
const unsubRef = useRef<null|UnlistenFn>(null)
const stableCallback = useCallback(callback, depArray)
useEffect(() => {
listen(eventName, stableCallback).then(unlisten => {
unsubRef.current = unlisten
})
return () => {
if (unsubRef.current) {
unsubRef.current()
}
}
}, [eventName, stableCallback])
}
Loading…
Cancel
Save