quick proof-of-concept of updating state and subscribing to events from react
parent
e826df051c
commit
092fe2a12f
@ -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…
Reference in New Issue