Skip to content

Commit 14d3845

Browse files
committed
move props inside Context
1 parent 7bc35e1 commit 14d3845

File tree

8 files changed

+116
-141
lines changed

8 files changed

+116
-141
lines changed

packages/yew/src/context.rs

Lines changed: 13 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ use crate::html::Scope;
55
use crate::{html, Callback, Children, Component, Html, Properties, ShouldRender};
66
use slab::Slab;
77
use std::cell::RefCell;
8-
use std::rc::Rc;
98

109
/// Props for [`ContextProvider`]
1110
#[derive(Debug, Clone, PartialEq, Properties)]
@@ -23,9 +22,7 @@ pub struct ContextProviderProps<T: Clone + PartialEq> {
2322
/// In function components the `use_context` hook is used.
2423
#[derive(Debug)]
2524
pub struct ContextProvider<T: Clone + PartialEq + 'static> {
26-
component_context: Context<Self>,
2725
context: T,
28-
children: Children,
2926
consumers: RefCell<Slab<Callback<T>>>,
3027
}
3128

@@ -48,14 +45,18 @@ impl<T: Clone + PartialEq + 'static> Drop for ContextHandle<T> {
4845
impl<T: Clone + PartialEq> ContextProvider<T> {
4946
/// Add the callback to the subscriber list to be called whenever the context changes.
5047
/// The consumer is unsubscribed as soon as the callback is dropped.
51-
pub(crate) fn subscribe_consumer(&self, callback: Callback<T>) -> (T, ContextHandle<T>) {
48+
pub(crate) fn subscribe_consumer(
49+
&self,
50+
callback: Callback<T>,
51+
scope: Scope<Self>,
52+
) -> (T, ContextHandle<T>) {
5253
let ctx = self.context.clone();
5354
let key = self.consumers.borrow_mut().insert(callback);
5455

5556
(
5657
ctx,
5758
ContextHandle {
58-
provider: self.component_context.clone(),
59+
provider: scope,
5960
key,
6061
},
6162
)
@@ -79,11 +80,9 @@ impl<T: Clone + PartialEq + 'static> Component for ContextProvider<T> {
7980
type Message = ();
8081
type Properties = ContextProviderProps<T>;
8182

82-
fn create(props: Rc<Self::Properties>, ctx: &Context<Self>) -> Self {
83+
fn create(ctx: &Context<Self>) -> Self {
8384
Self {
84-
component_context: ctx.clone(),
85-
children: props.children.clone(),
86-
context: props.context.clone(),
85+
context: ctx.props().context.clone(),
8786
consumers: RefCell::new(Slab::new()),
8887
}
8988
}
@@ -92,23 +91,12 @@ impl<T: Clone + PartialEq + 'static> Component for ContextProvider<T> {
9291
true
9392
}
9493

95-
fn changed(&mut self, _ctx: &Context<Self>, props: Rc<Self::Properties>) -> bool {
96-
let should_render = if self.children == props.children {
97-
false
98-
} else {
99-
self.children = props.children.clone();
100-
true
101-
};
102-
103-
if self.context != props.context {
104-
self.context = props.context.clone();
105-
self.notify_consumers();
106-
}
107-
108-
should_render
94+
fn changed(&mut self, _ctx: &Context<Self>) -> bool {
95+
self.notify_consumers();
96+
true
10997
}
11098

111-
fn view(&self, _ctx: &Context<Self>) -> Html {
112-
html! { <>{ self.children.clone() }</> }
99+
fn view(&self, ctx: &Context<Self>) -> Html {
100+
html! { <>{ ctx.props().children.clone() }</> }
113101
}
114102
}

packages/yew/src/functional/mod.rs

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,6 @@ pub trait FunctionProvider {
7979
/// Wrapper that allows a struct implementing [`FunctionProvider`] to be consumed as a component.
8080
pub struct FunctionComponent<T: FunctionProvider + 'static> {
8181
_never: std::marker::PhantomData<T>,
82-
props: Rc<T::TProps>,
8382
hook_state: RefCell<HookState>,
8483
message_queue: MsgQueue,
8584
}
@@ -108,24 +107,23 @@ where
108107
type Message = Box<dyn FnOnce() -> bool>;
109108
type Properties = T::TProps;
110109

111-
fn create(props: Rc<Self::Properties>, ctx: &Context<Self>) -> Self {
112-
let scope = AnyScope::from(ctx.clone());
110+
fn create(ctx: &Context<Self>) -> Self {
111+
let scope = AnyScope::from(ctx.link().clone());
113112
let message_queue = MsgQueue::default();
114113

115114
Self {
116115
_never: std::marker::PhantomData::default(),
117-
props: Rc::clone(&props),
118116
message_queue: message_queue.clone(),
119117
hook_state: RefCell::new(HookState {
120118
counter: 0,
121119
scope,
122120
process_message: {
123-
let ctx = ctx.clone();
121+
let scope = ctx.link().clone();
124122
Rc::new(move |msg, post_render| {
125123
if post_render {
126124
message_queue.push(msg);
127125
} else {
128-
ctx.send_message(msg);
126+
scope.send_message(msg);
129127
}
130128
})
131129
},
@@ -139,18 +137,13 @@ where
139137
msg()
140138
}
141139

142-
fn changed(&mut self, _ctx: &Context<Self>, props: Rc<Self::Properties>) -> bool {
143-
self.props = props;
144-
true
145-
}
146-
147-
fn view(&self, _ctx: &Context<Self>) -> Html {
148-
self.with_hook_state(|| T::run(&self.props))
140+
fn view(&self, ctx: &Context<Self>) -> Html {
141+
self.with_hook_state(|| T::run(&*ctx.props()))
149142
}
150143

151144
fn rendered(&mut self, ctx: &Context<Self>, _first_render: bool) {
152145
for msg in self.message_queue.drain() {
153-
ctx.send_message(msg);
146+
ctx.link().send_message(msg);
154147
}
155148
}
156149

packages/yew/src/html/component/lifecycle.rs

Lines changed: 47 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,15 @@
33
use super::{Component, Scope};
44
use crate::scheduler::{self, Runnable, Shared};
55
use crate::virtual_dom::{VDiff, VNode};
6-
use crate::NodeRef;
6+
use crate::{Context, NodeRef};
77
use std::rc::Rc;
88
use web_sys::Element;
99

1010
pub(crate) struct ComponentState<COMP: Component> {
1111
pub(crate) component: Box<COMP>,
1212
pub(crate) root_node: VNode,
1313

14-
scope: Scope<COMP>,
14+
context: Context<COMP>,
1515
parent: Element,
1616
next_sibling: NodeRef,
1717
node_ref: NodeRef,
@@ -29,11 +29,13 @@ impl<COMP: Component> ComponentState<COMP> {
2929
scope: Scope<COMP>,
3030
props: Rc<COMP::Properties>,
3131
) -> Self {
32-
let component = Box::new(COMP::create(Rc::clone(&props), &scope));
32+
let context = Context { scope, props };
33+
34+
let component = Box::new(COMP::create(&context));
3335
Self {
3436
component,
3537
root_node,
36-
scope,
38+
context,
3739
parent,
3840
next_sibling,
3941
node_ref,
@@ -127,25 +129,26 @@ impl<COMP: Component> Runnable for ComponentRunnable<COMP> {
127129
let should_render = match event {
128130
UpdateEvent::First => true,
129131
UpdateEvent::Message(message) => {
130-
state.component.update(&state.scope, message)
132+
state.component.update(&state.context, message)
131133
}
132134
UpdateEvent::MessageBatch(messages) => {
133135
messages.into_iter().fold(false, |acc, msg| {
134-
state.component.update(&state.scope, msg) || acc
136+
state.component.update(&state.context, msg) || acc
135137
})
136138
}
137139
UpdateEvent::Properties(props, node_ref, next_sibling) => {
138140
// When components are updated, a new node ref could have been passed in
139141
state.node_ref = node_ref;
140142
// When components are updated, their siblings were likely also updated
141143
state.next_sibling = next_sibling;
142-
state.component.changed(&state.scope, Rc::clone(&props))
144+
state.context.props = Rc::clone(&props);
145+
state.component.changed(&state.context)
143146
}
144147
};
145148

146149
if should_render {
147-
state.pending_root = Some(state.component.view(&state.scope));
148-
state.scope.process(ComponentLifecycleEvent::Render);
150+
state.pending_root = Some(state.component.view(&state.context));
151+
state.context.scope.process(ComponentLifecycleEvent::Render);
149152
};
150153
}
151154
}
@@ -155,25 +158,28 @@ impl<COMP: Component> Runnable for ComponentRunnable<COMP> {
155158
std::mem::swap(&mut new_root, &mut state.root_node);
156159
let ancestor = Some(new_root);
157160
let new_root = &mut state.root_node;
158-
let scope = state.scope.clone().into();
161+
let scope = state.context.scope.clone().into();
159162
let next_sibling = state.next_sibling.clone();
160163
let node = new_root.apply(&scope, &state.parent, next_sibling, ancestor);
161164
state.node_ref.link(node);
162-
state.scope.process(ComponentLifecycleEvent::Rendered);
165+
state
166+
.context
167+
.scope
168+
.process(ComponentLifecycleEvent::Rendered);
163169
}
164170
}
165171
}
166172
ComponentLifecycleEvent::Rendered => {
167173
if let Some(mut state) = current_state.as_mut() {
168174
let first_render = !state.has_rendered;
169-
state.component.rendered(&state.scope, first_render);
175+
state.component.rendered(&state.context, first_render);
170176
state.has_rendered = true;
171177
state.drain_pending_updates(&self.state);
172178
}
173179
}
174180
ComponentLifecycleEvent::Destroy => {
175181
if let Some(mut state) = current_state.take() {
176-
state.component.destroy(&state.scope);
182+
state.component.destroy(&state.context);
177183
state.root_node.detach(&state.parent);
178184
state.node_ref.set(None);
179185
}
@@ -201,20 +207,18 @@ mod tests {
201207
lifecycle: Rc<RefCell<Vec<String>>>,
202208
}
203209

204-
struct Child {
205-
props: Rc<ChildProps>,
206-
}
210+
struct Child {}
207211

208212
impl Component for Child {
209213
type Message = ();
210214
type Properties = ChildProps;
211215

212-
fn create(props: Rc<Self::Properties>, _ctx: &Context<Self>) -> Self {
213-
Child { props }
216+
fn create(_ctx: &Context<Self>) -> Self {
217+
Child {}
214218
}
215219

216-
fn rendered(&mut self, _ctx: &Context<Self>, _first_render: bool) {
217-
self.props
220+
fn rendered(&mut self, ctx: &Context<Self>, _first_render: bool) {
221+
ctx.props()
218222
.lifecycle
219223
.borrow_mut()
220224
.push("child rendered".into());
@@ -224,7 +228,7 @@ mod tests {
224228
false
225229
}
226230

227-
fn changed(&mut self, _ctx: &Context<Self>, _: Rc<Self::Properties>) -> ShouldRender {
231+
fn changed(&mut self, _ctx: &Context<Self>) -> ShouldRender {
228232
false
229233
}
230234

@@ -245,60 +249,63 @@ mod tests {
245249
}
246250

247251
struct Comp {
248-
props: Rc<Props>,
252+
lifecycle: Rc<RefCell<Vec<String>>>,
249253
}
250254

251255
impl Component for Comp {
252256
type Message = bool;
253257
type Properties = Props;
254258

255-
fn create(props: Rc<Self::Properties>, ctx: &Context<Self>) -> Self {
256-
props.lifecycle.borrow_mut().push("create".into());
259+
fn create(ctx: &Context<Self>) -> Self {
260+
ctx.props().lifecycle.borrow_mut().push("create".into());
257261
#[cfg(feature = "wasm_test")]
258-
if let Some(msg) = props.create_message {
259-
ctx.send_message(msg);
262+
if let Some(msg) = ctx.props().create_message {
263+
ctx.link().send_message(msg);
264+
}
265+
Comp {
266+
lifecycle: Rc::clone(&ctx.props().lifecycle),
260267
}
261-
Comp { props }
262268
}
263269

264270
fn rendered(&mut self, ctx: &Context<Self>, first_render: bool) {
265-
if let Some(msg) = self.props.rendered_message.borrow_mut().take() {
266-
ctx.send_message(msg);
271+
if let Some(msg) = ctx.props().rendered_message.borrow_mut().take() {
272+
ctx.link().send_message(msg);
267273
}
268-
self.props
274+
ctx.props()
269275
.lifecycle
270276
.borrow_mut()
271277
.push(format!("rendered({})", first_render));
272278
}
273279

274280
fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> ShouldRender {
275-
if let Some(msg) = self.props.update_message.borrow_mut().take() {
276-
ctx.send_message(msg);
281+
if let Some(msg) = ctx.props().update_message.borrow_mut().take() {
282+
ctx.link().send_message(msg);
277283
}
278-
self.props
284+
ctx.props()
279285
.lifecycle
280286
.borrow_mut()
281287
.push(format!("update({})", msg));
282288
msg
283289
}
284290

285-
fn changed(&mut self, _ctx: &Context<Self>, _: Rc<Self::Properties>) -> ShouldRender {
286-
self.props.lifecycle.borrow_mut().push("change".into());
291+
fn changed(&mut self, ctx: &Context<Self>) -> ShouldRender {
292+
self.lifecycle = Rc::clone(&ctx.props().lifecycle);
293+
self.lifecycle.borrow_mut().push("change".into());
287294
false
288295
}
289296

290297
fn view(&self, ctx: &Context<Self>) -> Html {
291-
if let Some(msg) = self.props.view_message.borrow_mut().take() {
292-
ctx.send_message(msg);
298+
if let Some(msg) = ctx.props().view_message.borrow_mut().take() {
299+
ctx.link().send_message(msg);
293300
}
294-
self.props.lifecycle.borrow_mut().push("view".into());
295-
html! { <Child lifecycle={self.props.lifecycle.clone()} /> }
301+
self.lifecycle.borrow_mut().push("view".into());
302+
html! { <Child lifecycle={self.lifecycle.clone()} /> }
296303
}
297304
}
298305

299306
impl Drop for Comp {
300307
fn drop(&mut self) {
301-
self.props.lifecycle.borrow_mut().push("drop".into());
308+
self.lifecycle.borrow_mut().push("drop".into());
302309
}
303310
}
304311

packages/yew/src/html/component/mod.rs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,37 @@ use std::rc::Rc;
1616
pub type ShouldRender = bool;
1717

1818
/// Context
19-
pub type Context<T> = Scope<T>;
19+
#[derive(Debug)]
20+
pub struct Context<COMP: Component> {
21+
pub(crate) scope: Scope<COMP>,
22+
pub(crate) props: Rc<COMP::Properties>,
23+
}
24+
25+
impl<COMP: Component> Context<COMP> {
26+
/// The component link
27+
#[inline]
28+
pub fn link(&self) -> &Scope<COMP> {
29+
&self.scope
30+
}
31+
32+
/// The component's props
33+
#[inline]
34+
pub fn props(&self) -> &COMP::Properties {
35+
&*self.props
36+
}
37+
}
2038

2139
#[allow(missing_docs)]
2240
/// Yew component
2341
pub trait Component: Sized + 'static {
2442
type Message: 'static;
2543
type Properties: Properties;
2644

27-
fn create(props: Rc<Self::Properties>, ctx: &Context<Self>) -> Self;
45+
fn create(ctx: &Context<Self>) -> Self;
2846
fn update(&mut self, _ctx: &Context<Self>, _msg: Self::Message) -> ShouldRender {
2947
false
3048
}
31-
fn changed(&mut self, _ctx: &Context<Self>, _new_props: Rc<Self::Properties>) -> ShouldRender {
49+
fn changed(&mut self, _ctx: &Context<Self>) -> ShouldRender {
3250
true
3351
}
3452
fn view(&self, ctx: &Context<Self>) -> Html;

0 commit comments

Comments
 (0)