DioxusLabs/dioxus
在 GitHub 查看State management with dynamic rendering inside contenteditable divs
Open
#1,962 创建于 2024年2月22日
bughelp wanted
仓库指标
- Star
- (36,038 star)
- PR 合并指标
- (平均合并 16天 13小时) (30 天内合并 9 个 PR)
描述
State isn't synced properly when user deletes children nodes in contentetitable div
the user can delete elements by using the backspace inside contentetitable elements. Video below.
I also have a question regarding the event listeners of the child elements. Why they aren't triggered at all? Only the parent element event listeners are called.
Steps To Reproduce
Code:
#![allow(non_snake_case)]
// import the prelude to get access to the `rsx!` macro and the `Scope` and `Element` types
use dioxus::prelude::*;
use dioxus_desktop::{tao::event_loop::EventLoop, use_window, LogicalSize, WindowBuilder};
use uuid::Uuid;
fn main() {
// launch the dioxus app in a webview
dioxus_desktop::launch_cfg(
App,
dioxus_desktop::Config::new()
.with_custom_head(
r#"
<head>
<link rel="stylesheet" href="public/tailwind.css">
</head>
"#
.to_string(),
)
.with_window(
WindowBuilder::new()
.with_title("Desktop App")
.with_inner_size(LogicalSize {
width: 400.0,
height: 400.0,
})
.with_min_inner_size(LogicalSize {
width: 400.0,
height: 400.0,
})
.with_transparent(true),
),
)
}
enum Blocks {
ParagraphBlock(Uuid)
}
pub fn Paragraph(cx: Scope) -> Element {
let inner_text = use_state(cx, || "".to_string());
cx.render(rsx! {
div {
class: "border-solid border-2 border-indigo-300 p-4 rounded-lg some-block",
onkeydown: move |e| {println!("Inner State (onkeydown) {:?}", e.key().to_string());},
oninput : move |e| {println!("Inner State (oninput) {:?}", e.data.value.clone()); inner_text.set(e.data.value.clone())},
p{
class: "text-xs font-semibold text-gray-600 uppercase some-block-header",
"contenteditable": "false",
"Paragraph"
},
p {
class: "text-base text-gray-800 empty:before:content-[attr(data-placeholder)] empty:before:text-gray-300 whitespace-pre-wrap selectable-area",
"data-placeholder" : "Write text here ..",
inner_text.as_str()
}
}
}
)
}
fn App(cx: Scope) -> Element {
let window = use_window(&cx);
let some_blocks = use_ref(cx, Vec::<Blocks>::new);
if some_blocks.read().is_empty() {
some_blocks
.write()
.push(Blocks::ParagraphBlock(Uuid::new_v4()));
some_blocks
.write()
.push(Blocks::ParagraphBlock(Uuid::new_v4()));
some_blocks
.write()
.push(Blocks::ParagraphBlock(Uuid::new_v4()));
}
let binding = some_blocks.read();
let blocks_rendered = binding
.iter()
.map(|block| match block {
Blocks::ParagraphBlock(id) => rsx! {Paragraph{key: "{id}"}},
});
cx.render(rsx! {
div {
class: "h-screen w-screen flex bg-pink-100 p-4 rounded-lg flex-col space-y-4 overflow-auto",
"contenteditable" : "true",
onkeydown: move |_e| { println!("Number of blocks: {:?} ", some_blocks.read().len()) },
onmousedown: move |_| {window.drag()},
blocks_rendered
}
})
}
Expected behavior
State should be maintained and synced
Screenshots
Environment:
- Dioxus version: 0.4.3
- Rust version: rustc 1.76.0
- OS info: Windows 10
- App platform: desktop
Questionnaire
- I'm interested in fixing this myself but don't know where to start
- I would like to fix and I have a solution
- I don't have time to fix this right now, but maybe later