Feat: massive changes to definition of components
This change switches back to the original `ctx<props>` syntax for commponents. This lets lifetime elision to remove the need to match exactly which lifetime (props or ctx) gets carried to the output. As such, `Props` is currently required to be static. It *is* possible to loosen this restriction, and will be done in the future, though only through adding metadata about the props through the Props derive macro. Implementing the IS_STATIC trait is unsafe, so the derive macro will do it through some heuristics. For now, this unlocks sharing vnodes from parents to children, enabling pass-thru components, fragments, portals, etc.
This commit is contained in:
1 parent
c1fd848f89
commit
508c560320
82 files changed
+692
-558
No files matched your search
@@ -112,8 +112,8 @@ impl<T: Clone + PartialEq + 'static> Component for ContextProvider<T> {
|
||||
|
||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
||||
Self {
|
||||
children: props.children,
|
||||
context: Rc::new(props.context),
|
||||
children: ctx.children,
|
||||
context: Rc::new(ctx.context),
|
||||
consumers: RefCell::new(Vec::new()),
|
||||
}
|
||||
}
|
||||
@@ -123,14 +123,14 @@ impl<T: Clone + PartialEq + 'static> Component for ContextProvider<T> {
|
||||
}
|
||||
|
||||
fn change(&mut self, props: Self::Properties) -> bool {
|
||||
let should_render = if self.children == props.children {
|
||||
let should_render = if self.children == ctx.children {
|
||||
false
|
||||
} else {
|
||||
self.children = props.children;
|
||||
self.children = ctx.children;
|
||||
true
|
||||
};
|
||||
|
||||
let new_context = Rc::new(props.context);
|
||||
let new_context = Rc::new(ctx.context);
|
||||
if self.context != new_context {
|
||||
self.context = new_context;
|
||||
self.notify_consumers();
|
||||
@@ -357,10 +357,10 @@ mod tests {
|
||||
log::info!("Render counter {:?}", counter);
|
||||
return html! {
|
||||
<>
|
||||
<div id=props.id.clone()>
|
||||
<div id=ctx.id.clone()>
|
||||
{ format!("total: {}", counter.borrow()) }
|
||||
</div>
|
||||
{ props.children.clone() }
|
||||
{ ctx.children.clone() }
|
||||
</>
|
||||
};
|
||||
}
|
||||
@@ -384,14 +384,14 @@ mod tests {
|
||||
let ctx = use_context::<Rc<MyContext>>().expect("context not passed down");
|
||||
log::info!("============");
|
||||
log::info!("ctx is {:#?}", ctx);
|
||||
log::info!("magic is {:#?}", props.magic);
|
||||
log::info!("magic is {:#?}", ctx.magic);
|
||||
log::info!("outlet counter is {:#?}", ctx);
|
||||
log::info!("============");
|
||||
|
||||
return html! {
|
||||
<>
|
||||
<div>{ format!("magic: {}\n", props.magic) }</div>
|
||||
<div id=props.id.clone()>
|
||||
<div>{ format!("magic: {}\n", ctx.magic) }</div>
|
||||
<div id=ctx.id.clone()>
|
||||
{ format!("current: {}, total: {}", ctx.0, counter.borrow()) }
|
||||
</div>
|
||||
</>
|
||||
|
||||
@@ -277,8 +277,8 @@ mod tests {
|
||||
type TProps = FunctionProps;
|
||||
|
||||
fn run(props: &Self::TProps) -> Html {
|
||||
let effect_called = props.effect_called.clone();
|
||||
let destroy_called = props.destroy_called.clone();
|
||||
let effect_called = ctx.effect_called.clone();
|
||||
let destroy_called = ctx.destroy_called.clone();
|
||||
use_effect_with_deps(
|
||||
move |_| {
|
||||
effect_called();
|
||||
@@ -297,7 +297,7 @@ mod tests {
|
||||
if *show {
|
||||
let effect_called: Rc<dyn Fn()> = Rc::new(move || set_show(false));
|
||||
return html! {
|
||||
<UseEffectComponent destroy_called=props.destroy_called.clone() effect_called=effect_called />
|
||||
<UseEffectComponent destroy_called=ctx.destroy_called.clone() effect_called=effect_called />
|
||||
};
|
||||
} else {
|
||||
return html! {
|
||||
|
||||
@@ -48,7 +48,7 @@ use std::{cell::RefCell, rc::Rc};
|
||||
pub fn use_ref<T: 'static>(initial_value: impl FnOnce() -> T + 'static) -> Rc<RefCell<T>> {
|
||||
use_hook(
|
||||
|| Rc::new(RefCell::new(initial_value())),
|
||||
|state, _| state.clone(),
|
||||
|state| state.clone(),
|
||||
|_| {},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ uses the same memoization on top of the use_context API.
|
||||
|
||||
Here's a fully-functional todo app using the use_map API:
|
||||
```rust
|
||||
static TodoList: FC<()> = |ctx, props| {
|
||||
static TodoList: FC<()> = |ctx| {
|
||||
let todos = use_map(ctx, || HashMap::new());
|
||||
let input = use_ref(|| None);
|
||||
|
||||
|
||||
Reference in new issue
Block a user