使用 React 和 Tauri (rust) 渲染数千/百万次
Posted
技术标签:
【中文标题】使用 React 和 Tauri (rust) 渲染数千/百万次【英文标题】:Render thousands/millions times with React and Tauri (rust) 【发布时间】:2021-08-17 16:48:19 【问题描述】:我正在学习 Rust。我正在创建一个桌面应用程序,它读取 csv 文件中的数千/百万行数据,然后使用 tauri event
将它们一一传输。
结果:Rust 读取文件没有问题(不到 5 秒)。在前端,我的 React 应用程序似乎无法跟上事件的步伐。在屏幕上,altitude
值会间歇性更新。
React 是如何处理这种情况的?或者我做错了什么?
反应方:
// App.js
import listen from '@tauri-apps/api/event';
import useEffect, useCallback, useState from 'react';
import invoke from '@tauri-apps/api/tauri'
const App = () =>
const [altitude, setAltitude] = useState("0");
useEffect(() =>
listen('rust-event', myCallback)
, [])
const myCallback = useCallback((e) =>
console.log(e);
setAltitude(e.payload);
,[])
const handleClick = async () =>
invoke('my_custom_command').catch(error => console.log(error));
;
return (
<div>
<button onClick=handleClick>Click Me To Start Fetching!</button>
<span>altitude</span>
</div>
);
export default App;
金牛座:
// main.rs
use arrow::csv;
use arrow::datatypes::DataType, Field, Schema;
use std::fs::File;
use std::sync::Arc;
use arrow::array::StringArray, ArrayRef;
#[tauri::command]
async fn my_custom_command(window: tauri::Window)
let schema = Schema::new(vec![
Field::new("altitude", DataType::Utf8, false)
]);
// Open file
let file = File::open("src/data.csv").unwrap();
// Get csv Reader using schema
let mut csv = csv::Reader::new(file, Arc::new(schema), true, None, 1, None, None);
// Loop through each row
while let Some(m) = csv.next()
let n = m.unwrap();
// Get reference of array of a column
let col: &ArrayRef = n.column(0);
// Cast the reference of array to array of string
let col = col.as_any().downcast_ref::<StringArray>().unwrap();
// Get value from the array using index
let v = col.value(0);
println!("", col.value(0));
// Send each value through an event
window
.emit("rust-event", v)
.expect("failed to emit");
fn main()
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![my_custom_command])
.run(tauri::generate_context!())
.expect("failed to run app");
【问题讨论】:
就像人们已经回答的那样,Rust 超级快,javascript 超级慢。即使只是生成几千个元素对 javascript 来说也是一个挑战,更不用说几十万或几百万了。我建议在您的前端切换方法。我最近做了一个简单的生活日历,打算每周显示一个盒子,但是前端对于这种方法来说太滞后了,所以我改为每年一个盒子,点击一个盒子会显示几周那个盒子。仅仅由于前端的限制,类似的解决方案可能更适合您。 【参考方案1】:嗯,我猜 Rust 太快了 :) React 无法处理这个速度。
我使用 settimeout rust lib 减慢了事件发出的速度,我现在对此很满意。
// Before emit an event, delay it 100 microsecond;
set_timeout(Duration::from_micros(100)).await;
window
.emit("rust-event", v)
.expect("failed to emit");
【讨论】:
【参考方案2】:我个人不建议您这样做,因为您可能会遇到堆栈溢出。
最好是批量发出它们,你可以填充一个本地缓冲区,当有 X 个元素时(或到达末尾),发出事件,并清除缓冲区。
示例
#[tauri::command]
async fn my_custom_command(window: tauri::Window)
// Your code
// [...]
// send 20 elements in the Vec (array)
let should_trigger_at = 20;
// local buffer
let local_buffer: Vec<String> = Vec::new();
// Loop through each row
while let Some(m) = csv.next()
let n = m.unwrap();
// Get reference of array of a column
let col: &ArrayRef = n.column(0);
// Cast the reference of array to array of string
let col = col.as_any().downcast_ref::<StringArray>().unwrap();
// Get value from the array using index
let v = col.value(0);
println!("", col.value(0));
// add the value in the buffer
local_buffer.push(col.value(0));
if local_buffer.len() == should_trigger_at
// Send each value through an event
window
.emit("rust-event", local_buffer)
.expect("failed to emit");
// reset local buffer
local_buffer = Vec::new();
// if buffer not empty, lets emit the values
if local_buffer.len() > 0
window
.emit("rust-event", local_buffer)
.expect("failed to emit");
// [...]
// Your code
请注意;这样做会将Array of String
发送到Webview 而不是String
。
【讨论】:
以上是关于使用 React 和 Tauri (rust) 渲染数千/百万次的主要内容,如果未能解决你的问题,请参考以下文章