feat: add update functionality to useref
This commit is contained in:
1 parent
5502429626
commit
a2b0c50a34
16 files changed
+77
-47
No files matched your search
@@ -47,6 +47,7 @@ fxhash = "0.2.1"
|
|||||||
anyhow = "1.0.42"
|
anyhow = "1.0.42"
|
||||||
reqwest = "0.11.4"
|
reqwest = "0.11.4"
|
||||||
serde_json = "1.0.68"
|
serde_json = "1.0.68"
|
||||||
|
simple_logger = "1.13.0"
|
||||||
|
|
||||||
[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies]
|
[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies]
|
||||||
argh = "0.1.5"
|
argh = "0.1.5"
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ This example is a simple iOS-style calculator. This particular example can run a
|
|||||||
This calculator version uses React-style state management. All state is held as individual use_states.
|
This calculator version uses React-style state management. All state is held as individual use_states.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use dioxus::events::on::*;
|
use dioxus::events::*;
|
||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
@@ -56,7 +56,7 @@ const APP: FC<()> = |cx, _| {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let keydownhandler = move |evt: KeyboardEvent| match evt.key_code() {
|
let keydownhandler = move |evt: KeyboardEvent| match evt.key_code {
|
||||||
KeyCode::Add => operator.set(Some("+")),
|
KeyCode::Add => operator.set(Some("+")),
|
||||||
KeyCode::Subtract => operator.set(Some("-")),
|
KeyCode::Subtract => operator.set(Some("-")),
|
||||||
KeyCode::Divide => operator.set(Some("/")),
|
KeyCode::Divide => operator.set(Some("/")),
|
||||||
|
|||||||
+3
-3
@@ -59,13 +59,13 @@ static App: FC<()> = |cx, _| {
|
|||||||
h2 {"Add new client" margin_bottom: "10px" }
|
h2 {"Add new client" margin_bottom: "10px" }
|
||||||
form { class: "pure-form"
|
form { class: "pure-form"
|
||||||
input { class: "new-client firstname" placeholder: "First name" value: "{firstname}"
|
input { class: "new-client firstname" placeholder: "First name" value: "{firstname}"
|
||||||
oninput: move |e| firstname.set(e.value())
|
oninput: move |e| firstname.set(e.value.clone())
|
||||||
}
|
}
|
||||||
input { class: "new-client lastname" placeholder: "Last name" value: "{lastname}"
|
input { class: "new-client lastname" placeholder: "Last name" value: "{lastname}"
|
||||||
oninput: move |e| lastname.set(e.value())
|
oninput: move |e| lastname.set(e.value.clone())
|
||||||
}
|
}
|
||||||
textarea { class: "new-client description" placeholder: "Description" value: "{description}"
|
textarea { class: "new-client description" placeholder: "Description" value: "{description}"
|
||||||
oninput: move |e| description.set(e.value())
|
oninput: move |e| description.set(e.value.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
button { class: "pure-button pure-button-primary", onclick: {add_new}, "Add New" }
|
button { class: "pure-button pure-button-primary", onclick: {add_new}, "Add New" }
|
||||||
|
|||||||
@@ -8,11 +8,11 @@
|
|||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
env_logger::init();
|
simple_logger::init_with_level(log::Level::Debug);
|
||||||
dioxus::desktop::launch(App, |c| {
|
dioxus::desktop::launch(App, |c| {
|
||||||
c.with_window(|w| {
|
c.with_window(|w| {
|
||||||
w.with_resizable(false).with_inner_size(
|
w.with_resizable(true).with_inner_size(
|
||||||
dioxus::desktop::wry::application::dpi::LogicalSize::new(800.0, 400.0),
|
dioxus::desktop::wry::application::dpi::LogicalSize::new(400.0, 800.0),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -70,6 +70,7 @@ impl Files {
|
|||||||
|
|
||||||
fn reload_path_list(&mut self) {
|
fn reload_path_list(&mut self) {
|
||||||
let cur_path = self.path_stack.last().unwrap();
|
let cur_path = self.path_stack.last().unwrap();
|
||||||
|
log::info!("Reloading path list for {:?}", cur_path);
|
||||||
let paths = match std::fs::read_dir(cur_path) {
|
let paths = match std::fs::read_dir(cur_path) {
|
||||||
Ok(e) => e,
|
Ok(e) => e,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
@@ -79,15 +80,18 @@ impl Files {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
let collected = paths.collect::<Vec<_>>();
|
||||||
|
log::info!("Path list reloaded {:#?}", collected);
|
||||||
|
|
||||||
// clear the current state
|
// clear the current state
|
||||||
self.clear_err();
|
self.clear_err();
|
||||||
self.path_names.clear();
|
self.path_names.clear();
|
||||||
|
|
||||||
for path in paths {
|
for path in collected {
|
||||||
self.path_names
|
self.path_names
|
||||||
.push(path.unwrap().path().display().to_string());
|
.push(path.unwrap().path().display().to_string());
|
||||||
}
|
}
|
||||||
|
log::info!("path namees are {:#?}", self.path_names);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn go_up(&mut self) {
|
fn go_up(&mut self) {
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ fn main() {
|
|||||||
AppendChildren { many: 1 },
|
AppendChildren { many: 1 },
|
||||||
];
|
];
|
||||||
|
|
||||||
dioxus_desktop::WebviewRenderer::run_with_edits(APP, (), |c| c, Some(edits)).expect("failed");
|
dioxus_desktop::run(APP, (), |c| c.with_edits(edits)).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
const APP: FC<()> = |cx, _props| {
|
const APP: FC<()> = |cx, _props| {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
//! RefMuts at the same time.
|
//! RefMuts at the same time.
|
||||||
|
|
||||||
use dioxus::desktop::wry::application::dpi::LogicalSize;
|
use dioxus::desktop::wry::application::dpi::LogicalSize;
|
||||||
use dioxus::events::on::*;
|
use dioxus::events::{on::*, KeyCode};
|
||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
const STYLE: &str = include_str!("./assets/calculator.css");
|
const STYLE: &str = include_str!("./assets/calculator.css");
|
||||||
@@ -169,7 +169,7 @@ impl Calculator {
|
|||||||
self.waiting_for_operand = true;
|
self.waiting_for_operand = true;
|
||||||
}
|
}
|
||||||
fn handle_keydown(&mut self, evt: KeyboardEvent) {
|
fn handle_keydown(&mut self, evt: KeyboardEvent) {
|
||||||
match evt.key_code() {
|
match evt.key_code {
|
||||||
KeyCode::Backspace => self.backspace(),
|
KeyCode::Backspace => self.backspace(),
|
||||||
KeyCode::Num0 => self.input_digit(0),
|
KeyCode::Num0 => self.input_digit(0),
|
||||||
KeyCode::Num1 => self.input_digit(1),
|
KeyCode::Num1 => self.input_digit(1),
|
||||||
|
|||||||
+2
-2
@@ -57,7 +57,7 @@ const App: FC<()> = |cx, props| {
|
|||||||
class: "new-todo"
|
class: "new-todo"
|
||||||
placeholder: "What needs to be done?"
|
placeholder: "What needs to be done?"
|
||||||
value: "{draft}"
|
value: "{draft}"
|
||||||
oninput: move |evt| draft.set(evt.value())
|
oninput: move |evt| draft.set(evt.value.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{todolist}
|
{todolist}
|
||||||
@@ -100,7 +100,7 @@ pub fn TodoEntry<'a>(cx: Context<'a>, props: &TodoEntryProps) -> DomTree<'a> {
|
|||||||
{is_editing.then(|| rsx!{
|
{is_editing.then(|| rsx!{
|
||||||
input {
|
input {
|
||||||
value: "{contents}"
|
value: "{contents}"
|
||||||
oninput: move |evt| contents.set(evt.value())
|
oninput: move |evt| contents.set(evt.value.clone())
|
||||||
}
|
}
|
||||||
})}
|
})}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ use std::{
|
|||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub use on::*;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct UserEvent {
|
pub struct UserEvent {
|
||||||
/// The originator of the event trigger
|
/// The originator of the event trigger
|
||||||
|
|||||||
@@ -30,8 +30,9 @@ impl<'a> DesktopConfig<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_edits(&mut self, edits: Vec<DomEdit<'a>>) {
|
pub fn with_edits(&mut self, edits: Vec<DomEdit<'a>>) -> &mut Self {
|
||||||
self.manual_edits = Some(edits);
|
self.manual_edits = Some(edits);
|
||||||
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_prerendered(&mut self, content: String) -> &mut Self {
|
pub fn with_prerendered(&mut self, content: String) -> &mut Self {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
<div id="_dioxusroot">
|
<div id="_dioxusroot">
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
<script type="text/javascript" src="/index.js">
|
<script type="text/javascript" src="index.js">
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
@@ -153,6 +153,10 @@ class Interpreter {
|
|||||||
this.root.addEventListener(event_name, (event) => {
|
this.root.addEventListener(event_name, (event) => {
|
||||||
const target = event.target;
|
const target = event.target;
|
||||||
const val = target.getAttribute(`dioxus-event-${event_name}`);
|
const val = target.getAttribute(`dioxus-event-${event_name}`);
|
||||||
|
if (val == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const fields = val.split(".");
|
const fields = val.split(".");
|
||||||
const scope_id = parseInt(fields[0]);
|
const scope_id = parseInt(fields[0]);
|
||||||
const real_id = parseInt(fields[1]);
|
const real_id = parseInt(fields[1]);
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ pub fn run<T: Properties + 'static + Send + Sync>(
|
|||||||
let locked_receiver = Rc::new(RefCell::new(event_rx));
|
let locked_receiver = Rc::new(RefCell::new(event_rx));
|
||||||
|
|
||||||
let webview = WebViewBuilder::new(window)?
|
let webview = WebViewBuilder::new(window)?
|
||||||
.with_url("wry://src/index.html")?
|
.with_url("wry://index.html")?
|
||||||
.with_rpc_handler(move |_window: &Window, mut req: RpcRequest| {
|
.with_rpc_handler(move |_window: &Window, mut req: RpcRequest| {
|
||||||
//
|
//
|
||||||
match req.method.as_str() {
|
match req.method.as_str() {
|
||||||
@@ -130,20 +130,11 @@ pub fn run<T: Properties + 'static + Send + Sync>(
|
|||||||
use wry::http::ResponseBuilder;
|
use wry::http::ResponseBuilder;
|
||||||
// Remove url scheme
|
// Remove url scheme
|
||||||
let path = request.uri().replace("wry://", "");
|
let path = request.uri().replace("wry://", "");
|
||||||
// Read the file content from file path
|
|
||||||
let content = read(canonicalize(&path)?)?;
|
|
||||||
|
|
||||||
// Return asset contents and mime types based on file extentions
|
let (data, meta) = match path.as_str() {
|
||||||
// If you don't want to do this manually, there are some crates for you.
|
"index.html" => (include_bytes!("./index.html").to_vec(), "text/html"),
|
||||||
// Such as `infer` and `mime_guess`.
|
"index.html/index.js" => (include_bytes!("./index.js").to_vec(), "text/javascript"),
|
||||||
let (data, meta) = if path.ends_with(".html") {
|
_ => unimplemented!("path {}", path),
|
||||||
(content, "text/html")
|
|
||||||
} else if path.ends_with(".js") {
|
|
||||||
(content, "text/javascript")
|
|
||||||
} else if path.ends_with(".png") {
|
|
||||||
(content, "image/png")
|
|
||||||
} else {
|
|
||||||
unimplemented!();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ResponseBuilder::new().mimetype(meta).body(data)
|
ResponseBuilder::new().mimetype(meta).body(data)
|
||||||
|
|||||||
@@ -1,14 +1,37 @@
|
|||||||
use std::cell::{Ref, RefCell, RefMut};
|
use std::{
|
||||||
|
cell::{Cell, Ref, RefCell, RefMut},
|
||||||
|
rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
use dioxus_core::Context;
|
use dioxus_core::Context;
|
||||||
|
|
||||||
|
pub fn use_ref<T: 'static>(cx: Context, f: impl FnOnce() -> T) -> UseRef<T> {
|
||||||
|
cx.use_hook(
|
||||||
|
|_| UseRefInner {
|
||||||
|
update_scheuled: Cell::new(false),
|
||||||
|
update_callback: cx.schedule_update(),
|
||||||
|
value: RefCell::new(f()),
|
||||||
|
},
|
||||||
|
|inner| {
|
||||||
|
inner.update_scheuled.set(false);
|
||||||
|
UseRef { inner }
|
||||||
|
},
|
||||||
|
|_| {},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub struct UseRef<'a, T> {
|
pub struct UseRef<'a, T> {
|
||||||
inner: &'a RefCell<T>,
|
inner: &'a UseRefInner<T>,
|
||||||
|
}
|
||||||
|
struct UseRefInner<T> {
|
||||||
|
update_scheuled: Cell<bool>,
|
||||||
|
update_callback: Rc<dyn Fn()>,
|
||||||
|
value: RefCell<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T> UseRef<'a, T> {
|
impl<'a, T> UseRef<'a, T> {
|
||||||
pub fn read(&self) -> Ref<'_, T> {
|
pub fn read(&self) -> Ref<'_, T> {
|
||||||
self.inner.borrow()
|
self.inner.value.borrow()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_write(&self) -> (Ref<'_, T>, &Self) {
|
pub fn read_write(&self) -> (Ref<'_, T>, &Self) {
|
||||||
@@ -17,12 +40,20 @@ impl<'a, T> UseRef<'a, T> {
|
|||||||
|
|
||||||
/// Calling "write" will force the component to re-render
|
/// Calling "write" will force the component to re-render
|
||||||
pub fn write(&self) -> RefMut<'_, T> {
|
pub fn write(&self) -> RefMut<'_, T> {
|
||||||
self.inner.borrow_mut()
|
self.needs_update();
|
||||||
|
self.inner.value.borrow_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Allows the ability to write the value without forcing a re-render
|
/// Allows the ability to write the value without forcing a re-render
|
||||||
pub fn write_silent(&self) -> RefMut<'_, T> {
|
pub fn write_silent(&self) -> RefMut<'_, T> {
|
||||||
self.inner.borrow_mut()
|
self.inner.value.borrow_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn needs_update(&self) {
|
||||||
|
if !self.inner.update_scheuled.get() {
|
||||||
|
self.inner.update_scheuled.set(true);
|
||||||
|
(self.inner.update_callback)();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,7 +63,3 @@ impl<T> Clone for UseRef<'_, T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<T> Copy for UseRef<'_, T> {}
|
impl<T> Copy for UseRef<'_, T> {}
|
||||||
|
|
||||||
pub fn use_ref<T: 'static>(cx: Context, f: impl FnOnce() -> T) -> UseRef<T> {
|
|
||||||
cx.use_hook(|_| RefCell::new(f()), |f| UseRef { inner: f }, |_| {})
|
|
||||||
}
|
|
||||||
@@ -29,7 +29,7 @@ static HTML_CONTENT: &'static str = include_str!("../../desktop/src/index.html")
|
|||||||
pub fn launch(root: FC<()>, builder: fn(WindowBuilder) -> WindowBuilder) -> anyhow::Result<()> {
|
pub fn launch(root: FC<()>, builder: fn(WindowBuilder) -> WindowBuilder) -> anyhow::Result<()> {
|
||||||
launch_with_props(root, (), builder)
|
launch_with_props(root, (), builder)
|
||||||
}
|
}
|
||||||
pub fn launch_with_props<P: Properties + 'static>(
|
pub fn launch_with_props<P: 'static + Send>(
|
||||||
root: FC<P>,
|
root: FC<P>,
|
||||||
props: P,
|
props: P,
|
||||||
builder: fn(WindowBuilder) -> WindowBuilder,
|
builder: fn(WindowBuilder) -> WindowBuilder,
|
||||||
@@ -50,7 +50,7 @@ enum RpcEvent<'a> {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Properties + 'static> WebviewRenderer<T> {
|
impl<T: 'static + Send> WebviewRenderer<T> {
|
||||||
pub fn run(
|
pub fn run(
|
||||||
root: FC<T>,
|
root: FC<T>,
|
||||||
props: T,
|
props: T,
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ static APP: FC<()> = |cx, _| {
|
|||||||
input {
|
input {
|
||||||
r#type: "text",
|
r#type: "text",
|
||||||
value: "{text_content}"
|
value: "{text_content}"
|
||||||
oninput: move |e| text_content.set(e.value())
|
oninput: move |e| text_content.set(e.value.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
{(0..10).map(|_| {
|
{(0..10).map(|_| {
|
||||||
@@ -45,8 +45,8 @@ static APP: FC<()> = |cx, _| {
|
|||||||
id: "cars"
|
id: "cars"
|
||||||
value: "{content}"
|
value: "{content}"
|
||||||
oninput: move |ev| {
|
oninput: move |ev| {
|
||||||
content.set(ev.value());
|
content.set(ev.value.clone());
|
||||||
match ev.value().as_str() {
|
match ev.value.as_str() {
|
||||||
"h1" => count.set(0),
|
"h1" => count.set(0),
|
||||||
"h2" => count.set(5),
|
"h2" => count.set(5),
|
||||||
"h3" => count.set(10),
|
"h3" => count.set(10),
|
||||||
|
|||||||
@@ -68,13 +68,13 @@ static App: FC<()> = |cx, _| {
|
|||||||
h2 {"Add new client" margin_bottom: "10px" }
|
h2 {"Add new client" margin_bottom: "10px" }
|
||||||
form { class: "pure-form"
|
form { class: "pure-form"
|
||||||
input { class: "new-client firstname" placeholder: "First name" value: "{firstname}"
|
input { class: "new-client firstname" placeholder: "First name" value: "{firstname}"
|
||||||
oninput: move |evt| firstname.set(evt.value())
|
oninput: move |evt| firstname.set(evt.value.clone())
|
||||||
}
|
}
|
||||||
input { class: "new-client lastname" placeholder: "Last name" value: "{lastname}"
|
input { class: "new-client lastname" placeholder: "Last name" value: "{lastname}"
|
||||||
oninput: move |evt| lastname.set(evt.value())
|
oninput: move |evt| lastname.set(evt.value.clone())
|
||||||
}
|
}
|
||||||
textarea { class: "new-client description" placeholder: "Description" value: "{description}"
|
textarea { class: "new-client description" placeholder: "Description" value: "{description}"
|
||||||
oninput: move |evt| description.set(evt.value())
|
oninput: move |evt| description.set(evt.value.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
button { class: "pure-button pure-button-primary", onclick: {add_new}, "Add New" }
|
button { class: "pure-button pure-button-primary", onclick: {add_new}, "Add New" }
|
||||||
|
|||||||
Reference in new issue
Block a user