mirror of
https://github.com/yewstack/yew.git
synced 2025-12-08 21:26:25 +00:00
Replace mounted with rendered lifecycle method (#1072)
* Replace mounted with rendered lifecycle method * Cleanup
This commit is contained in:
parent
d799368894
commit
a91e7f6512
@ -28,11 +28,12 @@ impl Component for Model {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mounted(&mut self) -> ShouldRender {
|
fn rendered(&mut self, first_render: bool) {
|
||||||
if let Some(input) = self.refs[self.focus_index].cast::<InputElement>() {
|
if first_render {
|
||||||
input.focus().unwrap();
|
if let Some(input) = self.refs[self.focus_index].cast::<InputElement>() {
|
||||||
|
input.focus().unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
||||||
|
|||||||
@ -1,10 +1,9 @@
|
|||||||
|
use wasm_bindgen::JsCast;
|
||||||
use web_sys::HtmlCanvasElement;
|
use web_sys::HtmlCanvasElement;
|
||||||
use web_sys::WebGlRenderingContext as GL;
|
use web_sys::WebGlRenderingContext as GL;
|
||||||
use yew::services::{RenderService, Task};
|
use yew::services::{RenderService, Task};
|
||||||
use yew::{html, Component, ComponentLink, Html, NodeRef, ShouldRender};
|
use yew::{html, Component, ComponentLink, Html, NodeRef, ShouldRender};
|
||||||
|
|
||||||
use wasm_bindgen::JsCast;
|
|
||||||
|
|
||||||
pub struct Model {
|
pub struct Model {
|
||||||
canvas: Option<HtmlCanvasElement>,
|
canvas: Option<HtmlCanvasElement>,
|
||||||
gl: Option<GL>,
|
gl: Option<GL>,
|
||||||
@ -31,8 +30,8 @@ impl Component for Model {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mounted(&mut self) -> ShouldRender {
|
fn rendered(&mut self, first_render: bool) {
|
||||||
// Once mounted, store references for the canvas and GL context. These can be used for
|
// Once rendered, store references for the canvas and GL context. These can be used for
|
||||||
// resizing the rendering area when the window or canvas element are resized, as well as
|
// resizing the rendering area when the window or canvas element are resized, as well as
|
||||||
// for making GL calls.
|
// for making GL calls.
|
||||||
|
|
||||||
@ -52,18 +51,16 @@ impl Component for Model {
|
|||||||
// done here, such as enabling or disabling depth testing, depth functions, face
|
// done here, such as enabling or disabling depth testing, depth functions, face
|
||||||
// culling etc.
|
// culling etc.
|
||||||
|
|
||||||
// The callback to request animation frame is passed a time value which can be used for
|
if first_render {
|
||||||
// rendering motion independent of the framerate which may vary.
|
// The callback to request animation frame is passed a time value which can be used for
|
||||||
let render_frame = self.link.callback(Msg::Render);
|
// rendering motion independent of the framerate which may vary.
|
||||||
let handle = RenderService::new().request_animation_frame(render_frame);
|
let render_frame = self.link.callback(Msg::Render);
|
||||||
|
let handle = RenderService::new().request_animation_frame(render_frame);
|
||||||
|
|
||||||
// A reference to the handle must be stored, otherwise it is dropped and the render won't
|
// A reference to the handle must be stored, otherwise it is dropped and the render won't
|
||||||
// occur.
|
// occur.
|
||||||
self.render_loop = Some(Box::new(handle));
|
self.render_loop = Some(Box::new(handle));
|
||||||
|
}
|
||||||
// Since WebGL is rendered to the canvas "separate" from the DOM, there is no need to
|
|
||||||
// render the DOM element(s) again.
|
|
||||||
false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
||||||
|
|||||||
@ -181,9 +181,16 @@ fn use_effect_destroys_on_component_drop() {
|
|||||||
type TProps = DestroyCalledProps;
|
type TProps = DestroyCalledProps;
|
||||||
|
|
||||||
fn run(props: &Self::TProps) -> Html {
|
fn run(props: &Self::TProps) -> Html {
|
||||||
let (should_rerender, set_rerender) = use_state(|| true);
|
let (show, set_show) = use_state(|| true);
|
||||||
if *should_rerender {
|
use_effect_with_deps(
|
||||||
set_rerender(false);
|
move |_| {
|
||||||
|
set_show(false);
|
||||||
|
|| {}
|
||||||
|
},
|
||||||
|
(),
|
||||||
|
);
|
||||||
|
|
||||||
|
if *show {
|
||||||
return html! {
|
return html! {
|
||||||
<UseEffectComponent destroy_called=props.destroy_called.clone() />
|
<UseEffectComponent destroy_called=props.destroy_called.clone() />
|
||||||
};
|
};
|
||||||
@ -196,11 +203,11 @@ fn use_effect_destroys_on_component_drop() {
|
|||||||
}
|
}
|
||||||
let app: App<UseEffectWrapperComponent> = yew::App::new();
|
let app: App<UseEffectWrapperComponent> = yew::App::new();
|
||||||
let destroy_counter = Rc::new(std::cell::RefCell::new(0));
|
let destroy_counter = Rc::new(std::cell::RefCell::new(0));
|
||||||
let destroy_country_c = destroy_counter.clone();
|
let destroy_counter_c = destroy_counter.clone();
|
||||||
app.mount_with_props(
|
app.mount_with_props(
|
||||||
yew::utils::document().get_element_by_id("output").unwrap(),
|
yew::utils::document().get_element_by_id("output").unwrap(),
|
||||||
DestroyCalledProps {
|
DestroyCalledProps {
|
||||||
destroy_called: Rc::new(move || *destroy_country_c.borrow_mut().deref_mut() += 1),
|
destroy_called: Rc::new(move || *destroy_counter_c.borrow_mut().deref_mut() += 1),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
assert_eq!(1, *destroy_counter.borrow().deref());
|
assert_eq!(1, *destroy_counter.borrow().deref());
|
||||||
|
|||||||
@ -34,18 +34,21 @@ impl Component for Guide {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mounted(&mut self) -> ShouldRender {
|
fn rendered(&mut self, _first_render: bool) {
|
||||||
self.router_agent.send(GetCurrentRoute);
|
self.router_agent.send(GetCurrentRoute);
|
||||||
false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, msg: Self::Message) -> bool {
|
fn update(&mut self, msg: Self::Message) -> bool {
|
||||||
match msg {
|
match msg {
|
||||||
Msg::UpdateRoute(route) => {
|
Msg::UpdateRoute(route) => {
|
||||||
self.route = Some(route);
|
let new_route = Some(route);
|
||||||
|
if self.route != new_route {
|
||||||
|
self.route = new_route;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
true
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change(&mut self, _: Self::Properties) -> bool {
|
fn change(&mut self, _: Self::Properties) -> bool {
|
||||||
|
|||||||
@ -41,10 +41,6 @@ impl Component for MarkdownWindow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mounted(&mut self) -> ShouldRender {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update(&mut self, msg: Self::Message) -> bool {
|
fn update(&mut self, msg: Self::Message) -> bool {
|
||||||
match msg {
|
match msg {
|
||||||
Msg::MarkdownArrived(md) => {
|
Msg::MarkdownArrived(md) => {
|
||||||
|
|||||||
@ -185,9 +185,8 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mounted(&mut self) -> ShouldRender {
|
fn rendered(&mut self, _first_render: bool) {
|
||||||
self.router_agent.send(RouteRequest::GetCurrentRoute);
|
self.router_agent.send(RouteRequest::GetCurrentRoute);
|
||||||
false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
||||||
|
|||||||
@ -29,11 +29,12 @@ impl Component for Model {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mounted(&mut self) -> ShouldRender {
|
fn rendered(&mut self, first_render: bool) {
|
||||||
if let Some(input) = self.refs[self.focus_index].cast::<InputElement>() {
|
if first_render {
|
||||||
input.focus();
|
if let Some(input) = self.refs[self.focus_index].cast::<InputElement>() {
|
||||||
|
input.focus();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
||||||
|
|||||||
@ -33,8 +33,8 @@ impl Component for Model {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mounted(&mut self) -> ShouldRender {
|
fn rendered(&mut self, first_render: bool) {
|
||||||
// Once mounted, store references for the canvas and GL context. These can be used for
|
// Once rendered, store references for the canvas and GL context. These can be used for
|
||||||
// resizing the rendering area when the window or canvas element are resized, as well as
|
// resizing the rendering area when the window or canvas element are resized, as well as
|
||||||
// for making GL calls.
|
// for making GL calls.
|
||||||
let c: CanvasElement = self.node_ref.cast().unwrap();
|
let c: CanvasElement = self.node_ref.cast().unwrap();
|
||||||
@ -47,18 +47,16 @@ impl Component for Model {
|
|||||||
// done here, such as enabling or disabling depth testing, depth functions, face
|
// done here, such as enabling or disabling depth testing, depth functions, face
|
||||||
// culling etc.
|
// culling etc.
|
||||||
|
|
||||||
// The callback to request animation frame is passed a time value which can be used for
|
if first_render {
|
||||||
// rendering motion independent of the framerate which may vary.
|
// The callback to request animation frame is passed a time value which can be used for
|
||||||
let render_frame = self.link.callback(Msg::Render);
|
// rendering motion independent of the framerate which may vary.
|
||||||
let handle = RenderService::new().request_animation_frame(render_frame);
|
let render_frame = self.link.callback(Msg::Render);
|
||||||
|
let handle = RenderService::new().request_animation_frame(render_frame);
|
||||||
|
|
||||||
// A reference to the handle must be stored, otherwise it is dropped and the render won't
|
// A reference to the handle must be stored, otherwise it is dropped and the render won't
|
||||||
// occur.
|
// occur.
|
||||||
self.render_loop = Some(Box::new(handle));
|
self.render_loop = Some(Box::new(handle));
|
||||||
|
}
|
||||||
// Since WebGL is rendered to the canvas "separate" from the DOM, there is no need to
|
|
||||||
// render the DOM element(s) again.
|
|
||||||
false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
||||||
|
|||||||
@ -67,14 +67,9 @@ pub trait Component: Sized + 'static {
|
|||||||
/// Components are created with their properties as well as a `ComponentLink` which
|
/// Components are created with their properties as well as a `ComponentLink` which
|
||||||
/// can be used to send messages and create callbacks for triggering updates.
|
/// can be used to send messages and create callbacks for triggering updates.
|
||||||
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self;
|
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self;
|
||||||
/// Called after the component has been attached to the VDOM and it is safe to receive messages
|
|
||||||
/// from agents but before the browser updates the screen. If true is returned, the view will
|
/// Components handle messages in their `update` method and commonly use this method
|
||||||
/// be re-rendered and the user will not see the initial render.
|
/// to update their state and (optionally) re-render themselves.
|
||||||
fn mounted(&mut self) -> ShouldRender {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
/// Called everytime when a messages of `Msg` type received. It also takes a
|
|
||||||
/// reference to a context.
|
|
||||||
fn update(&mut self, msg: Self::Message) -> ShouldRender;
|
fn update(&mut self, msg: Self::Message) -> ShouldRender;
|
||||||
|
|
||||||
/// When the parent of a Component is re-rendered, it will either be re-created or
|
/// When the parent of a Component is re-rendered, it will either be re-created or
|
||||||
@ -107,7 +102,12 @@ pub trait Component: Sized + 'static {
|
|||||||
/// `html!` procedural macro. The full guide to using the macro can be found in [Yew's
|
/// `html!` procedural macro. The full guide to using the macro can be found in [Yew's
|
||||||
/// documentation](https://yew.rs/docs/concepts/html).
|
/// documentation](https://yew.rs/docs/concepts/html).
|
||||||
fn view(&self) -> Html;
|
fn view(&self) -> Html;
|
||||||
/// Called for finalization on the final point of the component's lifetime.
|
|
||||||
|
/// The `rendered` method is called after each time a Component is rendered but
|
||||||
|
/// before the browser updates the page.
|
||||||
|
fn rendered(&mut self, _first_render: bool) {}
|
||||||
|
|
||||||
|
/// The `destroy` method is called right before a Component is unmounted.
|
||||||
fn destroy(&mut self) {} // TODO(#941): Replace with `Drop`
|
fn destroy(&mut self) {} // TODO(#941): Replace with `Drop`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -359,11 +359,12 @@ where
|
|||||||
/// }
|
/// }
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// fn mounted(&mut self) -> ShouldRender {
|
/// fn rendered(&mut self, first_render: bool) {
|
||||||
/// if let Some(input) = self.node_ref.cast::<InputElement>() {
|
/// if first_render {
|
||||||
/// input.focus();
|
/// if let Some(input) = self.node_ref.cast::<InputElement>() {
|
||||||
|
/// input.focus();
|
||||||
|
/// }
|
||||||
/// }
|
/// }
|
||||||
/// false
|
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// fn change(&mut self, _: Self::Properties) -> ShouldRender {
|
/// fn change(&mut self, _: Self::Properties) -> ShouldRender {
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate::scheduler::{scheduler, Runnable, Shared};
|
use crate::scheduler::{scheduler, ComponentRunnableType, Runnable, Shared};
|
||||||
use crate::virtual_dom::{VDiff, VNode};
|
use crate::virtual_dom::{VDiff, VNode};
|
||||||
use cfg_if::cfg_if;
|
use cfg_if::cfg_if;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
@ -73,22 +73,15 @@ impl<COMP: Component> Scope<COMP> {
|
|||||||
};
|
};
|
||||||
*scope.shared_state.borrow_mut() = ComponentState::Ready(ready_state);
|
*scope.shared_state.borrow_mut() = ComponentState::Ready(ready_state);
|
||||||
scope.create();
|
scope.create();
|
||||||
scope.mounted();
|
|
||||||
scope
|
scope
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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 = 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
|
/// 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().push_create(Box::new(create));
|
scheduler().push_comp(ComponentRunnableType::Create, Box::new(create));
|
||||||
|
self.rendered(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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
|
||||||
@ -97,14 +90,25 @@ impl<COMP: Component> Scope<COMP> {
|
|||||||
shared_state: self.shared_state.clone(),
|
shared_state: self.shared_state.clone(),
|
||||||
update,
|
update,
|
||||||
};
|
};
|
||||||
scheduler().push(Box::new(update));
|
scheduler().push_comp(ComponentRunnableType::Update, Box::new(update));
|
||||||
|
self.rendered(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Schedules a task to call the rendered method on a component
|
||||||
|
pub(crate) fn rendered(&self, first_render: bool) {
|
||||||
|
let shared_state = self.shared_state.clone();
|
||||||
|
let rendered = RenderedComponent {
|
||||||
|
shared_state,
|
||||||
|
first_render,
|
||||||
|
};
|
||||||
|
scheduler().push_comp(ComponentRunnableType::Rendered, Box::new(rendered));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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().push(Box::new(destroy));
|
scheduler().push_comp(ComponentRunnableType::Destroy, Box::new(destroy));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send a message to the component
|
/// Send a message to the component
|
||||||
@ -113,10 +117,13 @@ impl<COMP: Component> Scope<COMP> {
|
|||||||
T: Into<COMP::Message>,
|
T: Into<COMP::Message>,
|
||||||
{
|
{
|
||||||
self.update(ComponentUpdate::Message(msg.into()));
|
self.update(ComponentUpdate::Message(msg.into()));
|
||||||
|
self.rendered(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send a batch of messages to the component
|
/// Send a batch of messages to the component
|
||||||
pub fn send_message_batch(&self, messages: Vec<COMP::Message>) {
|
pub fn send_message_batch(&self, messages: Vec<COMP::Message>) {
|
||||||
self.update(ComponentUpdate::MessageBatch(messages));
|
self.update(ComponentUpdate::MessageBatch(messages));
|
||||||
|
self.rendered(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a `Callback` which will send a message to the linked component's
|
/// Creates a `Callback` which will send a message to the linked component's
|
||||||
@ -196,6 +203,7 @@ struct ReadyState<COMP: Component> {
|
|||||||
impl<COMP: Component> ReadyState<COMP> {
|
impl<COMP: Component> ReadyState<COMP> {
|
||||||
fn create(self) -> CreatedState<COMP> {
|
fn create(self) -> CreatedState<COMP> {
|
||||||
CreatedState {
|
CreatedState {
|
||||||
|
rendered: false,
|
||||||
component: COMP::create(self.props, self.scope),
|
component: COMP::create(self.props, self.scope),
|
||||||
element: self.element,
|
element: self.element,
|
||||||
last_frame: self.ancestor,
|
last_frame: self.ancestor,
|
||||||
@ -205,6 +213,7 @@ impl<COMP: Component> ReadyState<COMP> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct CreatedState<COMP: Component> {
|
struct CreatedState<COMP: Component> {
|
||||||
|
rendered: bool,
|
||||||
element: Element,
|
element: Element,
|
||||||
component: COMP,
|
component: COMP,
|
||||||
last_frame: Option<VNode>,
|
last_frame: Option<VNode>,
|
||||||
@ -212,13 +221,11 @@ struct CreatedState<COMP: Component> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<COMP: Component> CreatedState<COMP> {
|
impl<COMP: Component> CreatedState<COMP> {
|
||||||
/// Called once immediately after the component is created.
|
/// Called after a component and all of its children have been rendered.
|
||||||
fn mounted(mut self) -> Self {
|
fn rendered(mut self, first_render: bool) -> Self {
|
||||||
if self.component.mounted() {
|
self.rendered = true;
|
||||||
self.update()
|
self.component.rendered(first_render);
|
||||||
} else {
|
self
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(mut self) -> Self {
|
fn update(mut self) -> Self {
|
||||||
@ -237,22 +244,25 @@ impl<COMP: Component> CreatedState<COMP> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct MountedComponent<COMP>
|
struct RenderedComponent<COMP>
|
||||||
where
|
where
|
||||||
COMP: Component,
|
COMP: Component,
|
||||||
{
|
{
|
||||||
shared_state: Shared<ComponentState<COMP>>,
|
shared_state: Shared<ComponentState<COMP>>,
|
||||||
|
first_render: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<COMP> Runnable for MountedComponent<COMP>
|
impl<COMP> Runnable for RenderedComponent<COMP>
|
||||||
where
|
where
|
||||||
COMP: Component,
|
COMP: Component,
|
||||||
{
|
{
|
||||||
fn run(self: Box<Self>) {
|
fn run(self: Box<Self>) {
|
||||||
let current_state = self.shared_state.replace(ComponentState::Processing);
|
let current_state = self.shared_state.replace(ComponentState::Processing);
|
||||||
self.shared_state.replace(match current_state {
|
self.shared_state.replace(match current_state {
|
||||||
ComponentState::Created(state) => ComponentState::Created(state.mounted()),
|
ComponentState::Created(s) if !s.rendered => {
|
||||||
ComponentState::Destroyed => current_state,
|
ComponentState::Created(s.rendered(self.first_render))
|
||||||
|
}
|
||||||
|
ComponentState::Destroyed | ComponentState::Created(_) => current_state,
|
||||||
ComponentState::Empty | ComponentState::Processing | ComponentState::Ready(_) => {
|
ComponentState::Empty | ComponentState::Processing | ComponentState::Ready(_) => {
|
||||||
panic!("unexpected component state: {}", current_state);
|
panic!("unexpected component state: {}", current_state);
|
||||||
}
|
}
|
||||||
@ -274,7 +284,7 @@ where
|
|||||||
fn run(self: Box<Self>) {
|
fn run(self: Box<Self>) {
|
||||||
let current_state = self.shared_state.replace(ComponentState::Processing);
|
let current_state = self.shared_state.replace(ComponentState::Processing);
|
||||||
self.shared_state.replace(match current_state {
|
self.shared_state.replace(match current_state {
|
||||||
ComponentState::Ready(state) => ComponentState::Created(state.create().update()),
|
ComponentState::Ready(s) => ComponentState::Created(s.create().update()),
|
||||||
ComponentState::Created(_) | ComponentState::Destroyed => current_state,
|
ComponentState::Created(_) | ComponentState::Destroyed => current_state,
|
||||||
ComponentState::Empty | ComponentState::Processing => {
|
ComponentState::Empty | ComponentState::Processing => {
|
||||||
panic!("unexpected component state: {}", current_state);
|
panic!("unexpected component state: {}", current_state);
|
||||||
@ -341,7 +351,12 @@ where
|
|||||||
this.component.change(props)
|
this.component.change(props)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let next_state = if should_update { this.update() } else { this };
|
let next_state = if should_update {
|
||||||
|
this.rendered = false;
|
||||||
|
this.update()
|
||||||
|
} else {
|
||||||
|
this
|
||||||
|
};
|
||||||
ComponentState::Created(next_state)
|
ComponentState::Created(next_state)
|
||||||
}
|
}
|
||||||
ComponentState::Destroyed => current_state,
|
ComponentState::Destroyed => current_state,
|
||||||
|
|||||||
@ -26,8 +26,43 @@ pub(crate) trait Runnable {
|
|||||||
pub(crate) struct Scheduler {
|
pub(crate) struct Scheduler {
|
||||||
lock: Rc<RefCell<()>>,
|
lock: Rc<RefCell<()>>,
|
||||||
main: Shared<VecDeque<Box<dyn Runnable>>>,
|
main: Shared<VecDeque<Box<dyn Runnable>>>,
|
||||||
create_component: Shared<VecDeque<Box<dyn Runnable>>>,
|
component: ComponentScheduler,
|
||||||
mount_component: Shared<Vec<Box<dyn Runnable>>>,
|
}
|
||||||
|
|
||||||
|
pub(crate) enum ComponentRunnableType {
|
||||||
|
Destroy,
|
||||||
|
Create,
|
||||||
|
Update,
|
||||||
|
Rendered,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct ComponentScheduler {
|
||||||
|
// Queues
|
||||||
|
destroy: Shared<VecDeque<Box<dyn Runnable>>>,
|
||||||
|
create: Shared<VecDeque<Box<dyn Runnable>>>,
|
||||||
|
update: Shared<VecDeque<Box<dyn Runnable>>>,
|
||||||
|
|
||||||
|
// Stack
|
||||||
|
rendered: Shared<Vec<Box<dyn Runnable>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ComponentScheduler {
|
||||||
|
fn new() -> Self {
|
||||||
|
ComponentScheduler {
|
||||||
|
destroy: Rc::new(RefCell::new(VecDeque::new())),
|
||||||
|
create: Rc::new(RefCell::new(VecDeque::new())),
|
||||||
|
update: Rc::new(RefCell::new(VecDeque::new())),
|
||||||
|
rendered: Rc::new(RefCell::new(Vec::new())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next_runnable(&self) -> Option<Box<dyn Runnable>> {
|
||||||
|
None.or_else(|| self.destroy.borrow_mut().pop_front())
|
||||||
|
.or_else(|| self.create.borrow_mut().pop_front())
|
||||||
|
.or_else(|| self.update.borrow_mut().pop_front())
|
||||||
|
.or_else(|| self.rendered.borrow_mut().pop())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Scheduler {
|
impl Scheduler {
|
||||||
@ -35,43 +70,36 @@ impl Scheduler {
|
|||||||
Scheduler {
|
Scheduler {
|
||||||
lock: Rc::new(RefCell::new(())),
|
lock: Rc::new(RefCell::new(())),
|
||||||
main: Rc::new(RefCell::new(VecDeque::new())),
|
main: Rc::new(RefCell::new(VecDeque::new())),
|
||||||
create_component: Rc::new(RefCell::new(VecDeque::new())),
|
component: ComponentScheduler::new(),
|
||||||
mount_component: Rc::new(RefCell::new(Vec::new())),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn push_comp(&self, run_type: ComponentRunnableType, runnable: Box<dyn Runnable>) {
|
||||||
|
match run_type {
|
||||||
|
ComponentRunnableType::Destroy => {
|
||||||
|
self.component.destroy.borrow_mut().push_back(runnable)
|
||||||
|
}
|
||||||
|
ComponentRunnableType::Create => self.component.create.borrow_mut().push_back(runnable),
|
||||||
|
ComponentRunnableType::Update => self.component.update.borrow_mut().push_back(runnable),
|
||||||
|
ComponentRunnableType::Rendered => self.component.rendered.borrow_mut().push(runnable),
|
||||||
|
};
|
||||||
|
self.start();
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn push(&self, runnable: Box<dyn Runnable>) {
|
pub(crate) fn push(&self, runnable: Box<dyn Runnable>) {
|
||||||
self.main.borrow_mut().push_back(runnable);
|
self.main.borrow_mut().push_back(runnable);
|
||||||
self.start();
|
self.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn push_create(&self, runnable: Box<dyn Runnable>) {
|
fn next_runnable(&self) -> Option<Box<dyn Runnable>> {
|
||||||
self.create_component.borrow_mut().push_back(runnable);
|
None.or_else(|| self.component.next_runnable())
|
||||||
self.start();
|
.or_else(|| self.main.borrow_mut().pop_front())
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn push_mount(&self, runnable: Box<dyn Runnable>) {
|
|
||||||
self.mount_component.borrow_mut().push(runnable);
|
|
||||||
self.start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn start(&self) {
|
pub(crate) fn start(&self) {
|
||||||
let lock = self.lock.try_borrow_mut();
|
if let Ok(_lock) = self.lock.try_borrow_mut() {
|
||||||
if lock.is_err() {
|
while let Some(runnable) = self.next_runnable() {
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
loop {
|
|
||||||
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();
|
runnable.run();
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user