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,
|
||||
};
|
||||
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)]
|
||||
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 {
|
||||
/// Get the wrapped Node reference if it exists
|
||||
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
|
||||
@ -319,7 +326,12 @@ impl NodeRef {
|
||||
|
||||
/// Place a Node in a reference for later use
|
||||
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
|
||||
pub(crate) fn mounted(&mut self) {
|
||||
let shared_state = self.shared_state.clone();
|
||||
let mounted = Box::new(MountedComponent { shared_state });
|
||||
scheduler().put_and_try_run(mounted);
|
||||
let mounted = MountedComponent { shared_state };
|
||||
scheduler().push_mount(Box::new(mounted));
|
||||
}
|
||||
|
||||
/// Schedules a task to create and render a component and then mount it to the DOM
|
||||
pub(crate) fn create(&mut self) {
|
||||
let shared_state = self.shared_state.clone();
|
||||
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
|
||||
@ -94,14 +94,14 @@ impl<COMP: Component> Scope<COMP> {
|
||||
shared_state: self.shared_state.clone(),
|
||||
update,
|
||||
};
|
||||
scheduler().put_and_try_run(Box::new(update));
|
||||
scheduler().push(Box::new(update));
|
||||
}
|
||||
|
||||
/// Schedules a task to destroy a component
|
||||
pub(crate) fn destroy(&mut self) {
|
||||
let shared_state = self.shared_state.clone();
|
||||
let destroy = DestroyComponent { shared_state };
|
||||
scheduler().put_and_try_run(Box::new(destroy));
|
||||
scheduler().push(Box::new(destroy));
|
||||
}
|
||||
|
||||
/// Send a message to the component
|
||||
@ -173,10 +173,17 @@ impl<COMP: Component> CreatedState<COMP> {
|
||||
}
|
||||
|
||||
fn update(mut self) -> Self {
|
||||
let mut vnode = self.component.render();
|
||||
let node = vnode.apply(&self.element, None, self.last_frame);
|
||||
self.node_ref.set(node);
|
||||
self.last_frame = Some(vnode);
|
||||
let mut root = self.component.render();
|
||||
if let Some(node) = root.apply(&self.element, None, self.last_frame) {
|
||||
self.node_ref.set(Some(node));
|
||||
} 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
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,7 +3,6 @@
|
||||
use std::cell::RefCell;
|
||||
use std::collections::VecDeque;
|
||||
use std::rc::Rc;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
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.
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct Scheduler {
|
||||
lock: Rc<AtomicBool>,
|
||||
sequence: Shared<VecDeque<Box<dyn Runnable>>>,
|
||||
}
|
||||
|
||||
impl Clone for Scheduler {
|
||||
fn clone(&self) -> Self {
|
||||
Scheduler {
|
||||
lock: self.lock.clone(),
|
||||
sequence: self.sequence.clone(),
|
||||
}
|
||||
}
|
||||
lock: Rc<RefCell<()>>,
|
||||
main: Shared<VecDeque<Box<dyn Runnable>>>,
|
||||
create_component: Shared<VecDeque<Box<dyn Runnable>>>,
|
||||
mount_component: Shared<Vec<Box<dyn Runnable>>>,
|
||||
}
|
||||
|
||||
impl Scheduler {
|
||||
/// Creates a new scheduler with a context.
|
||||
fn new() -> Self {
|
||||
let sequence = VecDeque::new();
|
||||
Scheduler {
|
||||
lock: Rc::new(AtomicBool::new(false)),
|
||||
sequence: Rc::new(RefCell::new(sequence)),
|
||||
lock: Rc::new(RefCell::new(())),
|
||||
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>) {
|
||||
self.sequence.borrow_mut().push_back(runnable);
|
||||
if self.lock.compare_and_swap(false, true, Ordering::Relaxed) {
|
||||
pub(crate) fn push(&self, runnable: Box<dyn Runnable>) {
|
||||
self.main.borrow_mut().push_back(runnable);
|
||||
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;
|
||||
}
|
||||
|
||||
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 {
|
||||
runnable.run();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
self.lock.store(false, Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,18 +18,11 @@ enum GeneratorType {
|
||||
}
|
||||
|
||||
/// A virtual component.
|
||||
#[derive(Clone)]
|
||||
pub struct VComp {
|
||||
type_id: TypeId,
|
||||
state: Rc<RefCell<MountState>>,
|
||||
}
|
||||
|
||||
impl Clone for VComp {
|
||||
fn clone(&self) -> Self {
|
||||
VComp {
|
||||
type_id: self.type_id,
|
||||
state: self.state.clone(),
|
||||
}
|
||||
}
|
||||
pub(crate) node_ref: NodeRef,
|
||||
}
|
||||
|
||||
/// A virtual child component.
|
||||
@ -92,6 +85,7 @@ impl VComp {
|
||||
where
|
||||
COMP: Component,
|
||||
{
|
||||
let node_ref_clone = node_ref.clone();
|
||||
let generator = move |generator_type: GeneratorType| -> Mounted {
|
||||
match generator_type {
|
||||
GeneratorType::Mount(element, dummy_node) => {
|
||||
@ -100,12 +94,12 @@ impl VComp {
|
||||
let mut scope = scope.mount_in_place(
|
||||
element,
|
||||
Some(VNode::VRef(dummy_node.into())),
|
||||
node_ref.clone(),
|
||||
node_ref_clone.clone(),
|
||||
props.clone(),
|
||||
);
|
||||
|
||||
Mounted {
|
||||
node_ref: node_ref.clone(),
|
||||
node_ref: node_ref_clone.clone(),
|
||||
scope: scope.clone().into(),
|
||||
destroyer: Box::new(move || scope.destroy()),
|
||||
}
|
||||
@ -115,7 +109,7 @@ impl VComp {
|
||||
scope.update(ComponentUpdate::Properties(props.clone()));
|
||||
|
||||
Mounted {
|
||||
node_ref: node_ref.clone(),
|
||||
node_ref: node_ref_clone.clone(),
|
||||
scope: scope.clone().into(),
|
||||
destroyer: Box::new(move || scope.destroy()),
|
||||
}
|
||||
@ -128,6 +122,7 @@ impl VComp {
|
||||
state: Rc::new(RefCell::new(MountState::Unmounted(Unmounted {
|
||||
generator: Box::new(generator),
|
||||
}))),
|
||||
node_ref,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -215,17 +210,14 @@ impl VDiff for VComp {
|
||||
this.mount(parent.to_owned(), dummy_node)
|
||||
}
|
||||
};
|
||||
|
||||
let node = mounted.node_ref.get();
|
||||
self.state.replace(MountState::Mounted(mounted));
|
||||
node
|
||||
}
|
||||
state => {
|
||||
self.state.replace(state);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Transformer<T, T> for VComp {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user