mirror of
https://github.com/yewstack/yew.git
synced 2025-12-08 21:26:25 +00:00
Fix component rendering process (#913)
* wip * Fix component rendering process
This commit is contained in:
parent
c422a5ed1b
commit
3dca0c7758
@ -739,7 +739,7 @@ impl<AGN: Agent> AgentScope<AGN> {
|
|||||||
update,
|
update,
|
||||||
};
|
};
|
||||||
let runnable: Box<dyn Runnable> = Box::new(envelope);
|
let runnable: Box<dyn Runnable> = Box::new(envelope);
|
||||||
scheduler().put_and_try_run(runnable);
|
scheduler().push(runnable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -304,12 +304,19 @@ where
|
|||||||
/// }
|
/// }
|
||||||
/// }
|
/// }
|
||||||
#[derive(PartialEq, Debug, Default, Clone)]
|
#[derive(PartialEq, Debug, Default, Clone)]
|
||||||
pub struct NodeRef(Rc<RefCell<Option<Node>>>);
|
pub struct NodeRef(Rc<RefCell<NodeRefInner>>);
|
||||||
|
|
||||||
|
#[derive(PartialEq, Debug, Default, Clone)]
|
||||||
|
struct NodeRefInner {
|
||||||
|
node: Option<Node>,
|
||||||
|
link: Option<NodeRef>,
|
||||||
|
}
|
||||||
|
|
||||||
impl NodeRef {
|
impl NodeRef {
|
||||||
/// Get the wrapped Node reference if it exists
|
/// Get the wrapped Node reference if it exists
|
||||||
pub fn get(&self) -> Option<Node> {
|
pub fn get(&self) -> Option<Node> {
|
||||||
self.0.borrow().clone()
|
let inner = self.0.borrow();
|
||||||
|
inner.node.clone().or_else(|| inner.link.as_ref()?.get())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Try converting the node reference into another form
|
/// Try converting the node reference into another form
|
||||||
@ -319,7 +326,12 @@ impl NodeRef {
|
|||||||
|
|
||||||
/// Place a Node in a reference for later use
|
/// Place a Node in a reference for later use
|
||||||
pub(crate) fn set(&self, node: Option<Node>) {
|
pub(crate) fn set(&self, node: Option<Node>) {
|
||||||
*self.0.borrow_mut() = node;
|
self.0.borrow_mut().node = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Link a downstream `NodeRef`
|
||||||
|
pub(crate) fn link(&self, node_ref: Self) {
|
||||||
|
self.0.borrow_mut().link = Some(node_ref);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -77,15 +77,15 @@ impl<COMP: Component> Scope<COMP> {
|
|||||||
/// Schedules a task to call the mounted method on a component and optionally re-render
|
/// Schedules a task to call the mounted method on a component and optionally re-render
|
||||||
pub(crate) fn mounted(&mut self) {
|
pub(crate) fn mounted(&mut self) {
|
||||||
let shared_state = self.shared_state.clone();
|
let shared_state = self.shared_state.clone();
|
||||||
let mounted = Box::new(MountedComponent { shared_state });
|
let mounted = MountedComponent { shared_state };
|
||||||
scheduler().put_and_try_run(mounted);
|
scheduler().push_mount(Box::new(mounted));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Schedules a task to create and render a component and then mount it to the DOM
|
/// Schedules a task to create and render a component and then mount it to the DOM
|
||||||
pub(crate) fn create(&mut self) {
|
pub(crate) fn create(&mut self) {
|
||||||
let shared_state = self.shared_state.clone();
|
let shared_state = self.shared_state.clone();
|
||||||
let create = CreateComponent { shared_state };
|
let create = CreateComponent { shared_state };
|
||||||
scheduler().put_and_try_run(Box::new(create));
|
scheduler().push_create(Box::new(create));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Schedules a task to send a message or new props to a component
|
/// Schedules a task to send a message or new props to a component
|
||||||
@ -94,14 +94,14 @@ impl<COMP: Component> Scope<COMP> {
|
|||||||
shared_state: self.shared_state.clone(),
|
shared_state: self.shared_state.clone(),
|
||||||
update,
|
update,
|
||||||
};
|
};
|
||||||
scheduler().put_and_try_run(Box::new(update));
|
scheduler().push(Box::new(update));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Schedules a task to destroy a component
|
/// Schedules a task to destroy a component
|
||||||
pub(crate) fn destroy(&mut self) {
|
pub(crate) fn destroy(&mut self) {
|
||||||
let shared_state = self.shared_state.clone();
|
let shared_state = self.shared_state.clone();
|
||||||
let destroy = DestroyComponent { shared_state };
|
let destroy = DestroyComponent { shared_state };
|
||||||
scheduler().put_and_try_run(Box::new(destroy));
|
scheduler().push(Box::new(destroy));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send a message to the component
|
/// Send a message to the component
|
||||||
@ -173,10 +173,17 @@ impl<COMP: Component> CreatedState<COMP> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn update(mut self) -> Self {
|
fn update(mut self) -> Self {
|
||||||
let mut vnode = self.component.render();
|
let mut root = self.component.render();
|
||||||
let node = vnode.apply(&self.element, None, self.last_frame);
|
if let Some(node) = root.apply(&self.element, None, self.last_frame) {
|
||||||
self.node_ref.set(node);
|
self.node_ref.set(Some(node));
|
||||||
self.last_frame = Some(vnode);
|
} else if let VNode::VComp(child) = &root {
|
||||||
|
// If the root VNode is a VComp, we won't have access to the rendered DOM node
|
||||||
|
// because components render asynchronously. In order to bubble up the DOM node
|
||||||
|
// from the VComp, we need to link the currently rendering component with its
|
||||||
|
// root child component.
|
||||||
|
self.node_ref.link(child.node_ref.clone());
|
||||||
|
}
|
||||||
|
self.last_frame = Some(root);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,6 @@
|
|||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
|
||||||
|
|
||||||
pub(crate) type Shared<T> = Rc<RefCell<T>>;
|
pub(crate) type Shared<T> = Rc<RefCell<T>>;
|
||||||
|
|
||||||
@ -23,44 +22,57 @@ pub(crate) trait Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// This is a global scheduler suitable to schedule and run any tasks.
|
/// This is a global scheduler suitable to schedule and run any tasks.
|
||||||
|
#[derive(Clone)]
|
||||||
pub(crate) struct Scheduler {
|
pub(crate) struct Scheduler {
|
||||||
lock: Rc<AtomicBool>,
|
lock: Rc<RefCell<()>>,
|
||||||
sequence: Shared<VecDeque<Box<dyn Runnable>>>,
|
main: Shared<VecDeque<Box<dyn Runnable>>>,
|
||||||
}
|
create_component: Shared<VecDeque<Box<dyn Runnable>>>,
|
||||||
|
mount_component: Shared<Vec<Box<dyn Runnable>>>,
|
||||||
impl Clone for Scheduler {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
Scheduler {
|
|
||||||
lock: self.lock.clone(),
|
|
||||||
sequence: self.sequence.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Scheduler {
|
impl Scheduler {
|
||||||
/// Creates a new scheduler with a context.
|
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
let sequence = VecDeque::new();
|
|
||||||
Scheduler {
|
Scheduler {
|
||||||
lock: Rc::new(AtomicBool::new(false)),
|
lock: Rc::new(RefCell::new(())),
|
||||||
sequence: Rc::new(RefCell::new(sequence)),
|
main: Rc::new(RefCell::new(VecDeque::new())),
|
||||||
|
create_component: Rc::new(RefCell::new(VecDeque::new())),
|
||||||
|
mount_component: Rc::new(RefCell::new(Vec::new())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn put_and_try_run(&self, runnable: Box<dyn Runnable>) {
|
pub(crate) fn push(&self, runnable: Box<dyn Runnable>) {
|
||||||
self.sequence.borrow_mut().push_back(runnable);
|
self.main.borrow_mut().push_back(runnable);
|
||||||
if self.lock.compare_and_swap(false, true, Ordering::Relaxed) {
|
self.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn push_create(&self, runnable: Box<dyn Runnable>) {
|
||||||
|
self.create_component.borrow_mut().push_back(runnable);
|
||||||
|
self.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn push_mount(&self, runnable: Box<dyn Runnable>) {
|
||||||
|
self.mount_component.borrow_mut().push(runnable);
|
||||||
|
self.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn start(&self) {
|
||||||
|
let lock = self.lock.try_borrow_mut();
|
||||||
|
if lock.is_err() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let do_next = self.sequence.borrow_mut().pop_front();
|
let do_next = self
|
||||||
|
.create_component
|
||||||
|
.borrow_mut()
|
||||||
|
.pop_front()
|
||||||
|
.or_else(|| self.mount_component.borrow_mut().pop())
|
||||||
|
.or_else(|| self.main.borrow_mut().pop_front());
|
||||||
if let Some(runnable) = do_next {
|
if let Some(runnable) = do_next {
|
||||||
runnable.run();
|
runnable.run();
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.lock.store(false, Ordering::Relaxed);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,18 +18,11 @@ enum GeneratorType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A virtual component.
|
/// A virtual component.
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct VComp {
|
pub struct VComp {
|
||||||
type_id: TypeId,
|
type_id: TypeId,
|
||||||
state: Rc<RefCell<MountState>>,
|
state: Rc<RefCell<MountState>>,
|
||||||
}
|
pub(crate) node_ref: NodeRef,
|
||||||
|
|
||||||
impl Clone for VComp {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
VComp {
|
|
||||||
type_id: self.type_id,
|
|
||||||
state: self.state.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A virtual child component.
|
/// A virtual child component.
|
||||||
@ -92,6 +85,7 @@ impl VComp {
|
|||||||
where
|
where
|
||||||
COMP: Component,
|
COMP: Component,
|
||||||
{
|
{
|
||||||
|
let node_ref_clone = node_ref.clone();
|
||||||
let generator = move |generator_type: GeneratorType| -> Mounted {
|
let generator = move |generator_type: GeneratorType| -> Mounted {
|
||||||
match generator_type {
|
match generator_type {
|
||||||
GeneratorType::Mount(element, dummy_node) => {
|
GeneratorType::Mount(element, dummy_node) => {
|
||||||
@ -100,12 +94,12 @@ impl VComp {
|
|||||||
let mut scope = scope.mount_in_place(
|
let mut scope = scope.mount_in_place(
|
||||||
element,
|
element,
|
||||||
Some(VNode::VRef(dummy_node.into())),
|
Some(VNode::VRef(dummy_node.into())),
|
||||||
node_ref.clone(),
|
node_ref_clone.clone(),
|
||||||
props.clone(),
|
props.clone(),
|
||||||
);
|
);
|
||||||
|
|
||||||
Mounted {
|
Mounted {
|
||||||
node_ref: node_ref.clone(),
|
node_ref: node_ref_clone.clone(),
|
||||||
scope: scope.clone().into(),
|
scope: scope.clone().into(),
|
||||||
destroyer: Box::new(move || scope.destroy()),
|
destroyer: Box::new(move || scope.destroy()),
|
||||||
}
|
}
|
||||||
@ -115,7 +109,7 @@ impl VComp {
|
|||||||
scope.update(ComponentUpdate::Properties(props.clone()));
|
scope.update(ComponentUpdate::Properties(props.clone()));
|
||||||
|
|
||||||
Mounted {
|
Mounted {
|
||||||
node_ref: node_ref.clone(),
|
node_ref: node_ref_clone.clone(),
|
||||||
scope: scope.clone().into(),
|
scope: scope.clone().into(),
|
||||||
destroyer: Box::new(move || scope.destroy()),
|
destroyer: Box::new(move || scope.destroy()),
|
||||||
}
|
}
|
||||||
@ -128,6 +122,7 @@ impl VComp {
|
|||||||
state: Rc::new(RefCell::new(MountState::Unmounted(Unmounted {
|
state: Rc::new(RefCell::new(MountState::Unmounted(Unmounted {
|
||||||
generator: Box::new(generator),
|
generator: Box::new(generator),
|
||||||
}))),
|
}))),
|
||||||
|
node_ref,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -215,16 +210,13 @@ impl VDiff for VComp {
|
|||||||
this.mount(parent.to_owned(), dummy_node)
|
this.mount(parent.to_owned(), dummy_node)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let node = mounted.node_ref.get();
|
|
||||||
self.state.replace(MountState::Mounted(mounted));
|
self.state.replace(MountState::Mounted(mounted));
|
||||||
node
|
|
||||||
}
|
}
|
||||||
state => {
|
state => {
|
||||||
self.state.replace(state);
|
self.state.replace(state);
|
||||||
None
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user